二足歩行ロボットを作る(5)
歩けた。でも立っているときの強さは無かった
200歩で約6m。ただし歩きながら押すと、数字はまるで違いました
この記事に出てくる数値・結論は、すべてMuJoCo上のシミュレーションで測ったものです。実機による検証は経ていません。実際にロボットを組み立てて確かめた結果ではなく、計算機の中で起きたことである点をご承知おきください。
この連載は「専門家として正しさを保証する記事」ではなく、開発の実況記録です。うまくいかなかったことや、後から誤りだと分かったこともそのまま書いています。
前回のおさらいと、今回の結論
前回、横方向の弱さの原因がコードのバグ2つだと分かり、その場足踏みの消費率が96%から68%まで下がりました。ようやく「歩く」に進める土台ができた状態です。
今回、この機体はついに前へ進みました。
| 項目 | 結果 |
|---|---|
| 1歩の歩幅の上限 | 30mm |
| 200歩で進んだ距離 | 5.97m |
| 速度 | 1.59cm/s |
この機体には、まだ上体(胴・腕・頭)がありません。骨盤の箱で終わっています。ここに出てくる30mmは、その「脚だけの機体」の上限歩幅です。
上体を載せれば、この数字は落ちます。重心が上がるからです。実機を組めば、さらに変わります。先に書いておきます。
200歩・374秒かけて約6メートル。正直に書くと、実用的な意味での「歩行」にはまだ遠い速度です。それでも、前回まで「歩幅1cmで2歩以内に転倒」だった機体が、30mmの歩幅で200歩続くようになりました。
そして今回の本題は、その先にあります。歩きながら押してみたら、立っているときに測った強さは、ほとんど残っていませんでした。
歩けた!って喜んだ直後に、また現実を見せられるやつだ…。
「未解決」が、測り直したら成立していた
今回いちばん拍子抜けしたのが、これです。
前々回、前進歩行は「216通り試して0通り」という完敗でした。原因もムーンウォーク現象として特定していました。今回はその対策を実装するつもりで着手したのですが、まず現状を測り直したところ、すでに歩けていました。
前回までのバグ修正が、前進歩行の問題も一緒に解決していたのです。「未解決」として引き継がれた前提が、いつの間にか古くなっていました。
着手前にベースラインを測り直したから気づけました。もし引き継ぎメモを信じて対策の実装から始めていたら、すでに直っている問題を直そうとして、その効果を評価できずに混乱していたはずです。「今どうなっているか」を測ることは、何かを変える前に必ずやるべき手順でした。
ついでに、古い記録が原因を取り違えていたことも分かりました。当時「3つの修正が効いた」と書かれていたものは、実際にはそれぞれ別の役割を果たしていて、記録の説明とは対応していませんでした。動くようになった直後に書いた説明は、たいてい雑になります。
歩幅の上限を決めていたのは、存在しない自由度だった
歩けるようになったので、次は「どこまで歩幅を伸ばせるか」です。伸ばしていくと、あるところで転倒します。何が限界を決めているのかを調べました。
転倒の直接の原因はヨー方向——体が水平にねじれる方向——の発散でした。歩幅を大きくするほど、1歩ごとに体がわずかにねじれ、それが積み上がって最後に転びます。
ここで困ったことに気づきます。
この機体には、ヨー軸のアクチュエータがありません。股関節はピッチ(前後)とロール(左右)の2軸で、ねじれを直接制御する関節が存在しないのです。つまり「ねじれが発散して転ぶ」と分かっても、制御側から打てる手が無いということになります。
遊脚の姿勢を補償する仕組みを追加して歩幅は伸ばせましたが、根本的にはこの制約が残ります。これは制御の問題ではなく機構設計への申し送りになりました。「次に機体を設計するときは、ヨー軸をどうするか決めておく必要がある」という形です。
原因が分かっても手が出せない、というのは初めての経験でした。バグなら直せます。パラメータなら振れます。関節が無い、というのはそのどちらでもありません。
1 ULPで、結果が反転した
歩幅の限界を調べている最中に、理解に苦しむ現象に出会いました。
同じ歩幅0.023mのはずなのに、書き方を変えると結果が変わるのです。
| 歩幅の書き方 | 結果 |
|---|---|
0.023(そのまま書く) | 32歩 完走 |
0.020 + 0.001 × 3(計算で作る) | 30歩で転倒 |
数学的にはどちらも0.023です。しかしコンピュータの中では、この2つはまったく同じ数値ではありません。
小数は2進数で表現されるため、0.001のような値はぴったり表せません。足し算を繰り返すと、ごくわずかな誤差が乗ります。その差は1 ULP——浮動小数点数で表現できる最小の刻み、3.5×10⁻¹⁸メートルでした。
原子1個の直径がおよそ10⁻¹⁰メートルですから、その1億分の1ほどの差です。この差が、転ぶか歩き続けるかを分けました。
この機体の転倒境界がカオス的であることの、これ以上ない証拠になりました。第2回で「16Nだけ転ぶ」という非単調な境界に出会って探索を打ち切りましたが、あれと同じ性質のものが、ここでは極端な形で現れたわけです。
実務的な教訓もあります。掃引スクリプトが値を足し算で作っていたのが原因なので、そこは修正しました。ただしもっと重要なのは、境界のちょうど際の数値を「性能」として引用してはいけないということです。
32mmと30mm、どちらを性能と呼ぶか
その教訓が、そのまま次の判断につながりました。
歩幅の上限を測ると、条件によって32mmと30mmという2つの数字が出ます。どちらも嘘ではありません。違うのは採用の基準です。
| 基準 | 上限歩幅 |
|---|---|
| 1回だけ実行して200歩完走した | 32mm |
| 初期位置を±0.5/±1/±2mmずらした7条件すべてで完走した | 30mm |
32mmは、1回走らせれば完走します。しかし初期の立ち位置をコンマ数ミリずらすと、7条件のうち3条件しか通りません。実機に置き換えれば、置く位置が1mm違えば半分以上失敗するということです。
そこで「7条件すべてで完走する」を採用基準とし、公称値を30mmとしました。
実は、この件では並行して作業していた2つの記録で数字が食い違い、一方が22mm、もう一方が32mmと報告していました。意見の相違ではなく、採用基準の違いでした。基準を明示しないまま数字だけをやり取りすると、こういう食い違いが起きます。
結果として「単発実行で完走した値を上限として引用してはいけない」ということが、実例つきで証明された形になりました。作業の重複という事故から得た、意図しない収穫です。
歩けたので、歩きながら押してみた
ここからが今回の本題です。
これまで測ってきた「押されても耐えられる限界」は、すべてじっと立っている状態で測ったものでした。側方は14.0N。第3回で「その場足踏みだけで横の余裕を97%使う」と分かったときも、比較の基準はこの立位で14.0Nに押されたときの傾きでした。
※前方については、制御の設定しだいで限界が大きく動くため、ここでは1つの数字として挙げません。
では、実際に歩いている最中に押したら、どうなるのか。
ようやく前進歩行ができるようになったので、初めてこれを測れるようになりました。あわせて、後方(背中側)も初めて測っています。これまで前方と側方しか測っていなかったのです。
立っているときの強さは、歩行中には無かった
結果です。同じ機体を、3つの状態で4方向から押しました。
| 押す方向 | 立っている | その場足踏み | 前進歩行 |
|---|---|---|---|
| 前方 | 16.00N | 12.75N | 12.25N |
| 後方 | 6.75N | 3.75N | 5.50N |
| 側方(+) | 14.00N | 6.75N | 5.75N |
| 側方(-) | 14.00N | 6.75N | 6.25N |
| 最も弱い方向 | 6.75N | 3.75N | 5.50N |
側方を見てください。立っているときは14.00N。歩いている最中は5.75N。4割ほどしか残っていません。
これまで「側方14N」を性能として扱ってきましたが、その数字は歩いていないときの数字でした。歩き始めた瞬間に、6N前後まで落ちます。
最も弱い方向で見ると、歩行中は5.50N。ロボットの総重量は25.5Nですから、体重の約22%の力で押されると転ぶということになります。体重60kgの人でいえば、13kgぶんの力で押されたら倒れる計算です。
これは「性能が落ちた」のではありません。もともとこれが実力で、今まで測っていた数字が実力ではなかったということです。
第3回で「その場足踏みだけで側方の余裕の97%を使う」と書いたとき、比較の分母に立位で14.0Nに押されたときの傾きを使っていました。立って押されたときの数字を、歩いている最中の話の基準にしていたわけです。今にして思えば、あの比較そのものが楽観的すぎました。
弱点が、横から後ろへ移った
もうひとつ、表を見ると分かることがあります。
第2回からずっと、この機体の弱点は横方向でした。踏み出しても改善せず、足踏みで96%を消費し、前回はバグ2つの原因になった。ところが歩行中の数字を見ると、最も弱いのは後方の5.50Nです。
横方向は5.75〜6.25Nなので、わずかですが後方のほうが低い。ボトルネックが移りました。
そして後方については、これまで一度も測っていませんでした。前方と側方だけを見て「この機体は横が弱い」と言い続けていたわけです。測っていない方向は、弱点として認識されません。
4方向すべてを測って初めて、最悪方向がどこかを言えるようになりました。それまでの「横が弱い」という理解は、測った範囲の中で一番弱かったものにすぎません。何を測っていないかを意識するのは、測ったものを解釈するのと同じくらい重要でした。
後方の弱さは、制御ではなく形で説明がついた
では、なぜ後方だけ弱いのか。ここは気持ちよく説明がつきました。
この機体の足は、足首の中心より25mm前方に取り付けられています。そのため、足裏が地面と接している範囲——支えられる領域は、足首を基準にすると前に85mm、後ろに35mmと、前後で非対称になっています。
後ろに倒れそうになったとき踏ん張れる距離が、前に倒れそうなときの半分以下しかない、ということです。
この幾何から素朴に予想すると、後方の限界は前方の 35 ÷ 85 = 41% になるはずです。実際に測った比率はどうか。
| 比率 | |
|---|---|
| 設計図から計算した幾何比(35mm ÷ 85mm) | 41% |
| 実測した力の比(6.75N ÷ 16.00N) | 42% |
41%と42%。設計図の寸法から出した数字と、シミュレータで押して測った数字が、ほぼ一致しました。
後方の弱さは制御の出来不出来ではなく、機体の形そのもので決まっている、ということです。制御をどれだけ改善しても、足の取り付け位置を変えない限りこの比率は動きません。
逆に言えば、足の形を変えれば直せるかもしれない——という見通しが立ちました。次回はまさにそれを試すことになります。
ここまでバグと格闘し続けてきたので、設計図の数字と実測がここまできれいに合うのは久しぶりに気分の良い瞬間でした。
次回予告
今回の成果をまとめます。
- 前進歩行が成立した。歩幅30mm、200歩で5.97m、1.59cm/s
- 歩幅の上限を決めているのはヨー軸。ただしこの機体にその関節は無い(機構設計への申し送り)
- 1 ULP(3.5×10⁻¹⁸m)で結果が反転。境界の際の数値を性能として引用してはいけない
- 立位の強さは歩行中には無かった。側方14.00N → 5.75N
- 弱点が横から後方へ移り、その弱さは幾何で説明がついた(41% vs 42%)
「歩けました」と書ける、シリーズで初めての回でした。同時に、これまで性能として掲げてきた数字が、歩き出した途端に半分以下になることも分かった回です。
