ターゲット

  • ロボットの会話を作りたい人
  • チャットボットを自作したい人
  • 自分好みの会話をロボットにさせたい人
  • 会話がどのように生成されるか興味がある人など…

はじめに

ロボットの会話を作成しているりょぼっとです。

ロボット会話職人」の第一号(?)として活動しています。

今回はロボットの会話を作成する際に使っているIBM Bluemix上のWatsonのConversationについて解説します。

ロボットだけでなく多くの利用用途があるのでぜひ使ってみてほしいです。(30日間無料)

なお、IBM Bluemix上のConversationは日本語対応が正式には発表されていません。今後、何らかの理由で利用できなくなる可能性があるのでご注意ください。

Conversationとは

Conversationを使うと以下のようにブラウザ上で会話のシナリオを作成することができます。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-16-31-51

conversationの3大要素

基本的にはこの3つさえ押さえておけば会話を開発することができます。

  • Intents
    • 文章のカテゴリ・意図を作成する。
  • Entities
    • 単語を登録する。
  • Dialog
    • 返答を記述する。

作ってみる

実際に会話を作成した方が理解は早いので、作成してみましょう。

何かテーマがある方が作りやすいので、テーマを「お正月のロボット」として開発していきます。

Intents

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-13-44-03

Intentsの作り方は2つあります。1つ目はCreate newでGUIベースに作る方法ですが、慣れてくると2つ目のImportを使います。Importではあらかじめ作成したcsvデータを元に、Conversationが自動的に振り分けてくれるので便利です。ということで今回はImportを使います。

今回は以下のようなcsvデータを用意しました。(文字コードはUTF-8)


あけましておめでとうございます,greeting
今年もよろしくお願いします,greeting
よいお年を,greeting
こんにちは,greeting
おはようございます,greeting
さようなら,greeting

このデータをImportすると以下のように画面が変わり、無事追加されたことがわかります。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-08-44

では、試しに会話をしてみましょう。画面右上にある %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-14-31 のボタンを押すと、一番下にコメントを入力できる欄ができます。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-14-43

そこに「あけましておめでとうございます」と書き込み、Enterを打つと、

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-15-09

正しくgreetingに分類されました。

Dialog

次に、このセリフに対しての返答を書き込みます。

Dialogの画面でCreateを押すと以下のような画面が出てきます。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-23-23

Enter a conditionには先ほど作成したIntentsのカテゴリ名を、Enter a responseには返答を書きます。今回は「#greeting」と「おめでとうございます」を設定しました。

では、先ほどと同じように会話をしてみましょう。「あけましておめでとうございます」と打ってみてください。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-31-03

このように、先ほど追加した返答が返されます。

では、「こんにちは」と打ってみてください。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-38-40

「こんにちは」の返答が「おめでとうございます」となっています。これでは会話が成立しませんよね。そこでEntitiesの登場です。

Entities

Entitiesの画面を開くとIntentsにはなかったUse system entitiesというものがあります。これは数字や日付等の認識を可能にできますが今回は使用しません。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-15-41-16

Intentsと同じように以下のcsvデータをImportします。


greeting,hello,こんにちは,やあ,やっほー
greeting,bye,さようなら,バイバイ,じゃあね,またね
greeting,morning,おはよう,おはようございます
newyear,hello,あけましておめでとうございます,あけおめ
newyear,meet,よろしく,よろしくお願いします
year,year,今年,年

Importしたらこのようにカテゴリ分けが行われます。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-16-00-37

それではまた前回と同じように会話をしてみましょう。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-16-04-15

このように、先ほど登録した言葉を認識しています。あとは一気にDialogを作成します。

最終的にはこのようなフローになりました。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-16-31-51

会話を試してみた結果がこちらです。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-27-17-06-45

すべての発話に対して正しい返答ができています。

おわりに

このように簡単にロボットの会話を作成することができます!

今回は導入部分のみの解説にはなりましたが、より高度な扱いをすることが可能です。

次回はConversationとロボットを繋げる方法や、より高度な使い方などについて解説していきたいと思います。

 


関西弁と変なモーション。関西弁は AITalk さんの技術を使わせていただいています。
ロボットってやっぱりキャラクターなんだなと思います。イントネーションや声が変わるだけで印象がだいぶ変わりますね!

変なモーションはここからダウンロードできます。

https://github.com/Smartrobotics/nao_fushigimotion

そしてこのモーションに潜む秘密は、、、詳しくは来年を期待ください!


こんにちは。ハードエンジニアのGOE3です。
今回は、最近趣味で作ったロボットハンドについて紹介させて頂きたいと思います。

昨今、3Dプリントデータを公開するページを見ていると、多種多様なロボットハンドが公開されています。
しかし、駆動する多くのロボットハンドが「複数パーツを組み合わせる」「柔軟性のある樹脂材を使用する」といったアプローチで設計されております。

そこで、世にあるモノと同じ設計を行っても面白く無いなと思い、以下の条件を目標に設計してみました。
一通り出来ましたので、STLデータを公開させて頂きたいと思います。興味のある方は出力をトライして頂けますと幸いです。

  •  設計目標
    • 一般的な樹脂材(ABS)で造形可能
    • 廉価な3Dプリンターでも出力可能な、150mm角以内
    • 指が曲がる構造
    • 手の組立が不要(1度で出力可能)
    • 組立が出来るだけ簡単である事(理想は小学生でも組立可
  • 設計・造形環境
    • 設計ソフト : Solidworks 2016
    • 造形機 : ZORTRAX M200
    • 材料 : Z-ABS (積層ピッチ 0.19 以下,サポート角度10-20°推奨)
  • 形状イメージ
    • 成人女性の手(上司から「彼女創ってるの?」と聞かれましたが、造形サイズ制限が理由です!多分…)
  • 完成物

  • 解説
    • 関節部について
      • 関節部分を若干塑性変形する形状にする事で、曲げに対応させています。製作過程は、モデルデータ配布先で見て頂ければと思います。
      • %e3%82%ad%e3%83%a3%e3%83%97%e3%83%81%e3%83%a3
      • 耐久性はあまり無いように思っているのですが、半日ほど連続稼働(各指毎に約3000回程駆動)しても、壊れませんでした。サーボの方は焼けそうでしたが…
    • 改善したい箇所
      • 物を掴む形状にする(親指位置の変更/可動域改善/サーボ変更及び固定用パーツの別出力)
    • 今後トライしてみたい事
      • 弾性素材でも出力してみたい
      • 弾性のある紐で指とサーボを接続したかったが、適切な弾性素材が見つからず、現状は親指以外はワイヤー駆動。全指対応したい(これが出来れば小学生でも組立可)
  • まとめ
    • ソフトロボティクスに代表されるように、構造・素材を活かした柔らかい(人と触れ合える)ロボットを作りたいなあと考えています。今回は、そのアプローチの一つとしてこういった設計をしてみました。来年は素材の面でも色々挑戦していきたいです。

会話を期待されながら残念ながらいまいち会話が噛み合わない Pepper、問題の一つは音声認識にあります。スマートフォンに話しかけたりするのとは違ってマイクと話者との距離があったり、小さい頭の中に CPU やらそれを冷却するファンやらが集積されている中に埋め込まれたマイクは、構造上ノイズを拾いやすかったりと、音声認識の精度を上げることに一定の技術的、環境的ハードルがありました。 また Pepper が標準でアプリデベロッパーに提供する音声認識はあらかじめ登録したキーワードに対して聞いた言葉をマッチングさせる、キーワードベースの音声認識であり、登録したキーワード以外のことを発話されると会話はとかく破綻してしまいがちでした。 Pepper の兄貴分にあたる NAO も状況は同じで、Pepper よりさらに小さな頭にいろんなものが集積されている分、問題はより深刻でした。

どうにか NAO にもっと会話をさせたい。試行錯誤をしてきた中でかなりいい感じになってきたものがありこの場で紹介させてください。

どうですか? 音声認識の機能自体は私たちが開発したわけではなく、クラウドの音声認識を使っているのですが、ここへの音声の送信をライブで行っているところに工夫があります。 レスポンスも申し分なく、ノイズ耐性もかなり良いです。

現在この技術をサービス化してより多くの人に使ってもらえるよう開発中です!

近年の機械学習の進化により音声認識の分野は急速に精度が上がってきているようです。ロボットとの会話を考えたとき次に待っているのは、聞いたことに対してロボットがどう答えるか。 この分野はまだまだ未成熟で、これからかなという感じです。 
まずは色々なボットにつなげてみたり、AIや会話エンジンといっているものにつなげてみたい。 私たちもこれらの技術を持っているベンダーさんを探していますが、自薦、他薦、オススメありましたら情報をいただければと思います!

かつて HTMLというコンテンツ配信技術が生まれ、Web製作という職業が生まれたように、音声認識、音声合成の技術が成熟し、会話エンジンの仕組みがある程度整理されると、ロボットに会話を覚えさせる「ロボット会話職人」のような職業が生まれてくるのかな、そんな妄想をしてしまう今日この頃です。


ここでは、ダンス中転んでも起き上がって続きからダンスを踊る NAO (頑張るダンス)アプリの作り方を説明します。

対象

この記事は、NAO 向けアプリ開発ツール「Choregraphe」を使ってダンスアプリを作ったことがある方を対象としています。 そのため NAO の開発環境、Choregraphe の基本的な操作方法などに関する説明はここでは行いません。

はじめに

2本足で立ち、全身を動かすことができる NAO はとてもダイナミックな動きをすることができるのが最大の特徴の一つですが、同時に転倒のリスクに常に気を使う必要があります。 ダイナミックなダンスを披露するときなど、バランスを崩して転ばないかといつもヒヤヒヤします。 一方見ていただいた方からは小さいのに一生懸命がんばって踊っている感じがけなげでいいといったような意見をよく聞きます。 ならば転んでも起き上がって続きから踊るぐらいまでがんばってもいいのでは。  そんな思いから作ってみたのです。

サンプル動画

実装、動かしてみた例です。どうです、頑張っている感出てませんか?

原理

原理は結構単純です。 Choregraphe のタイムラインで作ったアニメーション、アニメーションの時間経過にしたがって各関節の角度をどう変化させればいいのかを配列の形式で記述した、スクリプトコードに落とし込むことができるのですが、このスクリプトコードでアニメーションを再生することにします。 途中で転んだら安全機能が働きアニメーションの再生が自動で止まるのですが、これを検出してまず起き上がり、無事立ち上がることができたら、次にアニメーションの再生を開始してからどれぐらい時間が経過したかを調べ、各関節の角度を収めている配列を、過去の情報を切り捨てて再構築、これを再生すれば途中からダンスを再開できるというわけです。

サンプルアプリ

是非皆さんも試してみてください。サンプルアプリを次からダウンロードできます。なお、ビデオは FC東京のマスコットキャラクター ドロンパ君のダンスを踊っていますが、サンプルアプリは、NAO 標準のダンス、太極拳ダンスを踊ります。

https://github.com/Smartrobotics/nao_fallrecoverydance/

あなたのダンスアプリを「頑張る化」する方法

サンプルアプリを変更してあなたのオリジナルダンスを倒れても起き上がってダンスにしてみましょう。

必要なもの

「頑張る化」に必要なのは次の2つです
* Choregraphe のタイムラインボックスで作られたアニメーション
* タイムラインのアニメーション再生中に再生する音楽ファイル

手順

次に手順を説明します

1. タイムラインをスクリプトとしてエクスポート

「頑張る化」したいアニメーションのタイムラインを開きます。 次の図の手順でタイムラインをスクリプトに変換します

timeline1

2. サンプルアプリのダンススクリプト部を入れ替える

サンプルアプリを開きます。この中のスクリプトを先ほどエクスポートしたものに入れ替えます。 まずエクスポートしたコードですが、この中で必要な箇所は

	names = list()

で始まる行から

	try:
	   # uncomment the following line and modify the IP if you use this script outside Choregraphe.
	   # motion = ALProxy("ALMotion", IP, 9559)

の行の前の行までです。 この部分で時間経過にしたがって各関節の角度をどうコントロールすればいいのかを配列に詰めています。この配列を使って独自の手法でダンスの再生をしたいわけです。 上記コードブロックをクリップボードにコピーしておきます。次に「Ganbaru Dance」ボックス

ganbaru_dance_box1

の中の「Timeline」ボックスをダブルクリック
timelinebox

スクリプトエディタが開くのでコメント部 「# put animation code here」 から 「#animation code end」 の部分をクリップボードにコピーした内容で入れ替えます

	class MyClass(GeneratedClass):
	    def __init__(self):
	        GeneratedClass.__init__(self)

	    def onLoad(self):
	        self.bIsRunning = False
	        self.player = ALProxy('ALAudioPlayer')
	        self.playerStop = ALProxy('ALAudioPlayer', True) #Create another proxy as wait is blocking if audioout is remote
	        self.soundId = None

	    def onUnload(self):
	        if self.soundId != None:
	            self.playerStop.stop(self.soundId)
	        while( self.bIsRunning ):
	            time.sleep( 0.2 )

	    def onInput_onPrepare(self,p):
	        self.soundFile = p

	        # put animation code here

	        	:     この箇所を入れ替える    :

	        #animation code end

	        self.names = names
	        self.times = times
	        self.keys = keys

	        if p != None and len(p) > 0:
	            self.soundId = self.player.loadFile(p)

貼り付けたらインんデントの調整を忘れずに。貼り付けたコードを選択したままの状態で Tab キーを押すとまとめて字下げをすることができると思います。 直前の self.soundFile = p と同じところまで貼り付けたコードを字下げします。

3. ダンスと同時に再生する音楽ファイルをインポート

ダンスと同時に再生する音楽ファイルをプロジェクトにインポートします。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-12-14-1-04-09

4. 音楽ファイルを設定

再生する音楽ファイルを 「Ganbaru Dance」 ボックスのプロパティで設定します。

set_music_file1

5. 再生

変更は以上です。再生してテストしてみてください

簡単に解説

一番の肝は 「Ganbaru Dance」 ボックスの中の 「Timeline」 ボックス、onInput_onResume メソッドの中です。ここであらかじめ定義された配列をもとに再生開始から現在までの経過時間を調べ、配列を再構築、再生しています


                :                   :

	    def onInput_onStart(self):
	        self.bIsRunning = True
	        import time

	        self.startTime = time.time()
	        if self.soundId != None:
	            tid = self.player.post.play(self.soundId)

	        self.onInput_onResume()

	        if self.soundId != None:
	            self.player.wait(tid, 0)

	        self.bIsRunning = False
	        self.onStopped()

	    def onInput_onResume(self):
	        adj_rate = 0.001

	        initialDelayEstimate = len(self.times[0]) * adj_rate

	        import time
	        motion = ALProxy("ALMotion")

	        times = list()
	        keys = list()

	        curTime = time.time() - self.startTime
	        nextTime = curTime + 2.0

	        for i in range(len(self.times)):
	            times0 = list()
	            keys0 = list()
	            for j in range(len(self.times[i])):
	                if self.times[i][j] > nextTime:
	                    times.append(self.times[i][j:]) # This loop may take time. Re-calcualte the time later
	                    keys.append(self.keys[i][j:])
	                    break

	        curTime = time.time() - self.startTime # get current time and re-calculate the time with this


	        currentDelayEstimate = len(times[0]) * adj_rate
	        adjTime = curTime - (initialDelayEstimate - currentDelayEstimate)

	        l = len(times)
	        for i in range(l):
	            times[i] = [x- adjTime for x in times[i]]


	        if len(keys) > 0:
	            motion.angleInterpolationBezier(self.names, times, keys)

	        #self.onStopped()


	    def onInput_onStop(self):
	        self.onUnload() #it is recommended to reuse the clean-up as the box is stopped
	        self.onStopped() #activate the output of the box

ちなみに、変数 adj_rate ですが、これは再生時間の微調整をしています。動画を見ていただくとダンス後半でダンスを復帰した時、同時に踊っているもう一台より少しアニメーションが早いタイミングで再生されていることが分かるかと思います。 どうもアニメーションを再生するメソッド angleInterpolationBezier は配列データが多いと再生開始に時間がかかるようで、これが原因で再生が少しだけずれています。ダンス後半でリカバリーするとき、残りのモーションが少なくなってくるので配列のデータ数が少なくなります。 これを再生するとき、アニメーションが実際に開始されるまでの angleInterpolationBezier メソッド内部での処理時間が短くなるので、angleInterpolationBezier メソッド呼び出しまでのタイミングで同期を取ったとき、若干のズレが生じてしまうのです。 このズレを調整しているのが adj_rate です。動画を撮った時点では、この調整が行われていなかったので、若干のズレが入っています。 adj_rate の値は計算結果によるものというより実測によりものになります。ズレが最小限になる値はダンスごとに調整が必要かもしれません。

Ganbaru Dance ボックスの中の fall recovery ボックスが転倒した状態から起き上がる処理をしています。

fallrecoverybox

fall recovery ボックスの中はモータをオンにして、立ち上がっています。 Set Speaker Vol. ボックスは転倒時音量を少し下げています。この辺りは利用シーンなどに応じて作り変える必要があると思います。

fallrecoverybox_inside

これはあくまでサンプル、どういった作りになっているかいろいろ研究して自由に作り変えてみてください。 もっともっと頑張ってる NAO が見れること楽しみにしています!


ロボットに関心がある技術者向けのブログ「スマロボ技術部ブログ」を始めます。
このブログは株式会社スマートロボティクスの社員と、株式会社スマートロボティクスと志を同じくする同志たちによって発信されるロボット関連の情報発信ブログです。

このブログが少しでも多くの人のロボットに関する情報収集の助けになると幸いです!