シーケンスモジュールが出来た

シーケンスモジュールがロボットで問題なく動いた。意外と早く出来てしまった(笑)

シーケンススクリプトを実行する。シーケンスとは、多様なポーズを時間的につなげて、一つのモーションを作ることだ。(私の作った言葉。Choregraphe のタイムラインに似ているかな)

上の動画は、サリーちゃんに昔流行ったギャグ「だっちゅーの」をやってもらった。シーケンスファイルは、次のような感じのスクリプトになっている。これを指定場所に置いておく。私の場合は、ロボットのコンピュータのフォルダ、/home/nao/ibot/user/sequence だ。ここに同時に、Choregrapheで作った様々なポーズがファイル化してある、xapファイルも置いておく。

# ------------------------------------------------------------
#
# msweq だちゅーのポーズ(サリーちゃん用)
#
# #から始まる行、空白行はスキップ
# コマンド、スピード制御、ポーズ名、スピード(最速を1とした割合)
# 時間は全て、ミリ秒であらわす
# ------------------------------------------------------------

# ゆっくり立ち上がる(スピード制御、数字は1.0が最大)
execpose,speed,Stand,0.2
# 1秒立った姿勢を維持する
sleep,1000
# ゆっくり「だっちゅー」のポーズをとる
execpose,speed,Dachuno,0.2
# そのポーズを3秒維持する
sleep,3000
# ポーズを時間制御に変更する
# 4秒かけてスタンドゼロのポーズを取る
#execpose,time,StandZero,4000
# 4秒かけてStandinitのポーズを取る
execpose,time,StandInit,4000
sleep,1000
# 3秒かけて座るポーズにはいる
execpose,time,Sitdown,3000
# 座ると、自動的にstiffnessが0.0にセットされる:モータの加熱回避で必要
#sleep,1000

このスクリプトは、ロボットの内部モジュールwsmotionライブラリによって読み取られ実行される。呼び出すためには、まず、qichatのスクリプトの良きところで、$motion_getposes_1="sally_pose.xap"という、メモリイベントを発生させる。=の右側に、Choregrapheのポーズリストファイルを指定する。全てのポーズが名前と、関節角度付きで入っている。これを実行したのち、$motion_sequence_1="dachuno.mseq" というシーケンスファイル(=の右側)の実行のためのメモリイベントを発生させる。どちらも、変数は、これで確定していて、変更は不可である。

テストに次のようなトピックファイルを用意した。

topic: ~wsmotion-181224 ()
language: jpj

# モーションテスト

u:({サリーちゃん} やってください) はいわかりました $motion_getposes_1="sally_pose.xap" データ読み込みました $motion_sequence_1="dachuno.mseq" \pau=7000\ だっちゅーの 

「だっちゅーの」の前の\pau=7000\(7秒停止)が気になる。呼び出しているNAOQIのAPIには、ブロッキングコールと書いているので、実行終えるまでは次に進まないと思っていたら、どんどん次を読んで実行してしまうので、だっちゅーのという言葉とギャグがかみ合わなくなってしまっているので、つけたが、いやに長く必要になっている。

Choregrapheで作成したポーズをC++モジュールで実行する

ポーズや動作を作成するのは、Choregrapheが優れている。動作は、ポーズの時間的なつながりであるとも考えるので(本当は違うが)、同じものとして考えよう。

Choregrapheでポーズを作ると、xapファイルとして出力できる。これについては、別の投稿に書いた。このファイルからポーズデータを読み込んで、NAOQIのAPIのALMotionのangleInterpolationWithSpeedメソッドで実行させる。

xapファイルは、xmlファイルなので、これを読み取らなければならない。これについては、wsibotでも使用している、tinyxml2というのを使う。これは、ヘッダーファイルとcppファイルなので、とても軽いし使いやすい。実行ライブラリ化していると組み込みがまた面倒になるから、数年前には、ほぼ、これ以外の選択肢はないように思えた。(今は、別にいいのがあるかもしれないが調べる気はない)

読み込んで、そのポーズを実行させるところまではほぼできた。その際、xapファイルに書かれている角度について少し困った。StandやStandInit、StandZeroのサーボ角度は度で書かれているのだが、新たに作った、あるいは登録した角度はラディアンで書かれているようなのだ。同じ、positionエレメント内に入っているのに、この違いは面倒臭い。両者を区別することはできないかと思ったら、どうも、version要素が2の時はラディアンと考えて問題が起きなさそうなのである。正しい回答かどうかはわからないが、まあ、これで当面矛盾は起きそうにないので、position要素の中でversionの値が2になっていたら、そのまま、angleInterpolationWithSpeedに食わせて、そうでなければ度からラディアンに変更するというようにしている。

ここまで終わったので、次は、ポーズを連続して動作させることと、それを変数のイベント化して、会話の中で呼び出せるようにしたい。

関節と動作関係のC++モジュール

ロボットの動きのボケのために、関節操作と動作関係のモジュールをメインモジュールから独立させようとしている。

そのために、久しぶりに、モジュールの新規作成を試みた。基本、NAOのV25までは32ビットで動いているので、32ビットのlinuxminiで動かすことにしている。これまでのシステムでは、既存のモジュールのqibuildを用いた再コンパイルは難なくできているのだが、新たにインストールしたlinuxでうまく行かない。

なんどもnaoqiとqibuildはインストールしているので、難なく行くはずだがと思っていたら、g++が入っていなかった(笑)

動作関係の新しいモジュール

今までは、基本言葉の部分で芸ロボットの可能性を探ってきた。動作は、言葉とリンクさせたり、言葉に動機付けられて立つ座る、歩く、回転するなどの基本操作しか制御するようにしていただけだった。

この動作でも、芸ロボットらしくボケたりできるように、動作関係のモジュールを作り直したいと思う。

今までは、wsibotというモジュールの中にmotion関係のクラスを作って動かしていたが、独立したwsmotionというモジュールを作成しようと思う。

複雑な動作はポーズの時間的な推移として表現できることがわかっている。このポーズは、基本choregrapheで作成する。Choregrapheのポーズは .xap というXMLファイルに保存される。.xapファイルの形は以下のようなものである。

NAOに五郎丸ポーズを取らせた時のものである。

<?xml version="1.0" encoding="UTF-8" ?>
<ChoregraphePositionLibrary xmlns="http://www.aldebaran-robotics.com/schema/choregraphe/position.xsd">
    <folder>
        <folded>yes</folded>
        <title>Basics</title>
        <position>
            <Motors>
                <Motor>
                    <name>HeadPitch</name>
                    <value>0</value>
                </Motor>
                <Motor>
                    <name>HeadYaw</name>
                    <value>0</value>
                </Motor>
...........全てのモーターのリスト..........
.....................
.....................
            </Motors>
            <name>StandZero</name>
            <description>All motors to 0</description>
            <bitmap>media/images/positions/StandZero.png</bitmap>
        </position>
        <position>
            <Motors>
                <Motor>
                    <name>HeadPitch</name>
                    <value>0</value>
                </Motor>
                <Motor>
                    <name>HeadYaw</name>
                    <value>0</value>
                </Motor>
                <Motor>
                    <name>RShoulderPitch</name>
                    <value>80</value>
                </Motor>
...........全てのモーターのリスト..........
.....................
.....................
            </Motors>
            <name>StandInit</name>
            <description>Nao is ready to do anything from this position !</description>
            <bitmap>media/images/positions/StandInit.png</bitmap>
        </position>
        <position>
            <Motors>
                <Motor>
                    <name>HeadPitch</name>
                    <value>-10.7252</value>
                </Motor>
                <Motor>
                    <name>HeadYaw</name>
                    <value>-0.266079</value>
                </Motor>
                <Motor>
                    <name>LAnklePitch</name>
                    <value>4.04062</value>
                </Motor>
...........全てのモーターのリスト..........
.....................
.....................
            </Motors>
            <name>Stand</name>
            <description>Standing position with low power consumption. </description>
            <bitmap>media/images/positions/Stand.png</bitmap>
        </position>
    </folder>
    <position>
        <Motors>
            <Motor>
                <name>HeadPitch</name>
                <value>0.00916195</value>
            </Motor>
            <Motor>
                <name>HeadYaw</name>
                <value>-0.00464392</value>
            </Motor>
            <Motor>
                <name>LAnklePitch</name>
                <value>-0.349794</value>
            </Motor>
            <Motor>
                <name>LAnkleRoll</name>
                <value>4.19617e-05</value>
            </Motor>
            <Motor>
                <name>LElbowRoll</name>
                <value>-1.51862</value>
            </Motor>
...........全てのモーターのリスト..........
.....................
.....................
        </Motors>
        <version>2</version>
        <name>goromarupose</name>
        <description>吾郎丸ポーズ</description>
        <bitmap>/Users/washida/.local/share/choregraphe/goromarupose_1.png</bitmap>
    </position>
</ChoregraphePositionLibrary>

 

四つのポーズがセットされている。最初は、StandZeroで、これは全てのモーターの角度をゼロポジションに置くということである。スッと立って、手をまっすぐ前に出したポーズである。次が、StandInitで、手を下ろして普通に立っているポジションである。三番目が、Standで、最もモーターの負荷を減らして、立っている状態という解説がついている。最後のものが五郎丸ポーズである。

モーターの角度は、度で記載されているのでラディアンに変更する必要がある。

このファイルを直接咥え込むAPIがNaoqiにあれば一番いい。が、それは探しても今の所見当たらない。

四つのの

コンセプトの管理システムの必要性

今、サリーには、2万語以上のコンセプトが組み込めるようになっている。ただ、もう、絶対使わないだろうなというコンセプトも入っている。それは無駄だ。よく使いそうなコンセプトに入れ替えて、まあ、全体として2万語になればいい。

そのためのシステムなり、データベースが必要だ。潜在的可能性のあるコンセプトを貯めておいて、スコアを与え、スコアの高いものから順番に入れておくというのが望ましい。実際に、wikipediaとか、twitterで使われる頻度、辞書への掲載などの基準でスコア化する。もちろん、ライブでお客さんから出されたお題の場合は、さらにスコアを大きくすべきだろう。

Qichatでヴァーチャルなif文を作る(2)

まとめると、Qichatで、もし 変数 $varが1の時は、Aという処理、0の時はBという処理をするというのは次のように書く。

u:(実行しなさい) わかりました $exec1=1 $exec2=1
u:(e:exec1) $var==1 Aを実行します 
u:(e:exec2) $var==0 Bを実行します 

これだけのことである。もちろん、これ以外にもいろんなやり方はあるだろう。

u:(実行しなさい) わかりました $var==1 Aを実行します 
u:(実行しなさい) わかりました $var==0 Bを実行します 

これでもいいかと思ったのだが、私がやった場合は、動かなかった。このような単純化すれば動くかもしれない。ただ、ぱっと見、「実行しなさい」が二つのイベントルールにマッチするような書き方が違和感がある。

u:(実行しなさい $var==1) わかりました Aを実行します 
u:(実行しなさい $var==0) わかりました Bを実行します 

これでも動きそうな気がする。「実行しなさい」の代わりにイベントだったらどうなるだろう。

NAOの認識コンセプトの上限

サリーやマリーが、即興漫才や謎かけのお題を取得するのは、音声認識機能を使うが、クラウドを全く使わないので、全てローカルでやっている。googleのクラウドなんかも使えなくはないのだが、テレビのスタジオやライブの舞台にネットが繋がるとは限らない。テレビの収録では、ほぼ期待できない。そういうことがわかっているのに、クラウドでしか音声認識ができないというのは、馬鹿げた戦略である。

ローカルでNAOがお題を認識するためには、qichatのconceptを使う。この夏までは、コンセプトに2千数百個を入れて、お客さんのお題に対応していた。少ない。そこで、システムを変えて、日本語wikipediaや数千万のツイートを使って、自力でネタをその場で生成するシステムに変更し、お題の認識可能性も8000語に増やした。それが、10月の初め。

さらに今日、AI的手法で、ウィキペディアやツイートから取得した関連語20000語を識別させようと入力したら、認識のための音素にコンパイルするのに3分以上かかったが、できたのだ。ちゃんと認識する。

NAOのコンピュータは相当古いが、ネタに必要な自作ライブラリやスマホからコントロールするためのHTML5関係のファイルしか入れていないので、メインメモリにもディスクにも比較的余裕があった、ので可能になったのではないかと思っている。

今、実際のネタ作りは、同じローカルネット内のパソコンにお題を送って作成させている。インターネットにつなぐ必要はなく、サリーとマリーとパソコンがローカルネットに繋がっていれば良いので、閉鎖空間でも対応できる。

何れにしても、今日はNAOが2万語以上も識別可能性を持っていることにただ驚愕した。下手すれば、メモリのある限り認識するのではないか。上限が推測できない。まだまだいけそうな気はする。

(その後、2万3千語あたりが、実質的限界であることがわかってきた。それ以上にすると、コンピュータの実行速度が低下する。メモリの誓約だと思われる 2018年11月24日追記)

NAOのUSBをストレージとして使う

NAO2台で、即興漫才はできるようになったが、HALと違って、NAOはCPUもストレージもパワーと容量がない。現在は、ノートパソコン(MAC)を持ち込んで、即興のネタ作りはそれにやらせる形になっているが、ロボットを3台扱うような面倒くささがある。

そこで、CPUパワーはどうしようもないが、NAOのストレージを頭にさせるUSBにできないかと思っている。頭にUSBをさせば醜いが、なるべく短くして、リボンでも飾れば、なんとかなるのではないかと思う。

今、NAOを今日のオーディション用にパッキングしてしまっているので、試せないが、
https://medium.com/@heatherkemp_89938/interfacing-nao-robots-with-the-arduino-in-depth-tutorial-284ecba0b0aa
に手続きが書いてある。全体が面白い記事だが、USBマウントのところだけメモしておく。

(1)NAOにrootユーザーとしてログインしておく。
(2)USBをマウントするフォルダを作っておく(フォルダ名は任意)

# mkdir /mnt/usb

(3)ブロックIDを確認する

# blkid /dev/sdb*
/dev/sdb1: UUID=”04D9–7E06" TYPE=”vfat”

(4)フォルダをマウントする

# mount /dev/sdb1 /mnt/usb

以上である。まだ試していない。

NAO、コンセプトの搭載可能数

Pepperは、クラウドで、qichatのワイルドカード認識に対応しているようなのだが、NAOについては、NAOQIバージョンもPepperほどにも更新されておらず、対応していないようだ。それはそれでいい。というのは、Qichatでは、conceptにリストアップしておけば、ロボットはかなり正確に人の言葉を認識できるからだ。だから、conceptにどれだけのワードが載せられるかは、非常に重要な仕様になっている。
まえから、幾つもに切り分けしていれば、500個以上のコンセプトを識別できることはわかっていた。それは、実際使っているものだ。
しかし、一つのconceptのなかに、幾つ詰め込むことができるかは調べたことがなかった。実は、多くのコンセプトに分けるよりも、一つに詰め込むと便利なことがある。とても便利になるのだ。今日試してみてとても驚いた。なんと、一つのコンセプトに、2000個以上のワードを詰め込んでも、識別できたのだ。つまり、トピックファイルの中に、
concept:(words) [今日 明日 ロボット などなど ・・・・・・]
と2000個以上の言葉をwordsというコンセプトで登録しておいても、たとえば
u:(お題は _~words です) なになに $1・・・・・・
というかたちで、言葉の認識、変数 $1 への代入が可能になるのだ。もちろん、ALDialogで、そのトピックファイルを読み込み、コンパイルするのには多少時間がかかる。20秒くらいか。それは、スタート時だけだから、全然大したロスではない。
2000個も入れると、言葉の中に変な文字、つまり、ロボットが発音できない文字が入っていると、コンパイルに失敗してトピックファイルが有効化されない。アンダースコアとか、全角の数字(これがエラーになるのはちょっと不思議だが)とか、「つ」の小さい版「っ」がワードの最後に発音しにくい形で入っていても、コンパイルエラーになった。しかし、数の大きさは平気だったのだ。
NAOがワイルドカードの認識が下手なので、やむ負えず、Googleのcloud APIで変換させたりしていたのだが、音源ファイルで送ろうとも、ストリーミングにしようとも、やはり、人が喋ってからその結果をロボットに返すまでに10秒余のロスが発生して、ネタの120秒などという短い尺には、耐えられない長さになってしまう。conceptにおいて、聞き取られレベ、ほぼリアルタイムで時間のロスがない。
2000個というのは相当のキーワード数だ。実際それ以上が可能かもしれない。それ以上を試す気になれないほど、2000という数字は大きかった。