前回は、PSDセンサで対戦相手を見つけるところまで説明した。今回は連載の最終回として、いよいよ大会で使用したバトル用プログラムについて解説することにしたい。
モーションを実行させる
前回のサンプルプログラムでは、RCB-4にコマンドを送って、腰ヨー軸のサーボモーターを直接制御している(RCB4_comクラスのmove_waist関数)。ここでは動かすサーボモーターが1個だけだったのでこの方法で良かったが、ロボットを歩かせたりする場合には、全身の17個ものサーボモーターを同時に制御する必要がある。
PCのプログラム側から全サーボモーターを制御し、歩かせることもできなくはないが、やや面倒。そこで、今回のバトル用のプログラムでは、KHR-3HVで用意されているモーション再生機能を活用する方法を試した。
KHR-3HVでは、付属ソフト「HeartToHeart4」を使って、ロボットのモーション(動き)を作成することができる。詳細については省略するが、歩行や攻撃など、モーションデータを事前にRCB-4に書き込んでおいて、コントローラのボタンを押すことで、指定したモーションを再生できる仕組みだ。
コントローラのボタンを押す代わりに、PCからボタン番号を送信することで、同じようにモーションを再生することができる。そのためのコマンド列は、連載の第2回で紹介した「RCB4CommandGenerator LE」を使えば、簡単に作成可能。たとえば、1歩前進するモーション(ボタン番号は1)を再生する場合、コマンドは下図のようになる。
用意したモーションとボタン番号は、上のHeartToHeart4画面の右側を見て欲しい。1歩前進のほか、2歩前進のモーションも作ってあり、この2つを組み合わせることで、任意の歩数の前進を実現している(RCB4_comクラスのgo_forward関数)。そのほかのモーションを実行する関数としては、以下のものを用意した。
関数 | 内容 |
---|---|
go_forward | 指定した歩数だけ前進する |
go_back | 指定した歩数だけ後進する |
go_left | 指定した歩数だけ左移動する |
go_right | 指定した歩数だけ右移動する |
rotate_left | 指定した角度だけ左旋回する(10°単位) |
rotate_right | 指定した角度だけ右旋回する(10°単位) |
stand_up | 加速度センサの値を参照し、転倒していたら起き上がる |
attack | 指定した攻撃モーションを出す(3種類) |
モーション実行関数 |
バトルのアルゴリズム
バトル用のプログラムは、以下の「battle.py」になる。処理がやや分かりにくいかと思うので、ソースの解説をしておこう。
「battle.py」(圧縮ファイルですので、解凍してご利用ください)
main関数でまず行っているのは、ユーザーインタフェースの作成だ。開始ボタンと停止ボタンのほか、攻撃モーション用のチェックボタンも付けた。ここでチェックを外した攻撃技は、バトル中に出さないようになっている。また最後の方では、バトル制御用のf_loop関数を別スレッドとして立ち上げている。
f_loop関数では、変数stateが現在の「状態」を示しており、その状態が遷移することで、バトルの処理を実現している。状態は0~4までの5種類で、遷移する関係は下図の通りとなる。
初期状態となるstate=0の「探索」では、前方±90°の範囲で相手を探す。もし見つかればstateを1に、見つからなければstateを2にセットする。
state=2の「索敵行動」では、4歩前進して、再びstateを0に戻す。また前進する前に、さきほどの「探索」で調べておいた左右の床面のデータもチェックして、崖側から離れるように、旋回する処理も実装している。
state=1の「接近」では、まず見つかった相手が正面に来るように旋回。もし相手までの距離が30cm以内なら、攻撃のためにstate=4にセット。しかし30cm以上離れているようなら、歩数を計算して(実測で1歩=7cm)、30cm以内まで近づくように前進、state=3にセットする。
state=4の「攻撃」では、技の優先順位と射程距離から、出す技を決定している。技は、優先度が高い順番に、前転キック、投げ、ダブルパンチの3種類を用意。射程距離は、attack_range_minとattack_range_maxの2つの配列で下限と上限を指定している。攻撃を実行したあとは、state=3にセットする。
ここで攻撃の「捨て身技」について補足しておこう。前転キックのような特殊な技はROBO-ONEにおける捨て身技となるので、ルール上、試合では1回しか使えない。そのため、配列attack_onceでフラグを立てた技については、1回しか出せないように実装している。
state=3の「敵位置確認」は、state=0の「探索」に似ているが、より早く処理を終わらせたいので、調べる範囲を前方±40°に狭めている。相手が見つかればstate=1にセットし、見つからなければstate=0にして「探索」からやり直す。
なお各状態の処理を行う前に、ループの先頭でロボットが転倒していないか調べている。もし転倒していたら起き上がり、stateを初期状態の0にセットしている。
とりあえず状態は以上の5つだけで作成したが、このように実装しておけば、あとで状態を追加するのも簡単。状態を増やして、より複雑なアルゴリズムにしても良いだろう。
完成したプログラムでテストしたところ、動作に特に問題は無さそうだったのだが、やはり距離や角度を大雑把に作っているため、精度にはやや課題がある。レギュレーション上、腕を通常より短くしている影響もあり、攻撃を空振りすることも多い。しかし今回は時間もないので、その修正は断念した。
対戦相手はまさかの…
そして迎えた大会当日。筆者の対戦相手は、なんとROBO-ONEで優勝経験もある強豪の「シンプルファイター」。もともとこちらはROBO-ONE Light向けのKHR-3HVなので、誰が相手でも倒して勝つのはほぼ不可能ということは最初から分かっていたものの、それにしてもこの相手は特に厳しい。
ただ、相手が勝手にリングアウトしたり、動かなくなってしまったりして、うっかり勝つ可能性もあるのが自律バトル競技である。それを期待しつつ、試合が開始。
しかしご覧の通り、結果は惨敗。他の出場ロボットはみんな予想通り、索敵に時間をかけていてそんなに突っ込んでこなかったのだが、シンプルファイターはとにかく接近が早かった。こちらが呑気に周囲をスキャンしている間に距離を詰められ、あっという間に倒されてしまった。プログラムとの相性も悪かった。
負けたこと自体は仕方ないのだが、筆者としては、出場の目標としていた「相手を見つけて攻撃を出す」ことができなかったのが何より悔しい。他のロボットが相手だったら攻撃できたかも……と思わなくもないが、それを言い出したらキリが無い。クジ運も含めてバトル競技というものだ。
とはいえ、当初の目標が果たせなかったわけだから、このまま終わるわけにはいかない。KHR-3HVのままではどうにもならないので、3kgクラスのオリジナルロボットを作り、センサーやプログラムも変えて、来年2月開催の第3回大会への出場を目指す予定である(間に合うかどうかは不明)。