2019年12月24日火曜日

Humanoid Robot Sports カーリング用プログラム解説


前回紹介したロボットカーリング。私のロボットに実装した、画像認識に基づく自動制御についてのおおまかな解説です。

どんな競技?


カーリング競技のルールはこちらに公開しました。→IRCカーリングルール(Googleドキュメント)面倒であれば、とりあえずゴルフのようなもの、と思ってもらえれば結構です。
関東ロボット練習会での実演例です。全体の流れがわかると思います。

位置の認識

物体の位置や向きは地面平面上でロボットを中心とした座標で表します。ロボット進行方向をx軸、左方向をy軸、足元を原点とします。
周囲の環境をマッピングするようなロボットの場合これに加えて原点を競技台等に固定した座標系も用いるのですが、今回それに相当する処理は実装しませんでした。ひたすらゴール方向に蹴る動作を繰り返せば課題は達成できるからです。
途中に残ったパックを回避しながら歩く、というような高度な処理をするならそれらを含めたフィールドの地図を作る必要があるでしょう。

物体の検出

処理の最初に、カメラの画像を地面と平行な平面に投影します。Homographyと呼ばれる、変面から平面への射影変換(回転と移動と遠近法的な変形)です。これにより以降、物体の大きさや形状を単純に画像上の面積・形状として扱うことができます。(位置にかかわらず縮尺が一定となるため)
厳密には、パックは高さがあるので形状が若干縦長に伸びた形になります。しかし、遠い位置にある場合はあまり精度はいらないので無視しました。

遠くを見ているときの画像例(右は直交化後各種要素の検出結果を重畳表示したもの)

※チェッカーボードは処理を見た目にわかりやすくするための参考用に置いたものです。

 足元を見ているときの画像例



ゴールとパックはいずれも画像上で特定の色の領域として検出します。更に面積が一定以上という条件、それから丸い形状ということで周長と面積の比が円に近いようなものという条件も付加しました。
パックは黄緑色のものにしました。ゴールの黄緑色と近いのですが、自分に近い方をパックとして認識します。
また、ゴールから遠い時にゴールの方向がわからないことも想定して、コースの端を認識する機能も用意しました。直線Hough変換に基づくものです。

カメラ

パックが遠い時はカメラの俯角を小さく(25度程度)して遠くを見る必要があります。このままでは足元が見えないので、30cm程度まで近づいたらカメラの俯角を75度程度にして下を見ます。
これに合わせて2通り、直立状態におけるカメラと地面の位置関係を事前に計測してあります。そのキャリブレーションデータを使って上のHomographyを計算します。
歩行中は視点の位置や姿勢が正確にはわかりませんが、先に述べたように精度はさほど必要ないので直立時と同じとして計算しています。

移動

まず、パックを蹴るための移動について。
パックに向かって歩いてきます。ロボットから見たパックの向きを正面にするように旋回角度へフィードバックしつつ前に進んでいきます。

ただこれだけですと、ゴールの方向から進行方向が外れてしまうことがあります。
そのため遠くを見てゴールとパックが両方見えているときは、パックからゴールへ引いた線の傾きを求め、それが0(真正面方向)になるように更に左右方向への移動や旋回を上乗せします。これらのフィードバック成分を適度に組み合わせる(現物合わせでゲイン調整する)と、うまく位置取りをするような動きが生成できました。

具体例で説明します。図ではロボットの真正面にパックがあります。これだけなら真っ直ぐ歩くところですが、パックからゴールへ引いた矢印を見ると、左に傾いています。そのため自分が右の方に移動するようにします。これは、ゴールとパックを結ぶ線の延長線上に近づく方向になっています。このままではパックに対してそっぽを向いてしまいますが、延長線上に近づくとこの効果は減っていきます。代わりに、先の「ロボットから見たパックの向きを正面にする」旋回が優位となり、パックとゴールの方に自然と向き直っていきます。

この処理が適用されているところは、IRC2019大会での動画がわかりやすいと思います。


パックが足元近くに来たら、前後歩行と横歩きを使ってパックが所定の位置に来るように調整します。所定の位置というは、キックモーションに合わせてちょうど上手く蹴ることのできる位置を予めロボットからの相対座標で与えています。
歩行中は左右への重心移動動作によってカメラの位置が随時変わっていますが、これを補正する方法は現在用意していません。このため精度よく検知するのが難しいので、ある程度近くになったら立ち止まって画像撮影・観測→数歩移動、という動作を繰り返して最終調整をします。

最終調整・ゴールへ向けて蹴る

カメラを前方と下方に交互に向けて、足元にあるパックとゴールとの距離・位置関係を得ます。パックが蹴るための位置十分近く、かつゴールとパックを結ぶ線がロボットの正面方向に平行となるまで、何回か歩いて停止・観測を繰り返します。実際には何回か繰り返したら強制的に次に移るようにしました。必ずしもぴったりに調整できず、そして競技時間の制限もあるためです。

最後に蹴る強さを決めます。蹴る強さと飛ぶ距離の関係を予め計測しておきます。最弱のキックで200mm程度としました。本来は確率分布を持ったものになるはずですが、ひとまず、蹴った強さに応じて確実にそれだけ進むと仮定しています。
十分近ければ赤色を狙う、そうでなければ黄色ゾーン手前までに留められる距離で最大限、というだけのアルゴリズムとしました。これにより、できるだけ黄色近くまで寄せてそこから真ん中を狙う、という挙動になります。

見えないゴールへ向けて蹴る

話が前後しますが、ゴールから遠いときの戦略について。
コースの端とロボットとの位置関係は使用していません。パックが見えている場合、それに向かって歩いていけばコースアウトすることはないからです。
とはいえ、向きを考えずに蹴るとパックが次第に端に寄っていってコースアウトしてしまうので、ゴールが見えればその方向、見えなければコースの縁の線に対して平行な方向に蹴ります。ここでコース端の線検出結果を使います。

その他

自律競技では操縦型と異なりキック回数が無制限となっています。そのため、サッカーのドリブルのように歩きながら細かく蹴ってゴール付近まで運ぶロボットもいました。Spiritにはカメラが1台しかなく、ゴールと足元のボールを同時に見ることが難しくなっています。そのため、ゴルフのように止まって長い距離蹴った後歩いて追いつく、という方式にしました。

電源分配基板

電源分配用基板を作り直しました。 電源をON/OFFするためのパワーMOSFETと、基板にネジが落ちるなど不慮の事故に備えての安全のための電流ヒューズを載せました。ロボットの操作パネルに付く電源スイッチ(定格5A)は駆動用電流を直接流すためではなく、このMOSFETのゲート電圧を...