javaコントローラーの作成

先日大学のネットワークが不調になって、iBotのサイトにつながらなくなって、はたと気づいた。ネットワークが不調のときにロボットが使えないというのはあまりに理不尽。iBotのクラウドシステムは、目の前にあるロボットのコントロールがインターネット上のiBotのサイトに依存してしまう。
そこで、トピックファイルの編集ダウンロード、設定ファイルの管理等、それら以外の、直接的なロボット管理は、インターネットがだめでも、ロボットとパソコンがローカルにつながっていればできるようにすべきだ。
java用のqimessaging.jarというjavaSDKがAldebaranから提供されている。最初は、android端末で使おうかと思ったが、やはり慣れていないので、javaアプリとして作ることにした。私はプログラマーではない。androidアプリはプログラマーに依頼することにして、私が必要とする機能を実現するのは、パソコンの使い慣れたjavaアプリで良いと判断した。qimessaging.jarを使うと、ローカルのロボット管理は、javascriptとほぼ同じ簡便さで実現してしまう。

iBotの一区切りと課題

iBotシステムは、予定していた以上の内容を伴って出来上がった。8月中に作るつもりだったが、1ヶ月余計にかかった。最後に組み込んだ、言葉で一連のコマンドを与えてるというシステムもできている(一連のコマンドの編集、再生、削除もロボットとの対話で実現できる)。いずれにしても、対話を中心としたロボットシステムという形は予定通りで来たと思う。ただ、ロボットがなければ、アカウント登録して使っても、実際の役には立たないので、公開はもう少し考えてからにする。
課題として残っているものは次のようなもの。
(1)口頭コマンドで、トピックのアクティベイションをコントロールする。
(2)商用トピックの暗号化と、サンプルの作成。
(3)moveToコマンド(naoqi API ALMotionのメソッド)によるロボットの動きの厳密な制御が確認できていない。(※ 現在、英語版のForumページに問い合わせ中)
(4)iBotサイトにつなげないときの、ロボットコントロール。これは、引き続き作業する。
(※ 2014年10月6日段階で、第2項目以外は全て作業を予定通り終了している)

会話アニメーションを組み込まれるようにした

iBotで、60種類の会話アニメーションを簡単に貼込めるようにした。お辞儀なんかも、自分でつくる必要があるかと思っていたが、きちんと作ってある。自分でコレグラフで作ろうとしたら、バランスが悪くて倒れそうになった。
全部試していないが、いろいろある。
あと、首を左右それぞれに傾ける動作が欲しいが、これくらいは自分で作ろうと思う。

言葉による一連の命令の逐次実行

ブラウザでロボット対話と動作を制御することはできるようになった。次にやるべきことだ。
NAOに、一連の命令をあたえて、それを実行させたいと思った。QiChatのトピックファイルの中にそれを書き込んで、やらせることはもちろんできる。が、その場で臨機応変にさせたい。
「ここから、3メートル歩いて、右に90度回転し、「こんにちわ」とあいさつをしなさい。そこにいる人の顔を覚えなさい。次に左に向いて、1メートル歩いて座りなさい。「たちなさい」と言われたら、たって、会話を始めなさい。・・・・等々」
と、その場で「人の言葉で」一連の命令を与えるとその通り実行を始めるようにしたいのだ。QiChatでは、命令の受け取りの部分だけを書いて、その流れの記憶と実行は、iBotでする。モジュールの中に新たにC++のクラスを加えよう。
「こういわれたらこう答えなさい」と言った感じで、対話そのものもその場で教えるようにすることもできるはずだ。QiChatスクリプトをその場で作るようなものだ。
対話を軸にしたロボットの管理、というiBotの精神にぴったりである。
かなり役に立つはずである。

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の対話機能と同等の機能を持たせることが現実的なものとなった。

qimessaging.js 使い方の注意点

iBotは、ブラウザから、ロボットのモジュールにアクセスし対話や動作をコントロールする。その際最も重要な役割を果たすのが、javascriptで書かれたqimessaging.jsである。Aldebaranから提供されていて、ロボット本体が持っているウェッブサーバーのドキュメントフォルダに置かれている。
javascriptはクライアント側でブラウザを操作するものなので、このロボットにあるqimessaging.jsをユーザー側のブラウザに取込まなければならない。その際、通常のjavascriptと同様に、

<script src="htttp://192.168.11.3/libs/qimessaging/1.0/qimessaging.js"></script>

のように、ヘッダー部分に置くことになる。IPアドレスは、ロボットのものでなければならない。
第1の注意点は、このqimessaging.jsをjqueryの$.getScriptコマンドをつかって、実行途中にダイナミックに取込むと、機能しないということだ。理由はあるのだろうがわからなかった。IPアドレスを取得したあと、phpでヘッダー部分に書き込むようにして、ページをリロードするという作業が必要だった。
このjsを取込むと、
var session = new QiSession(robotip);
というかたちで、Qisessionのインスタンスが作成可能になる。robotipはロボットのIPアドレスである。
第2の注意点は、このQisessionは、接続中に2度作成してはならないということである。2度作成すると、qimessaging.jsがエラーを引き起こす。当然のようであり単純なことなのだが、javaスクリプトファイルをいくつも作っているうちに問題を引き起こしがちである。
一旦、上記のsessionを作成すると、serviceメソッドを利用して、ロボットのnaoqiのさまざまなモジュールを利用できるようになる。基本的に、javascript特有の非同期的組み立てが幾重も必要になる。

XercesからTinyxml2へ

iBotシステムの、個々のロボットの設定ファイルは、xmlフォーマットで書かれていて、ロボット内のiBotモジュールから読み込まれ処理される。モジュールはC++で書いているので、C++でxmlファイルをparseしなければならない。
parserをxercesというライブラリを使うと書いたが、これで作成すると、ローカルモジュールだけじゃなく、このライブラリ自身もロボットに送り込まなければならず、これが数十メガバイトもあり重たい。しかも、ロボットは32ビットcpuという制約もある。
そこで、xercesを改め、もっと軽いそれ自体が、簡単な一つのクラスと一つの実行ファイルでできているtinyxml2に変えた。実に軽く簡単にparseできるようになった。そかし、このために、1日使った。