ロビ2メインプログラムの解析
2023年12月28日


 ロビ2のメインプログラムについて解析したので処理の流れやアドレスを備忘録としてまとめました。
 ロビ2のプログラムはメインプログラムと全部のサブプロログラムをSTARTUP.BINというプログラムファイルひとつで提供されています。
 ここはロビ2を起動してから音声認識などで実行命令を受け取る部分をメインプログラムと呼んでその部分を解析しています。
 プログラムがひとつなのでプログラムの箇所はアドレスで表示しています。
 アドレスというのはSTARUP.BINのファイル位置をバイトアドレス(16進数)で表します。  実際のプログラムでジャンプ先(jump)やサブルーチン(call)はこのアドレスが使われます。

 ロビ2のプログラムコマンドはこちらの記事(2019/4/27)を参考にしててください。
 ロビ2のマイコンメモリについてはこちらの記事(2021/1/19)を参考にしててください。
 ロビ2のプログラム解析にはロビプログラムアナライザーを使うと便利です。


初期化処理

 ロビ2が起動されるとSTARTUP.BINの最初から実行されます。
 STARTUP.BINの最初の部分(0x00000000〜0x00000a74)は各サーボモーターのパラメータ―などをマイコンボードにセットする命令で構成されます。
 一連のセットが終わったらメイン処理の部分コールしています。
 0x00000a7a
   <call adr="0x00000a84"/>
 このcall命令の後は自分のアドレスにジャンプ命令が入れられているのでロビは停止する
 callで呼ばれたメインプログラムの最初はカメラの接続チェックなどの一連の初期化処理が続く

 0x00000bb9
   <walt data="60"/>
 先頭で電源投入後のデバイスの安定を1秒(60)待つ

 0x0000149f
   <fread filename="VOLUME.BIN" adr=""0x0046"/>
 音量設定ファイルからデータを読み込んでロビの音量をセットする

 0x000015ad
   <fread filename="VBATALART_INT.BIN" adr=""0x0092"/>
 電圧警告設定ファイルからデータを読み込んで電圧低下警告の電圧をセットする

 0x00001653
   <fread filename="ENABLEINITML.BIN" adr=""0x0fa8"/>
 制御フラグ設定ファイルからデータを読込んで頭のスイッチで独り言のフラグをセットする

   0x000014ee
 サーボトルクをOFFの状態でサーボを原点に動かす
 この時目のLEDを標準色(橙)に点灯しようとしていますがプログラムが間違っているようで目は点灯しない

 0x000017d0
   <fread filename="ERRORCHKIGNORE.BIN" adr=""0x0fa8"/>
 起動時エラーチェック抑制フラグ設定ファイルからデータを読込んで設定されていた場合は起動時エラーチェックを行わない(0x00000d4eにジャンプします)

 0x000017bc
   <call adr="0x0000739d"/>
 画像処理ボード/音声認識ボード/赤外線ボード/RTCボード/Bluetoothボードの接続をチェックする
 エラーの場合、ロビがエラー内容を音声で伝えてロビが停止する

 0x00000b8e
   <call adr="0x00001c39"/>
 ロビの初期化(現在日時の設定およびユーザ登録)が終了しているかをチェックする
 ロビが初期化されているかはこのサブルーチンでINITPASSED.BINを読んでチェックする

 初期化されていない場合は目覚め一連の動きを行い続いて初期化(現在日時の設定およびユーザ登録)を行う
 0x00000dea
   <call adr="0x00003698"/>
 メッセージの初期化。
 ユーザデータを10人分読込んでデータで未登録のユーザ(0)に対するメッセージを消去する(0x00026917)

 0x00000d4e
   <call adr="0x00003401"/>
 ユーザデータを10人分読込んだデータは特に使っていない→何をしたいのか分からない?

 0x000000c47
   <call adr="0x00002bf0"/>
 画像認識ボード初期化を行う

 0x000000d3a
   <call adr="0x00002d67"/>
 音声認識ボードの初期化およびチェックを行う。

 0x00001a00
   <calc><mem_r size="1" adr="0x0fa8"/><const data="0"/><sub/><lt/><jump adr="0x0001873"/></calc>
 エラーの場合は0x0001873にジャンプして「音声認識ボードの調子がおかしいようです」と言ってプログラムを停止する

 0x00001125
   <fwrite filename="WAKEUP_DATETIME.BIN" adr=""0x0e2"/>
 時刻記録ファイルに現在日時を書込む

 0x00001480
   <calc><const data="0"/><mem_w size="1" adr="0x0f83"/></calc>
 顔の向き変数(0x0f3)を正面(0)にする

 0x00000148b
   <call adr="0x00005666"/>
 ロビの顔を顔の向き変数(0x0f83)で表す方向に動かす

 0x0000010e2
   <call adr="0x00004411"/>
   <calc><mem_r size="1" adr="0x0fa8"/><mem_w size="1" adr="0x0f82"/></calc>
 ロビの姿勢を取得して姿勢変数(0x0f2)にセットする
 姿勢に合わせてサーボを動かし動かすサーボを設定する

  立ち姿勢(0x00000e03)
  座り姿勢(0x00000e9b)
  充電椅子姿勢(0x00000f33)

 0x00000fd0
   <calc><const data="1"/><mem_w size="2" adr="0x0048"/></calc>
 サーボトルクをONにする

 0x0000164c
   <walt data="70"/>
 1.17秒(70)待つ

 0x00001b02
   <fread filename="OPENINGALERTIGNORE.BIN" adr=""0x0fa8"/>
 開始エラーチェック抑制設定ファイルからデータを読込んで設定されていた場合はユーザ登録チェックとRTCチェックを行わない(0x000001a17までジャンプする)

 0x0000015db
   <call adr="0x000056f9"/>
   <calc><mem_r size="2" adr="0x0fa8"/><const data="0"/><sub/><eq/><jump adr="0x0001615"/></calc>
 ユーザ登録チェックを行い未登録の場合(0x00001615)ユーザ登録処理を行う
 ユーザ登録処理は「あれ登録がないよ」と言って(0x000059ac)登録処理(0x00005853)を行う

 0x000001c25
   <call adr="0x00007931"/>
 RTCが正しく動作しているチェックする

 0x00000ba2
   <calc><mem_r size="1" adr="0x0fa8"/><const data="0"/><sub/><lt/><jump adr="0x0001629"/></calc>
 戻り値をチェックして-1の場合「電池切れかも」と言う(0x0000622b)、ロビの動作はそのまま続ける

 0x000001a17
   <call adr="0x000077a0"/>
 タイムアウト設定を行う

 0x000001074
   <jump adr="0x0000ac1"/>
 アイドリングループにジャンプする


アイドリングループ

 0.7秒周期で音声入力待ちや電圧監視などを繰り返し行う。
 ロビの動きとしては目をLEDの明暗で点滅させ手を小刻みに振るわせる動作を行います。

 0x00000ac1
 0x00000d7e
   <calc><mem_r size="2" adr="0x0088"/><const data="48"/><sub/><eq/><jump adr="0x0000d62"/></calc>
 カメラで人を検出したかチェックする
 検出した場合は顔の追従機能にジャンプします

 0x00000459b
   <call adr="0x0000171a"/>
 メッセージおよび独り言の監視する

 独り言についてはこちらの記事を参照してください

 0x00000c9e
   <calc><mem_r size="2" adr="0x0e66"/><const data="0"/><sub/><ne/><jump adr="0x000182e"/></calc>
 赤外線を受信したかチェックする
 受信した場合は赤外線受信処理にジャンプする

 0x00000b47
   <calc><mem_r size="2" adr="0x00a6"/><mem_r size="2" adr="0x0f20"/><sub/><ne/><jump adr="0x0000b42"/></calc>
 現在の送信カウント(0x00a6)と前回の送信カウント(0x0f20)を比較して新しいBluetooth信号を受信したかチェックする
 新しいBluetooth信号の場合Bluetooth信号受信処理にジャンプする

 0x00000ae1
   <calc><mem_r size="2" adr="0x0e58"/><const data="2"/><sub/><ne/><jump adr="0x0000c71"/></calc>
 音声認識が完了したかチェックする
 音声認識が完了した場合次のジャンプ命令で音声認識完了処理にジャンプする

 0x000010cb
   <calc><mem_r size="2" adr="0x0e5a"/><const data="16"/><and/><ne/><jump adr="0x000146c"/></calc>
 音声を認識した場合音声認識モーションをコールする

 0x0000011dd
   <call adr="0x00004b22"/>
 電圧およびタイムアウトの監視、ロビのアイドリングポーズもこの中で行なう

 0x00001795
   <calc><mem_r size="1" adr="0x0fa8"/><const data="0"/><sub/><lt/><jump adr="0x000177e"/></calc>
 戻り値をチェックして-1の場合タイムアウト処理を行う

 0x000001599
   <call adr="0x00005666"/>
 顔の向きを顔の向き変数(0x0f83)に合わせる(プログラムで動かした場合現在ロビの向いている方向に戻す)

 0x00000bf9
   <call adr="0x00000ac1"/>
 アイドリングループの先頭に戻る

タイムアウト処理
 0x0000177e
   <calc><mem_r size="1" adr="0x0f82"/><const data="0"/><sub/><eq/><jump adr="0x000176a"/></calc>
 ロビの姿勢を判定して立ち姿勢の場合は座らせる

 0x00000176a
   <call adr="0x00006dc2"/>
 ロビを座らせるサブルーチン

 0x000001a67
   <call adr="0x000077a0"/>
 タイムアウト値をリセットする
 IDLE_TIMEOUT_SITDOWN.BINを読み込む

 0x0000077a0
   <jump adr="0x0001599"/>
 
アイドリングループに戻る

音声認識モーション
 0x00000146c
   <call adr="0x0004979"/>
 ロビを一瞬黒目にするサブルーチンをコールする
 ロビの目の色を変更するだけなので目以外はモーション判定フラグ(0x0f24の0x00000080)で現在のアイドリングポーズと同じポーズにする

 
監視サブルーチン

 このサブルーチンで電圧の監視やタイムアウト監視を行う
 ロビの目のLEDの明暗で点滅させたり手を小刻みに振るわせる動作もこのサブルーチンで行う

 0x00004b22
   <calc><mem_r size="2" adr="0x0f82"/><const data="2"/><sub/><ne/><jump adr="0x0005328"/></calc>
 ロビの姿勢をチェックして充電椅子モードの場合は電圧監視処理を飛ばす
 充電椅子モードの場合はマイコンボードの電圧警告のしきい値を0にセットする(マイコンボードの電圧警告は行わないようにする)

 0x000053eb
   <fread filename="VBATALART_INT.BIN" adr=""0x0092"/>
 マイコンボードの電圧警告のしきい値データファイルを読み込む

   0x000053eb
   <fread filename="BATALART_AUTOPOWOFF.BIN" adr=""0x0fa8"/>
 プログラムの電圧警告のしきい値データファイルを読み込む

   0x00005260
   <calc><mem_r size="2" adr="0x0090"/><mem_r size="2" adr="0x0fa8"/<sub/><lt/><jump adr="0x000544e"/></calc>
 現在の電圧としきい値を比較して低い場合は
電圧低下処理にジャンプする

 0x00004d4d(充電椅子モードの場合もこちらジャンプ)
 0x00004d36
   <calc><mem_r size="2" adr="0x0f82"/><const data="0"/><sub/><ne/><jump adr="0x00052dc"/></calc>
   <jump adr="0x00004d06"/>
 充電椅子モードと座りモードの場合はつま先振動動作にジャンプする

 0x000052dc(立ちモードの場合)
 0x00004d06(つま先振動動作からの戻り)
 0x00004f6b
   <calc><mem_r size="2" adr="0x0088"/><const data="48"/><sub/><eq/><jump adr="0x0004f54"/></calc>
 画像認識ステータスをチェックして検出した場合はロビの目をピンクにする
 この後検出人数を取得して1人以上の場合は画像認識ステータスをチェックして検出した場合はロビの目をピンクにしたアイドリングモーションを動かす(0x00005249)
 詳しい解説はアイドリング時の顔認識を参照してくださいい

 0x00004f3d
   <calc><mem_r size="2" adr="0x00a0"/><const data="0"/><sub/><gt/><jump adr="0x00050da"/></calc>
 Bluetoothの受信ステータスをチェックして受信を検出した場合はロビの目を黄色にしたアイドリングモーションを動かす(0x000050da)

 0x00004f26
   <calc><mem_r size="2" adr="0x0f24"/><const data="128"/><sub/><ne/><jump adr="0x0004dce"/></calc>
 目が橙色の場合のモーション
 モーション判定フラグ(0x0f24の0x00000080)を判定してどちら(LEDの明暗)のモーションにするか決定する

 0x00004de7
   <mem_w size="2" adr="0x0a00"/>
     0x0000,0x0064,0xffe7,0x0000,0xfc4a,0x0000,0x0096,・・・
     0x0000,0x0064,0x0000,0x0009,0x0000,0x0009,0x0000,0x0064,0x0000,0x0064,0x0000,0x0064,0x0000,0x0064,0x0000,・・・
     ・・・,0x0014,0x0000,0x0032,0x0014,0x0000,
 目が橙色(暗い)で両腕を戻したモーション
 LEDはRGB(90,35,0),ID17=0°,ID20=0°

 0x00004e93
   <mem_w size="2" adr="0x0a00"/>
     0x0000,0x0064,0xffe7,0x0000,0xfc4a,0x0000,0x0096,0x0064,・・・
     0x0000,0x0064,0x0000,0x0009,0x0000,0x0009,0x0000,0x0064,0xffe7,0x0064,0x0000,0x0064,0x0000,0x0064,0x0019,・・・
     ・・・,0x00af,0x0064,0x0000,0x00af,0x0064,0x0000,
 目が橙色(明るい)で両腕を広げたのモーション
 LEDはRGB(175,70,0),ID17=-1.9°,ID20=1.9°

 0x00004d1d
   <calc><mem_r size="2" adr="0x0f24"/><const data="128"/><xor/><mem_w size="2" adr="0x0f24"/></calc>
 モーション判定フラグ(0x0f24の0x00000080)を反転させて次のアイドルループで他方のモーションが動くようにする
 目がピンクや黄色の場合もここでフラグを反転させる

 0x00005420
   <calc><mem_r size="4" adr="0x0080"/><mem_r size="4" adr="0x0fac"/><sub/><ge/><jump adr="0x00005442"/></calc>
 現在の経過時間とタイムアウトのしきい値変数を比較して越えている場合は戻り値-1でサブルーチンを終了する

 0x00005432
   <calc><const data="1"/><mem_w size="1" adr="0x0fa8"/></calc>
   <return/>
 電圧低下もタイムアウトもない場合は戻り値1でメインプログラムに戻る

つま先振動動作
 0x00004d06
 0x00004c17
   <calc><mem_r size="1" adr="0x0f82"/><const data="1"/><sub/><eq/><jump adr="0x0004c2e"/></calc>
   <jump adr="0x00004c9a"/>
 姿勢判定で座り姿勢と充電椅子で分岐する

 0x00004c47
   <mem_w size="2" adr="0x0ac0"/>
    0x0000,0xffe2,0xfbd2,0x0000,0xfed9,0x0000,0x001e,0x042e,0x0000,0x0127,・・・
 座り姿勢でつま先を曲げるモーション(ID5=-29.5°,ID10=29.5°)

 0x00004bc4
   <mem_w size="2" adr="0x0ac0"/>
    0x0000,0xffe2,0xfbd2,0x0000,0xfef2,0x0000,0x001e,0x042e,0x0000,0x010e,・・・
 座り姿勢でつま先を戻すモーション(ID5=-27.0°,ID10=27.0°)

 0x00004c12
   <jump adr="0x00004d06"/>
 監視サブルーチンメインに戻る

 0x00004cb3
   <mem_w size="2" adr="0x0ac0"/>
    0x0000,0xffe7,0xfc4a,0x0096,0xff4c,0xfff1,0x0019,0x03b6,0xff6a,0x00b4,・・・
 充電椅子姿勢でつま先を曲げるモーション(ID5=-18.0°,ID10=18.0°)

 0x00004bc4
   <mem_w size="2" adr="0x0ac0"/>
    0x0000,0xffe7,0xfc4a,0x0096,0xff60,0xfff1,0x0019,0x03b6,0xff6a,0x00a0,・・・
 充電椅子姿勢でつま先を戻すモーション(ID5=-16.0°,ID10=16.0°)

 0x00004ba6
   <jump adr="0x00004d06"/>
 監視サブルーチンメインに戻る

電圧低下処理
 0x0000528b
   <calc><mem_r size="1" adr="0x0f82"/><const data="0"/><sub/><eq/><jump adr="0x0005277"/></calc>
 ロビの姿勢を判定して立ち姿勢の場合は座らせる

 0x000005277
   <call adr="0x00006dc2"/>
 ロビを座らせるサブルーチン

 ランダムに下のどちらかのルーチンをコールする

 0x0000053b1
   <call adr="0x0002ca6a"/>
 「もうだめかも」と言うサブルーチンをコールする

 0x0000052a2
   <call adr="0x0002b5eb"/>
 「ジューデンシテ」と言うサブルーチンをコールする

 0x00000547c
   <call adr="0x000076da"/>
 ロビを停止させるサブルーチンをコールする


音声認識完了処理
 0x00000af8
   <calc><mem_r size="2" adr="0x0e5a"/><const data="2"/><and/><ne/><jump adr="0x00000b0f"/></calc>
 この音声認識ボードが聞き取れたかチェックして聞き取れた場合次の命令で音声認識語処理ルーチンをコールする

 0x0000011bf
   <call adr="0x00004979"/>
 このサブルーチンで音声認識語の解析並びに音声認識語に割り当てられた命令を実行する

赤外線受信処理
 0x00000182e
   <calc><mem_r size="4" adr="0x0f26"/><mem_r size="4" adr="/><sub/><lt/><jump adr="0x0001731"/></calc>
   <calc><mem_r size="4" adr="0x0f26"/><mem_r size="4" adr="/><sub/><mem_w size="4" adr="0x0f26"/></calc>
   <calc><mem_r size="4" adr="0x0f26"/><const data="-1"/><mul/><mem_w size="4" adr="0x0f26"/></calc>
   <calc><mem_r size="4" adr="0x0f26"/><const data="90"/><sub/><lt/><jump adr="0x0000d1a"/></calc>
 前回のループで赤外線を受信しなかった場合は0x0f26に0x0080(経過時間)が保持されている
 現在の経過時間との差分を計算して90(1.5秒)以内であれば有効な赤外線データとして処理する

 0x000000d1a
   <calc><const data="128"/><mem_w size="4" adr="0x0e56"/></calc>
 音声認識を停止する

 0x000000d06
   <call adr="0x0002ee3"/>
 このサブルーチンで赤外線コードの解析並びに赤外線コードに割り当てられた命令を実行する

Bluetoothデータ受信処理
 0x000000b42
   <jump adr="0x0000b4e"/>
 0x000000b4e
   <calc><const data="128"/><mem_w size="4" adr="0x0e56"/></calc>
 音声認識を停止する

 0x000000bd0
   <call adr="0x0002087"/>
 このサブルーチンでBluetoothコードの解析並びにBluetoothコードに割り当てられた命令を実行する

 0x000000bc0
   <calc><mem_r size="2" adr="0x00a6"/><mem_w size="2" adr="0x0f20"/></calc>
 Bluetoothの送信カウント変数を現在値に更新する


 アイドリングループの周期は目の点滅間隔でだいたい1秒位と認識していました。
 今回はアイドリングループの正確な時間を計測してみました。

 次のプログラムを使って計測しました。

  
loop_test.txt

 このプログラムをロビプログラムコンパイラーで読み込みSTARTUP.BINに書き込みます。
 音声認識語は「テストなんだ」に割付けます。

 アイドルループからこのプログラムにジャンプするようにSTARTUP.BINにパッチを当てて飛び先を変更します。
 0x00000c85:0x000010db→0x001d5995

 TEST_START.LOGとTEST_END.LOGというファイルをロビ2のSDカードに入れておきます。
 それぞれ3バイト以上のファイルで適当なxxxx.BINをコピーして作ってください。
 1000回のループで測定しました。
 次のような結果になりました。

   

 バイナーエディタで16進で表示しています。
 0バイト目がRTCの秒、1バイト目がRTCの分、2バイト目がRTCの時が記録されます。
 開始時刻が9時13分43秒で終了時刻が9時25分23秒となります。
 よって経過時間は11分40秒=700秒となります。
 1000回のループで測定していますので1回のループは0.7秒となります。

 ちなみにロビ1でも測定してみました。
 ロビ1の場合RTCがないので起動時からの経過時間(0x0080)を記録します。
 ロビ1のタイムアウトは充電椅子モードでも3分なので1000回のループだとタイムアウトで終了するため100回のループで測定しました。
 次のような結果になりました。

   

 0x0080を直接書き込んだのでバイトが下位バイトから書かれています。
 開始時刻が0x0000014c(332)で終了時刻が0x0000253c(9532)となります。
 経過時間は9200となりマイコンのクロック時間で1秒が60なので153.3秒となります。
 100回のループで測定していますので1回のループは1.5秒となります。
 ロビ1の場合1回のループで目の点滅と腕の振動1回分をやっているので倍以上の時間がかかっています。
 ロビ2の場合フラグ管理でこれらの動きを2回のループに分けて行っています。


目次に戻る