二足歩行ロボット開発日記(2) 押されたら一歩踏み出す制御を作った

ロボット開発
開発日記 #2

二足歩行ロボットを作る(2)
押されたら一歩踏み出す制御を作った

前方への耐性は29%改善。ただし側方は、1ミリも動きませんでした

使用ツール: MuJoCo / Python ゴール: 踏み出しによる外乱対応

前回のおさらいと、今回の結論

前回は、MuJoCo上に10自由度の二足歩行ロボットのモデルを作り、「押されても倒れずに立ち続ける」バランス制御までを作りました。ただしその制御は両足を地面につけたまま踏ん張るもので、当然ながら限界があります。

今回はその先、大きく押されたら片足を踏み出して踏みとどまる制御を作りました。人間が後ろから押されたときに、無意識に一歩出るあの動きです。

先に結論を書きます。

押される方向前回(両足固定)今回(踏み出しあり)
前方12N15.5N(+29%)
側方14N14N(変化なし)

前方は狙いどおり伸びました。しかし側方はまったく改善しませんでした。足を踏み出しているのに、踏み出さない制御と同じ数値なのです。正直、これは想定していませんでした。

そしてもうひとつ。前回の記事に載せた数値そのものが、間違っていました。測定のしかたに不備があったのです。その経緯も含めて、今回もそのまま記録します。

黄昏の戯れ
中の人

失敗が3つに、訂正が1つ。今回もにぎやかな回になりました。

なぜ「踏み出し」なのか

両足を地面につけたまま姿勢を戻せる範囲には、物理的な上限があります。足の裏が地面と接している範囲(支持基底面と呼びます)の外側に重心が出てしまえば、あとはどんなに関節を頑張らせても倒れます。

人間も同じです。軽く押されたときは足首や腰で吸収しますが、大きく押されれば足が出ます。あれは意識してやっているのではなく、支持基底面を作り直すことでしか対応できない領域に入ったということです。

つまり踏み出しは、制御の工夫というより物理的な制約そのものを動かす手段です。ここを超えないと、この先の「歩く」にも進めません。

どこに足を出すかを、どう決めるか

足を出すと決めたとして、次の問題は「どこに出すか」です。ここには、倒立振子モデルから導かれるキャプチャーポイントという考え方があります。

言葉にすると単純で、「今の速度で倒れ続けたとして、そこに足を置けば止まれる地点」です。転がっているボールを止めたい位置に手を出すのと同じ感覚で、いまの位置と速度から計算します。

この点が支持基底面の外に出そうになったら踏み出しを開始し、その点を新しい着地目標にする。実装としてはこれだけです。あとは、足を上げてその位置に運び、下ろす動きを作ります。

MEMO

足を運ぶ軌道は、関節の角度を直接計算するのではなく、MuJoCo自身の運動学に解かせる方式にしました。前回、足首の関節の符号を勘で決めて痛い目を見ているので、幾何を手計算するより、シミュレータに聞いたほうが安全だという判断です。

ここまでは、教科書どおりに進みました。問題はこの先です。

つまずき1: 測定のしかたが間違っていた

今回いちばん大きな出来事です。しかも、前回の記事に載せた数値まで訂正することになりました

「回復した」と思っていたものが、回復していなかった

外乱に耐えられたかどうかは、押したあと一定時間たった時点で、まだ骨盤が一定の高さより上にあるか——で判定していました。その待機時間を、前回は0.8〜1.0秒に設定していました。

ところが、この時間が短すぎたのです。

13Nで前方に押した場合、0.8秒後の姿勢を見ると、傾きが一度戻りかけていて「回復した」ように見えます。ところがその後もゆっくり発散を続け、1.4〜1.5秒後に転倒していました。判定を打ち切った直後に、静かに倒れていたわけです。

踏み出しが絡むともっと極端でした。18Nで押したケースは、0.9秒の判定では「2歩で回復」に見えます。しかし2.0秒まで見ると、判定時間の外側で3歩目が発火し、その後に転倒していました。

見つけたきっかけは「本当にこんなに伸びるだろうか」

気づいたのは偶然ではありません。踏み出し制御を入れたら前方18N付近まで耐えるという結果が出て、改善幅が大きすぎることに違和感があったのです。念のため待機時間を長くして測り直したところ、次々と「実は転倒していた」ケースが出てきました。

待機時間を2.5秒に伸ばし(4秒・6秒まで伸ばしても結果が変わらないことを確認しました)、測定スクリプトを両方とも修正して、すべて測り直しました。

訂正後の数値

方向前回の記事に載せた値訂正後
前方(ピッチ方向)約13N12N
側方(ロール方向)約12N14N

ここで注目していただきたいのは、誤差の方向が一定ではなかったことです。前方は悪くなり、側方は逆によくなりました。もし「測定不備はいつも数値を良く見せる方向に働く」のなら、悪い数値だけを疑えば済みます。しかし実際はそうではありませんでした。

学び

都合の良い数値だけでなく、都合の悪い数値も測定不備を疑う必要がある、という教訓になりました。「思ったより良い結果が出たときに疑う」のは比較的やりやすいのですが、「思ったより悪い結果」は「まあこんなものか」と受け入れてしまいがちです。今回、側方が12Nと低めに出ていたのを、私はそのまま信じていました。

黄昏の戯れ
中の人

前回の記事、数字を直さないといけないね。訂正はかっこ悪いけど、間違ったまま置いておくほうがずっとかっこ悪い。

つまずき2: 足裏の力センサが、ずっと0を返していた

どちらの足にどれだけ体重が乗っているかは、踏み出す足を決めるうえで欠かせない情報です。ところがこのセンサ、どんな姿勢でも常に0を返していました。立っていても、片足を上げても、0です。

原因は2つ重なっていました。

  1. センサの検出範囲が、実際の接触点を含んでいなかった。足裏は6cm×3cmの箱で、地面との接触は箱の角に生じます。ところがセンサは半径1cmの球として足裏の中心付近に置かれていて、角で起きている接触を拾えていませんでした
  2. 範囲を足裏とぴったり同じ大きさにしても、まだ不安定だった。今度は接触点がセンサ範囲の境界のちょうど上に乗ってしまい、内側か外側かの判定が浮動小数点の誤差で揺れていました

解決策は、足裏よりひとまわり大きい専用の検出範囲を用意することでした。修正後は、両足で立った状態で左右とも12.75Nを返すようになりました。ロボットの総重量が25.5Nなので、ちょうど半分ずつです。数字が合ったときは、素直に嬉しかったです。

学び

センサが0を返し続けているとき、「壊れている」より先に「見ている場所が違う」を疑うべきでした。診断は結局、接触の生データを直接ダンプして突き合わせることでしか進みませんでした。実機を作る段になっても、足裏の圧力センサをどこに貼るかで同じ問題が起きるはずです。今のうちに踏んでおいてよかったと思っています。

つまずき3: 「重心を寄せてから足を上げる」が起きない

片足を予告なく持ち上げると、片足立ちへの移行が「ガクッ」となります。実測すると、それだけで6度前後の傾きが発生していました。せっかく踏み出しても、その動作自体が新しい外乱を生んでいる状態です。

人間は、足を上げる前に無意識に軸足側へ体重を移しています。同じことをやらせようとしました。

重みをかけても、体は動かなかった

最初は「支えている荷重に比例して、その脚の制御を強くする」という重み付けで実現しようとしました。しかしこれはまったく効きませんでした

理由は考えてみれば当然でした。今回の制御は、傾きの誤差に比例して補正を出す仕組みです。まっすぐ立っている状態では傾きの誤差がほぼゼロなので、補正量もゼロです。ゼロに何を掛けてもゼロのままで、体重は動きません。

実際に荷重を動かすには、誤差とは無関係にこちらから能動的に指令を出す必要がありました。両足首のロール関節に同じ向きのオフセットを与えると荷重配分が変わることを実測で確認し(0.05radのバイアスで左69%/右31%程度)、これを踏み出し前の準備動作として組み込みました。

それでも、傾きは減らなかった

ところが、1秒かけて左右の荷重を18%対82%まで寄せてから踏み出しても、足が浮いた瞬間からの傾きはほとんど減りませんでした。最大0.11rad程度まで発達します。

つまり、単足支持へ移るときの外乱は「事前の荷重配分」が原因ではなかったのです。

調べた結果、主因は持ち上げた足そのものの動きが生む反作用でした。股関節や膝を動かすと、その反動が体全体に返ってきます。左右方向の関節はまったく動かしていない(前後方向にまっすぐ踏み出す場合、計算上ぴったりゼロになります)にもかかわらず、左右方向に傾く。剛体がつながっていることによる干渉です。

注意

「関節Aを動かしていないのだから、A方向には影響が出ないはず」という直感は、多関節のロボットでは成り立ちません。ここは実測しないと分からない部分でした。

準備動作そのものは無駄にならず、次の対策の土台になりました。ただし当初の狙いは外れた、というのが正直なところです。

つまずき4: どちらの足を上げるか、決められない

足を持ち上げると体が傾く。それが避けられないなら、左右交互に踏み出せば打ち消し合うのではないかと考えました。

実測すると、期待どおりでした。左足を上げると-0.116rad、右足を上げると+0.116rad。きれいな鏡像です。交互に出せば、傾きは積み上がらないはずです。

ところが、交互だけでは転ぶ

実際にやってみると、今度は別の問題が出ました。大きく傾いているとき、機械的に交互で選ぶといま体重を支えているほうの足を持ち上げてしまうことがあります。当然、その瞬間に倒れます。

ではセンサを見て「軽いほうの足を上げる」に変えればよいか——これも駄目でした。着地した瞬間の衝撃で、荷重は一時的に定常の1.5〜2倍まで跳ね上がります。これを「危険な偏り」と誤認して同じ足を連続で選んでしまい、傾きが打ち消されずに積み上がって転倒しました(前方16Nのケース)。

落としどころ

最終的に、「基本は交互。ただし交互で選ばれた足が総荷重の85%以上を背負っている場合だけ、センサで上書きする」という二段構えにしました。

この閾値は、0.10〜0.30の範囲で振ってもほぼ同じ結果でした。つまり閾値の精密な調整には意味がなく、「例外的な場合だけ上書きする」という構造そのものが効いていた、ということです。

学び

センサを信じるか、決め打ちのルールを信じるか——という二択に見えたものが、実際には「普段はルール、例外だけセンサ」という組み合わせで解けました。どちらか一方に寄せようとしている間は、ずっと転んでいました。

結果: 前方は+29%、側方はゼロ

方向前回(両足固定)今回(踏み出しあり)変化
前方12N × 0.1s15.5N × 0.1s+29%
側方14N × 0.1s14N × 0.1s変化なし

前方は、一連の修正(センサの修正・荷重に応じた重み付け・踏み出し前の準備動作・足の選び方)によって明確に改善しました。

側方が1ミリも動かなかった理由

問題は側方です。踏み出し制御を積んでいるのに、踏み出さない制御とまったく同じ数値でした。

原因は分かっています。前方の踏み出しで使えた「左右交互で打ち消す」という手が、側方では使えないのです。

横に足を出すと、今度は前後方向に副作用が出ます。実際のデータでも、14.2Nの側方押しに対して1歩目で左右の傾きは収まるのに、前後の傾きが-0.16から-0.36へと発散していきます。前方のときは「反対の足を出す」という打ち消し手段がありましたが、側方の副作用に対するそれに相当する操作が見つかりませんでした

足を運ぶ速度を変える、準備動作の時間を変える——といった調整では、どれも改善しませんでした。

現時点の結論

側方は、踏み出しが「効かない軸」として残りました。次の段階への最大の宿題です。前後方向に小さな補正ステップを許すなど、打ち消し手段そのものを別の形で用意する必要がありそうです。

16Nだけ転ぶ。追いかけるのをやめた話

前方の耐性を測っていて、不可解な結果に出会いました。

押す強さ結果
15.5N回復する
16N転倒する
16.5N回復する

弱くても強くても耐えるのに、その間の16Nだけ転ぶ。単調ではないのです。

詳しく追いかけると、外乱の大きさそのものが原因ではありませんでした。着地の衝撃が来るタイミングと、次の踏み出し判定のタイミングが、たまたま噛み合わない——そのズレが生む、カオス的な境界でした。判定の閾値や待機時間、足の選び方の設定をいろいろ振っても、この1点は解消しませんでした。

ここで探索を打ち切りました。

個別の数値を追いかけて16Nだけを直したとしても、条件が少し変われば別のどこかに同じ現象が現れます。それより、この種の非単調な境界が実在すること自体を記録に残すほうが有益だと判断しました。

学び

実用上は「15.5Nまでは確実に耐える」という保守的な数値で運用するのが正しい扱い方です。15.5〜18Nは「耐えることもある」帯であって、性能として掲げてよい数値ではありません。カタログに書ける数字と、実際に信頼してよい数字は違う、ということでもあります。

黄昏の戯れ
中の人

直せない不具合を「直せませんでした」と書いて残す。これ、地味だけど後で自分を助けてくれるやつだよね。

次回予告

今回で、押されたときに一歩踏み出して耐える制御ができました。前方は12Nから15.5Nへ。側方は14Nのまま、宿題として残っています。

振り返ると、今回進んだ距離のうち大半は「測り方が間違っていた」「センサが見ていなかった」「効くと思った対策が効かなかった」という、後ろ向きの作業でした。実際に新しく作った制御そのものは、教科書どおりに動いています。難しいのは、いつもその周辺です。

次は、外乱に反応して踏み出すのではなく、自分から足を出し続ける——つまり歩容の生成に入ります。まずはその場足踏みから。そこで「15.5N/14Nという余裕は、歩いている最中にも本当にあるのか」という、当然の疑問にぶつかることになります。

次回予告

次回は、その場足踏みの実装に着手します。押されて反応するのではなく、自分の意思で足を出し続ける段階です。そして「立っているときに測った余裕は、歩いている最中にも通用するのか」を確かめます。結論から言うと、ここで一度大きく躓きます。次回もぜひ読みに来ていただけると嬉しいです。

タイトルとURLをコピーしました