基本的な戦略はこうだ。
まず、ロボットが見ている画像320X240pxから、人を切り出す。人があるかどうかをチェックするためには、Histogram of Oriented Gradients (HOG法)とSupport Vector Machine (SVM)でやる。認識した人の姿から、HOGに似た手法で、特性値を取り出し、ロボットの関節(20数個ある)の角度ベクトルへの写像関数を推計する。二台のロボットのに方向から推計される姿勢のPointの高いものをロボットが認識した人の姿勢にする。ロボットの関節をその姿勢に向けて動かす。ただし、ロボットが倒れない工夫が難しい気がする。
HOGは、C++のプログラム化した。(SVMができていないので、アルゴリズムが正しいかどうかの検証はしていない、1個の学習画像を読み取り特性ベクトルを計算するまでしか作っていない。学習用の画像読み取りにOpenCVを使っているが、実際の認識の場合は、ロボットのビデオデバイスの画像データを直接読み取る。プログラムの中では、コメントアウトしている。g++のある環境で、makeコマンドをinvokeすればコンパイルできるはずです。)
<一旦公開したが、svmにかけたところデータ作成上に誤りがあるようで、公開を停止した。>
一方、SVMはアイデアはわかるが、プログラム化できていない。20数年前に、ニューラルネットワークやパーセプトロンの経済学への応用に没頭した時期があったが、SVMは、それに似ている。不思議な気がする。
SVMについては、時間をかけて、基本的な理論のところから理解し、プログラム化したいものだ。
月別: 2015年1月
人の動作を読み取る
こんなことをさせたいということのかなりのものを実現してきたが、次に、ロボットにやらせたいことは、人の動作を読み取って、自分の動作のためのメタ言語に翻訳することだ。
というのも、この間、ロボットに喋らせることを軸に、人の心とコミュニケーションをとらせるための基礎的な仕組みを作ってきたが、やはり、動作がありきたりでは、届けきれないことに気づいた。
動作を工夫することは、通常のプログラミングでもできる。しかし、次々に多様な動作をプログラミングすることは事実上できない。一番良いことは、人の動作を見て、その動作を自分の(ロボット自身の)体で実現してみることだ。それはすなわち、その動作をするメタ命令が自分の中で創作されていることになる。
それは、すでにロボット工学の分野では実現していることなのだが、私のロボットでもそれをやってみたい。
ロボットの映像をプログラマティカルに取り出すことはすでにできている。できれば、2台のロボットからみた画像を合成して、対象としている人の動きを立体的に再現させてみたいものだ。
ロボット漫才1『ロボットの時代』
テレパシー機能を使って、ロボットに漫才をやらせてみた。「ロミオとジュリエット」のように、動きを挟んではいない。他の記事で書いたが、一つのトピックファイルで、二つのロボット交互的な機能を果たす、ひとつの、最初のサンプルともなっている。
この台本のトピックファイルをご覧になりたい方は、以下にあります。
ロボット漫才「ロボットの時代」台本
ただし、このトピックファイルは、Choregrapheなどでは、そのまま使用できません。最新のiBotシステムのライブラリがロボットに組み込まれている必要があります。
iBotのロボット動作モード
iBotシステムには、ロボットの動きを制御するための三つのモードがある。(WSと頭につくモジュールは、当方が作成してロボットに組み込まれるモジュール)
(1)androidアプリのピノキオの動作機能で、直接ロボットを動かす。android端末のコントローラーで動きを制御する。直接といっても、ALMotionのmoveToなどでうごかすのではなく、ibotのメインモジュールWSIbotで一旦コマンドをうけとって、ALMotionを起動する仕組みになっている。このモードには、動作記録、記録された動作の実行も可能になっている。
(2)第二には、WSIbotモジュールの中のWSCommandクラスの機能を使う。これは基本的に、ロボットに口頭で動作コマンド(進んだり回転したりナビゲートする)を与えて、記録したり、実行したりできる。コマンドは最初は与えて記憶するだけで、実行命令が口頭で与えられるまで実行しない。一連のコマンド群を保存したり際ロードしたりもできる。
(3)第三の方法は、Dialogのトピックファイルに、実行コマンドを埋め込む。ロミオとジュリエットで対話しながら動作をさせているが、これは、トピックファイルに詳細な動作を埋め込んでいるからだ。この処理と実行にも、WSIbotを使っている。
これらは現状では相互に独立しているが、この第二の機能と第三の機能を繋げたいと思っていた。そこで、Dialogのなかから、コマンドモードに保存した一連の動作機能を起動させることができるようにしようと考えている。コマンドモードの保存機能も、現状一つのコマンド群(一つのコマンド群には、多数の個別コマンドが保存できる)しか保存できていないが、これを10とか20くらいのコマンド群でも保存できるようにして、それをDialogのトピックファイルから指定して、実行できるようにしたい。
そうすると、ロボットは、たとえば、舞台に入場して、何かを演じて、退場するところまでをすべて、トピックファイルに記述することができ、また、最初と最後の動作をその場に合わせて、コマンドに組み替えることが容易になる。まさに、パソコンも、スマホも不要になって、全ての機能を口頭、コミュニケーションで与えることが可能になるのだ。
1つのスクリプトで、2台のロボットが対話/動作
これまで、2台のロボットにシナリオを交互に対話/動作させる時、それぞれ別のスクリプト(TOPICファイル)を用意し、テレパシーシグナルでやり取りしあった。もともとの台本は一つのファイルに作成し、それをロボットごとに切り分けるのが、とても面倒だった。
これを一つのスクリプトで済ませることができるようになった。つまり、同じスクリプトをそれぞれのロボットにインストールしても、交互対話が実現できるのである。
工夫は難しくない。開始の構文の中に、そのロボット名と一致しなければ、有効ではなくなる条件式を入れただけである。開始ロボットが確定し、そのルールが起動すると、あとは、テレパシーシグナルがそこから交互に呼び出されるので、意図した対話/動作が実現できる。
こうすると、修正も楽である。一つの台本をいじればよいので。そうでなければ、二つの台本を、常に調整し合わなければならなかったから。
演劇などで、一つの台本をみんなで使う、人間のやり方に近づいた。
複数ロボットと複数端末
ピノキオはスマホタブレットの端末で、一台で複数のロボットを管理するためのツールだった。複数のロボット同士はテレパシーでコミュニケーションする。これに対して、あらたに、一台のロボットが多数の端末とコミュニケーションを取る状況が想定されることが分かった。
(1)ロボット自身が授業を進行させる状況下で、児童・生徒が持っているタブレット端末から、ロボットの問いかけに対する回答を集める。それらの回答をもとになんらかのリアクションをとるような場合。
(2)ロボットの次の言動を複数の人々の意見を元に決定していく状況。(たとえば、その場で創造的に作成されるロボット演劇)
そのために、ロボット側が全ての存在端末を認識することが必要である。端末からの情報をすべて集めて、その中から特定のメッセージ、リクエストを選び出し、それ言動として出力する機能が必要となる。
ロボット演劇「ロミオとジュリエット」
ibotのテレパシー機能を使って、シグナルをやりとりして、会話のタイミングをとり、また、動作を行う。これの実証実験として、シェークスピアのロミオとジュリエットの有名な場面、第二幕、第一場、「キャピューレット家の庭園」の場面を演じさせてみた。
動きは、まだ、十分な演出を行っていないので、ある意味、適当だが、もっと凝らした演出は可能である。最後に、奥から乳母が呼ぶ声を、ピッチを上げた声でしゃべらしたら、裏声になっている、ちょっと笑う。最後の最後で、「充電不足」のメッセージが出てしまった。普通に充電していれば問題なかったのだが、つい怠った。
こうしたロボット演劇は、すでに、「夕鶴」でもやっていたのだが、そちらは著作権問題がややこしそうだったので、公開はやめた。こちらは、青空文庫の坪内逍遙の訳を、私が現代語に改めたもの。著作権問題はないので、公開している。
もっともっと、ロボットによる対話という技術、コミュニケーションという技術を高めて、ロボットにできることの限界を探っていきたい。それをとおして、「人間のコミュニケーション」への理解を深めたいと思う。
ロボットを倒さない
テレパシーモジュール(ロボットに組み込むローカルライブラリ)に関わって、対話をめぐるシグナルのやりとりは、すでにビデオにアップしているように、問題無く機能する。ただ、対話と動作を組み込んだテレパシーのやりとりに問題が発生した。動作を開始しようとすると突然倒れるのだ。この問題を回避するために、十日以上時間を使ったことになる。
テレパシーモジュールがらみの問題だと思った。この間の経験から、メモリエラーが発生すると、すぐに倒れる。例えば、配列の枠以上のところにアクセスすると、セグメントエラーで、ロボットが麻痺して倒れることはよくあった。
そのために、モジュールの怪しい箇所を徹底的に調べた。結果的に、forkコマンドからpthreadによるスレッド処理にかえたり、自動で体を動かす機能をコントロールしたり、したが結局それらは問題ではなかった。そもそも、テレパシーモジュールの問題ではなかった。
要するに、歩行開始前の状態の問題だった。歩行開始前は、StandInitのポーズにしなければならない。ibotの基本モジュールでは、初期状態をALPostureモジュールで把握して、それがStandInitでなければ、ポーズをStandInitにセットするとしていたのだが、じつは、実際の姿勢がStandInitではなくても、そうであるかのように値を返すことが分かった。
そのあたりの問題があることに気づいたのは、実は、Choregrapheでも、初期状態をちょっと変にしておくと、Poseをとったときに、バーチャルロボットが倒れることがわかったことが大きい。つまり、Choregrapheも状況によって、機能できないと倒れるのだ。ここがヒントになって、上記のチェックを行った結果、どのような状況でも、moveToコマンド前に、StandInit状態にすることで、倒れなくなった。
さらに、moveToの終了後、まず、Standのポーズをとらせてから、体を自動的に動かす機能を復活させるにしたことも大切な対応だった。というのも、ロボットは、こうしたAutolife機能は、Standの状態で行うので、早めにStandを確保しないと、自動の動きを突然やらせると、体が揺れて、そのために倒れることがあるのだ。これも回避することができるようになった。
ロボットにとって、倒れることは深刻な問題だ。Pepperは、プログラマティカルに倒れることはないだろう。しかし、NAOは二足歩行である。倒れやすい。というか、倒れることを前提に、いろいろな対応が取られている。PepperにはPushrecovery機能があるのに、NAOには、なぜかその機能が組み込まれていない。NAOの足の裏には、片足、4個のセンサーが付いていて、圧力をチェックしているので、それを使って、Pushrecovery機能を持たせることができそうだが、なぜか、そのイベントと値を取得できない。
NAOにとって倒れないプログラム作りは決定的に重要なのだ。