テレパシー機能の実演として、ぴっきー、のっきーに地球温暖化問題をかたり合わせてみた。
通常の、相手の言葉を聞き、認識して指定された自分の言葉を語りALDialogの機能では、相手が終わった途端(あるいは途中)から、話し出すことはできずにモタモタする。テレパシー機能を使うと、リズムに関しては人間の会話に近づくことができる。
ただ、言葉がロボット訛りがあるのと、台本の若干の誤り、ロボットの警報音、15分近い長さ、など、まだ、完成ではありませんが、テレパシー機能とは何かを感じ取ってもらえるのではないかと思います。
課題はまだまだあります。
カテゴリー: NAO技術
テレパシーモジュール:もう一つ問題そして解決
先に困難を書いたが、テレパシーモジュールを機能させる上で、決定的な問題は、ローカルモジュール内で子プロセスからALMemoryのイベントを呼び出せないことだ。数日無駄にした。最終的に、forkでサーバー機能を持たせることを諦めた。そして、結果的にそれでうまくいった。今日、二台のロボットに、人と同じような、素早いレスポンスの対話をさせることができた。2、3日中に、youtubeにアップできると思う。
テレパシーとロボットクラス
テレパシモジュールを組んでいたら、ロボットクラスの必要性を感じるようになった。複数のロボットがテレパシーでやりあう上で、相手(複数)ロボットの情報を確保しておくクラスがあると便利なのだ。最初は、ネットワークソケット番号とIPアドレスが最低組まれていればいいという程度だったが、考えると、名前、さらには、相対位置なんかもつかんでおいたり、対話の段階(これは予定済み)、動作状況を相互に持っていると便利だ。
だから、複数のロボットが常に相互にやり取りしている状態を想定する。ロボットは1つのローカルネットにつなぐことが原則だが、ブロードキャスト機能を使って、どんなロボットがそこにつながっているかを自力で把握することはできるだろう。初期における位置と方向は、人間が与えなければならないと思う。
ただ、アルデバランロボットは、動作後の位置と方向について、予測と結果を出すようになっている。それもかなりの細かい単位で位置情報を出してくる。不正確だとぶつかるかもしれないが、そこは衝突防止機能や基礎検知機能が付いているので調整し合うこともできる。
いずれにしても、テレパシーとロボットクラスをつなげたモジュールを作成することにしよう。
テレパシーモジュールの機能
テレパシー機能は、ALmemoryのイベント機能と、ネットワークを結びつけるのが最も単純で、プリミティブな機能として実現することができる。
図で説明しよう。左のロボットから右のロボットに伝える場合である。
いま、作成予定のモジュールをWSTelepathyとしよう。受け持つ機能部分は、四角の枠で囲まれている。 続きを読む テレパシーモジュールの機能
ロボット同士のテレパシー
人と人、人とロボットの間のテレパシー機能は、脳波などを使えば実現できるのかもしれない。実際、実現できるだろう。私も経済実験で脳波計を使ったことがあり、研究室には数十台の1極脳波計が役目を終えて眠っている。実験では、人々が他者を出し抜こうとしている時と、協調しているときの脳波のフーリエ解析をやって、α波やβ波などの違いを検出していた。1極ではとても心もとなく、使えない。もっと高品質で手軽な脳波計があれば、すでにやられているが、ロボットと人とのテレパシー会話が実現するだろう。これはやってみたいが、ハードウェアに金がかかりすぎる。 続きを読む ロボット同士のテレパシー
スマホにロボットの目の映像
携帯端末、タブレット/スマホに、ロボットがとらえている画像を見れるようにしたいと思っている。ドキュメントを見る限りできそうなのだが、最後のデータの変換のところがいまいちわかりにくい。
javaによるibotコントローラー jiBot
java用のqimessaging.jarを使って、対話管理(スクリプトの開始や表示)、動作制御(5cm〜90cmの移動、10度〜180度の回転)、状態把握(バッテリ、ディスク、メモリ、休息、起床、停止、再起動など)、ibotのインストール(モジュールのロボットへの組込み)などをこなす、jiBotのチェックが終わった。
※ このjiBotは、Pepperにたいしても使えるはずである。使用しているすべてのAPIがNAOとPepperとの共用のものだから。
予定通り稼働した。先にビデオで示した、口頭による動作プログラム(長い距離:0.5m〜10m程度まで移動制御できる)とあわせれば、ほぼ、指定場所に、リモートでロボットをセットでき、対話の制御、また、ibotクラウドにつながらなくても、ibotモジュールの制御ができるようになった。
※ クリックすると原寸表示
(ロボットを含むローカルネットへの接続は必須:macとlinuxでは問題なく動く。Windowsについては、32ビットバージョンで稼働する。)
NAO顔認識システムの精度と可能性
NAOの顔認識システムは、とても優れていることがわかった。なぜこのようなことを書くかと言うと、Choregrapheで顔認識を使うと、「なんだこれは?」という結果を出す。例えば、数人の顔と名前をface learnで覚えさせて、その顔を覚えているか、問いかけると答えるようなシステムを作っておく。
そして、面と向かって顔を出して、認識させると、別人の答えを堂々と出してくる。どうなっているの?という感じ。face recognitionのphthonスクリプトをいじって、いろいろ調整してみせたが、うまく正確な答えを出さない。匙を投げた状態だ。
しかし、今回、iBotのモジュールの中で、FaceDetectionのAPIをいろいろいじっていると、相当に精密にチェックして、ほぼ正しい答えを出すことがわかってきた。マニュアルには、OKIのシステムを使っていると書いてあるので、日本製なのかもしれない。
NAOは、顔認識が命じられると、秒単位で、認識している顔のデータをはじき出してくる。一つのデータは、次のようなものである。[[1411453501, 326253], [[[0,
0.0465021, -0.0450004, 0.338801, 0.35308], [1, 0.909, "わしだ",
[0.112934, -0.117693, 0.0830395, -0.107309, 0.142828, -0.124617, 0, 0,
0, 0, 0, 0, 0, 0], [-0.0332158, -0.103847, -0.00332159, -0.096924,
-0.06311, -0.100386, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0,
0, 0, 0, 0], [0.0514845, -0.00346157, 0.0830395, -0.00692313, 0.0199295,
0], [0.112934, 0.0380773, -0.00664318, 0.0519235, 0.0531453, 0.0415388,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]], []], [0.00990079, -0.000137116,
0.212517, 0, -0.609572, -0.0138481], [-0.0178356, -0.0142919, 0.54325,
0.00973533, -0.684393, -0.0291758], 0]
これがわずかな時間に、100個、200個と作り出されてくる。データは、[ ]とカンマで、構造化されているが、使用は、ドキュメントに書かれている。
xmlでもなく、jsonでもなく、c++では取り出しにくいのだが、
1, 0.909, "わしだ",
の部分が重要である。これは、ID 1のユーザー(ロボットにか顔を向けている第1番目の人)は、90.9%の確からしさで、「わしだ」さんであると言うことだ。他の人の可能性も調べるが、そのスコアは、0.5よりも遥かに小さい数になる。
だから、スコアの高いデータの名前を取り出せば、ほぼ間違わないようだ。
iBotで顔認識のシステムを使うと、85%以上の確からしさで人を認識すると、その時点で、イベントを発生させ、スクリプトの対応変数の中に、名前を書き込み、ロボットにしゃべらせることができる。あるいは、100回の顔認識が行われると、最大スコアの顔を、それとして出力するようにしている。
しかし、これほどしっかりしたシステムであるならば、さまざまな使い方が考えられる。名前は、ハードディスクに保存されているようなので、ロボットの電源を落としても忘れない。個人のデータを、顔の情報とともに覚えることができる可能性がある。
メモリエラーで倒れる
これは記録に値する問題だ。
ローカルモジュールで、配列の要素数以上にアクセスしたら、メモリのセグメント違反でアプリは止まる。これは一般のC++アプリでもそうであるし、ロボットのnaoqiも同じだ。ただし、ロボットの場合、一時的に気を失い、倒れる。しばらくすると正気に戻る。
ロボットが気絶するとは、すべてのギアがstiffness(堅牢さ)を失うことだ。DCM Cycle time error というものが発生する。よくわかっていない。そもそも、DCMについて、何度マニュアルを読んでも理解できない。
一体どこに問題があるかを調べるときには、ロボットを支えたまま問題探しをしなければならない。が、やはり、こういう場合は、naoqiのC++SDKにあるシミュレーターを使うべきだ。確かにシミュレーターは便利だ。ほとんどのことはシミュレーターでいいのだが、顔認識機能やいくつかの大切な機能が、ロボットにしかない。
モジュールからQiChatイベントを呼び出す
二日間これにかかり切りだった。
つまり、たとえば、ロボットが歩くなどのモーションを行った後に、QiChatスクリプトの中に組み込まれたイベントのルールを呼び出して、「歩き終わりました」などとしゃべらせたいわけである。
その逆は簡単であった。すなわち、QiChatスクリプトで、ロボットが「これから歩きます」などと言って、歩き始めることは、その言葉のあとに $start_walk=1などと、変数変化を組み込み、これをモジュール側でイベントとして受け取って、コールバック関数を起動して、AlMotionのmoveTo関数を起動してロボットを動かせば良いのである。
私は簡単に、動作が終わったあとモジュールの側でスクリプトに組み込み込んだ、イベント起動の変数の値を入力すればうまくいくものだと思っていた。たとえば、スクリプトの中に、
u:(e:finish_walk) 歩き終わりました
というイベントルールを組み込み、モジュールの側から、このfinish_walkという変数に適当に値を入れれば、変数変化のイベントが発生し、上記の「歩き終わりました」という言葉をロボットが発すると思っていた。
そこで、たとえば、memoryをALMemoryのインスタンスとして、C++APIのinsertData関数を使って、
memory->insertData("finish_walk",1);
このように値を入れればイベントが発生するはずだった。ところが、これがそのようには行かないのだ。
確かに、finish_walkに1という値は入力することができる。しかし、イベントルールは発火しない。
不思議なことに、
u:(あたいをいれる) $finish_walk=1
というルールをスクリプトに書いて、ロボットに、「あたいをいれる」と話しかけると、先のルールが発火する。どうなっているの??という感じだ。原因をさぐるためにいろいろやった。何をやったか忘れるくらいの究明作業だった。
結局、先のinsertData関数ではだめだったのだ。AlMemoryのraseEvent関数を使って、
memory->raiseEvent("finish_walk",1);
のようにしなければならないのだ。なぜそんな簡単なことがわからなかったのか。insertData以前にこれはすでに試みていて、失敗していた。しかし、今思えば、raseEvent関数の問題ではなく、他の欠陥だったのだ。詳しく詮索するのはやめよう。
教訓は次のようにまとめる。
「QiChatの中では、変数に値を入力すると、同時にそれはイベントを発火させる。モジュール側からは、raseEventを使って、入力とイベントを同時発生させる。insertDataは、単に値の入力作業しかしない」
何はともあれ解決してよかった。
モジュールとQiChatスクリプトのそれぞれの出口と入り口がつながって、iBotがChoregrapheの対話機能と同等の機能を持たせることが現実的なものとなった。