はじめに
自作の小型二足歩行ヒューマノイドロボット「スピロ」を、深層強化学習で歩かせた話です。
昨年はパラメータから足先軌道を生成する方式で歩かせていましたが、今年は歩容そのものを強化学習で獲得させ、学習済みポリシーをマイコン単体で動かすところまで持っていきました。この記事では、Isaac Labでの学習からAtomS3Rへのデプロイ、そして一番苦労したsim2realギャップの詰め方までをまとめます。
この記事でやったこと
- 深層強化学習(PPO)で歩容を獲得。学習は Isaac Lab、sim2sim検証は MuJoCo
- 学習済みポリシーを M5Stack AtomS3R(ESP32-S3)に直接実装し、PCなしで歩行
- 前後左右移動・旋回、そしてプッシュリカバリーまで到達
- 一番効いたのは学習アルゴリズムよりもサーボのシステム同定とシミュレータと実機の合わせ込み
対象読者
- 自作ロボットで強化学習・sim2realに挑もうとしている方
- マイコン単体でRLポリシーを動かすことに興味がある方
1. 去年の歩行と、今年の目標
自作の小型二足歩行ヒューマノイドロボット 「スピロ」 を開発しています。機体の詳細は前回の記事にまとめました。
構成をあらためて整理すると、
- 20軸(右脚6軸 / 左脚6軸 / 右腕4軸 / 左腕4軸、胴体は非可動)
- アクチュエータは全軸 ROBOTIS DYNAMIXEL XL330-M288-T
- フレームは3DプリントのABS部品
- 電源はLiFePO4 2セル、または外部DC電源
- 自作ハブ基板でUART ↔ DYNAMIXEL TTL通信を中継
昨年の歩行実装
昨年時点の歩行は、パラメトリックな足先軌道生成でした。歩行周期・足上げ高さ・ストライド長・左右脚の位相差といった歩行パラメータを与えると、プログラムが足先のXYZ軌跡を動的に計算し、それを逆運動学(IK)で各関節角に変換して出力する方式です。姿勢列を記録して再生していたわけではなく、軌道はオンラインで生成していました。
なお、「起き上がり」や「着座」といった単発のモーションについては、Unityで自作したモーションエディタでキーフレームを打つ方式を使っています。周期運動である歩行だけがパラメトリック生成という切り分けになります。
IMUで機体の傾きを計測して姿勢を補正する制御も入れていましたが、歩容そのものは人間が決めたパラメータで決まっている状態です。
この方式だと下記課題がありました。
- ちょっとした不整地や床の材質変に対するロバスト性不足
- 横から押されたら、そのまま倒れる(一応IMU補正は入れているが調整不足)
- 歩容を変えたければ、パラメータの組み合わせを探し直す
これらは対策としてモデルベース制御の実装などが考えられます。
今年のメイカーフェアに向けた目標
今年は 「AIに歩かせる」 ことを目標に開発を進めました。人間が歩き方を教えるのではなく、ロボット自身に歩き方を見つけさせて歩けたら楽しいはず!(それまで茨の道…)
2. どんなやり方があるのか
まず二足歩行制御の分類を整理しました。二足歩行の制御の代表的なアプローチをざっくり並べると下記のようになります。
| アプローチ | 概要 | 特徴 |
|---|---|---|
| パラメトリック歩容生成(昨年の方式) | 歩行パラメータから足先軌道を生成し、IKで関節角に変換 | 実装が単純で意図通りに動く。パラメータの再調整が前提で、環境変化・外乱に弱い |
| ZMP規範 / プレビュー制御 | 重心軌道をZMP安定条件から生成 | 理論的に明快で実績豊富。モデル誤差に弱く、外乱応答の設計が大変 |
| MPC + WBC | 数ステップ先を最適化しながら全身制御 | 高性能だが実装量が多く、計算コストも高い。小型MCUには載せづらい |
| 模倣学習 | モーションキャプチャや既存軌道を学習 | 自然な動きになる。教師データの用意が前提 |
| 深層強化学習(RL) | シミュレータ内の試行錯誤でポリシーを獲得 | 設計対象が報酬関数に移る。sim-to-realギャップが最大の課題 |
今回使うポリシー構成は数層のMLPの行列積だけなので、マイコンでも十分に動くと考えました。今回の構成での 「学習は重いが推論は軽い」というRLの性質が、小型ロボットと非常に相性が良いはず。
「外乱に耐える歩容が欲しい」「推論が小さなMLPで済み、マイコンに載せられる」という2点からも、深層強化学習を選んでいます。
3. 強化学習で歩行を学習させる仕組み
深層強化学習というとなんだか難しく聞こえるかもしれないですが、やっていること自体は非常にシンプルです。
3.1 一言でいうと「試行錯誤」と「採点」
強化学習は、犬に芸を教えるやり方によく似ています。
例えば犬に「お手」の芸を教えるとき、飼い主は「右前足を15度上げて、次に…」といった動かし方を教えないし逆に教えるのは難しいと思います。基本的に、飼い主は犬がうまく芸ができたらおやつをあげる。犬はいろいろ試して、おやつがもらえる動きを自分で見つけます。
ロボットも同じです。
- ロボットがとりあえず動いてみる(最初はデタラメで、即座に転ぶ)
- その結果に点数をつける(前に進めた→加点、転んだ→減点)
- 点数が高くなる方向にニューラルネットワークを少しだけ調整する
- 1に戻る
これを何万回と繰り返します。人間がやることは「動かし方を書く」ことではなく、「採点基準を決める」ことに変わります。 ここが従来の歩容設計との決定的な違いです。
コラム:レバーを押すラット
この「試して、点数がつく」という構造は、動物の学習実験でおなじみのものです。
1930年代、B.F.スキナーは、ラットがレバーを押すと餌が出る装置を作りました(スキナー箱)。この装置を用いて、レバーを押す行動の頻度がその結果によってどのように変化するかを調べました。
押す → 餌が出る → 押す頻度が上がる。この流れが、上に書いた1〜4の手順とほぼ同じ形をしています。「強化学習」の強化(reinforcement)という言葉自体も、こうした動物の行動研究で使われてきたものです。
3.2 ロボットは何を見て、何を出しているのか
ロボットの中身、ロボットを動かす脳みそに当たる部分はめちゃくちゃ雑に言うと「入力を受け取って出力を返す関数」といえます。この関数を ポリシー(Policy) と呼びます。中身は数層のニューラルネットワーク(MLP)です。
[見ているもの] [出しているもの]
・今の関節の角度 → ポリシー → ・次に目指す関節の角度
・体の傾き、傾きの速さ (MLP) (20軸ぶんの数字)
・さっき自分が出した指令
・「前に進め」などの指令
見ているもの(観測 / Observation)
ポリシーに入れる入力データです。
| 観測 | どこから取るか |
|---|---|
| 各関節の角度 | DYNAMIXELから読み取る |
| 体の傾き・角速度 | IMU(AtomS3R内蔵) |
| 前回自分が出した指令 | 自分で覚えておく |
| 速度指令(前に/横に/回れ) | コントローラや自動生成 |
出しているもの(行動 / Action)
各関節の目標角度や足先の指示値になります。「このモータをこの角度に持っていけ」という指示を、1秒間に数十回出し続けます。
補足:なぜトルクではなく角度を出力するのか
ポリシーに直接トルク(力)の指示値を出させる方式もありますが、探索が難しく学習が不安定になりがちと言われています。また、モータがトルク指令通りのトルクを発揮できることがハードウェア側の条件になります。脚式ロボットRLでは、直接トルクを出力する方法よりも、ポリシーが目標関節角を出し、低レベルのPD制御に追従させる構成が広く使われています。DYNAMIXELは内部に位置制御ループを持っているので、実機構成とも素直に対応します。
3.3 なぜシミュレータの中で学習するのか
前述で「何万回も繰り返す」と言いましたが、これを実機でやったら、3Dプリント部品もサーボも一瞬で寿命を迎えます。そこでシミュレータを使います。
シミュレータには3つの利点があります。
- 壊れない:何万回転んでもコストはゼロ
- 並列化できる:GPU上で数千体のロボットを同時に歩かせられる
- 時間を圧縮できる:現実の1秒をPC内で0.1秒など加速して扱える、現実の数年ぶんの経験を数時間で積ませられる
一方で、シミュレータの中の物理は現実そのものではありません。この差(sim-to-realギャップ)をどう埋めるかが難しい部分になります。
3.4 報酬設計は「採点基準を書く」仕事
RLで人間が設計するのは報酬関数、つまり採点基準です。実際には数十項目の点数を足し合わせます。
やって欲しいこと(プラス点)
- 指令された速度で進めたか
- 体の高さを保てているか
やって欲しくないこと(マイナス点)
- 転倒しないか
- モータに無理な力がかかっていないか
- 指令がガタガタ暴れていないか
- 関節が可動限界にぶつかっていないか
- 体が傾いたり上下に揺れたりしていないか
歩き方の形を整えるための点数
- 左右の足を交互に接地できているか(周期的な関数で誘導)
- 足を十分に持ち上げているか(すり足の防止)
- 接地した足が滑っていないか
3.5 報酬設計でよくある失敗
採点基準を書くのは、実はかなり難しい作業です。ロボットは「人間の意図」ではなく「書いた点数」を最大化しに来ます。
- マイナス点を厳しくしすぎた場合:「じっと立っていれば減点されない」という結論に達し、ロボットは直立したまま一歩も動かなくなります
- マイナス点が緩すぎた場合:シミュレータの物理の穴を突いた、超高周波でブルブル震える謎の歩容が生まれます。シミュレータ上では高速で前進しますが、実機に持っていくと即座に発散します
どちらも実際に何度も遭遇しました。この綱引きの調整が時間のかかる部分の一つになります。
3.6 アルゴリズムはPPO
学習アルゴリズムには PPO(Proximal Policy Optimization) を、rsl_rl というライブラリで使っています。ロコモーションRLではおそらく事実上の標準です。
PPOの学習方針を一言でいうと、ポリシーを一度に大きく変えすぎないことです。うまくいった経験に引っ張られて極端にポリシーを書き換えると、それまで積み上げた能力を丸ごと失うことがあります。PPOは更新幅に制限をかけて、少しずつ改善していくような動きが特徴です。
4. 学習環境の選択:Genesis / MuJoCo / Isaac Lab
強化学習のために3つの物理シミュレータを検討しました。以下は私見や私が知る限りの内容でまとめた特徴です。
Genesis
- Pythonネイティブで導入が軽く、コードが読みやすい
- 学習が速く、試行錯誤のサイクルを回しやすい
- PD制御アクチュエータのパラメータ(
kp/kv/armature/frictionloss/force_range)を細かく設定できる - 一方でアクチュエータの忠実度は、今回の用途では実機サーボの遅延や非線形な応答まで再現しようとすると、標準的なPDモデルだけでは不足を感じた
- ドメインランダム化や遅延の注入といったsim2real向けの仕掛けは、自前で実装することになる(今回使用していたバージョンでの話)
MuJoCo
- 接触計算の質が高く、物理エンジンとしての信頼性がある
- sim2sim検証のリファレンスとして使いやすい
- 大規模並列学習には向かない(MJXを使えば別)
Isaac Lab
- GPU並列で数千環境を同時に回せる。学習スループットが桁違い
- ドメインランダム化・地形生成などロコモーションRL向けの機能が揃っている。何を・いつ・どの範囲でランダム化するかを宣言的に書け、数千環境へ一貫して適用される
- アクチュエータモデルが段階的に用意されている。素のPD制御、トルク上限やモータ特性を織り込んだもの、ニューラルネットで応答そのものを学習させるものから選べる
- 環境構築のハードルとVRAM要求が高い
環境については、Isaac Labを使いWindows Nativeでヘッドレス学習、グラフィカル推論を行っています。また実機デプロイ前の確認としてMuJoCoでSim2Sim推論も環境構築し行っています。
5. 全体の流れ:学習 → sim2sim → sim2real
一気に実機に持っていくと、うまくいった場合も失敗した場合も切り分けが分かりづらくなるため下記段階を踏んでいます。
[1] 学習 (Isaac Lab)
↓ 指令速度に追従して歩けるようになるまで
[2] sim2sim (MuJoCo)
↓ 別の物理エンジンでも歩けるか = 物理エンジン依存の挙動差を確認
[3] ポリシーのエクスポート → Cヘッダ化
↓
[4] sim2real (AtomS3R + 実機)
↓ 吊り下げ・支持 → 自立
sim2simを挟む意味は大きいです。ここで歩けないポリシーは、実機でも歩けない可能性が高いです。実機転倒など壊すリスクなしにギャップを検出できる可能性があります。
6. 実機をどう動かすか:AtomS3R上でのポリシー実行
ここが結構特徴的なところで、PCを介さず、ポリシーをマイコンに直接載せています。
6.1 なぜマイコン単体で動かすのか
ポリシーの実行(推論)は基本的に学習したPCでそのまま行うのが手っ取り早いです。そのため、PCとロボットをUSBケーブルなどでつなぎ、推論はPC、実際のロボットの駆動と観測データ取得は実機ロボットという構成で推論を行うのは割とポピュラーなやり方だと思います。今回のメイカーフェアで展示した別の四脚ロボットはこちらの方式で有線で動かしていました。
一方で二足歩行ロボットは多脚ロボットより転倒リスクが高いです。そのため、できるだけ配線など引っ掛かることで転倒要因になるものは繋ぎたくない気持ちもあります。
ひとつの解決手段としては無線でやり取りすることがあげられますが、ポリシーへの入出力は制御フィードバックループに相当します。 そのためPCとの無線通信が挟まると、その分だけ遅延やジッタが増えます。これらは露骨に不安定な動きに直結します。
そこで今回は、ポリシーのMLPまでマイコンのソフトとして実装し完全スタンドアロンで推論歩行させることを目指しました。
6.2 実装方法
学習したポリシー(MLP)は、NNの重みをCヘッダファイルの配列に変換して AtomS3R に載せています。
数層のMLPであれば推論は行列積の連続なので、外部の推論ランタイムを持ち込むより直接書いたほうが軽量実装可能と考え今回の方法を採っています。推論自体は50Hzで回しています。
6.3 IMUと制御ループ
AtomS3Rは BMI270(6軸IMU)+ BMM150(地磁気) を内蔵しています。ポリシーの観測に必要な角速度と重力方向は、この内蔵IMUから取得しています。I2Cなどでセンサ基板を別に引き回す必要がないのが大変ありがたいです。
制御ループはおおよそこの流れです。
[1] IMU読み取り(角速度・姿勢)
[2] DYNAMIXELから現在関節角を読み取り
[3] 観測ベクトルを構築
[4] MLP推論
[5] アクション → 目標関節角に変換
[6] DYNAMIXELへ送信
7. 失敗と改善
長くなりましたがここからが本題です。実機へポリシーをデプロイするところまではできましたが、それと転倒せずうまく歩けることは別の話で、シミュレータ上でうまく歩けたからと言って実機に適用して同じように一発で歩きだすことは、新規設計やオリジナルのロボットではまずありえないと思います。「シミュレータでは完璧に歩くのに、実機では転ぶ」 をどう埋めたか、ここからはXで上げたポストに沿って解説します。
まずは学習したポリシーをそのまま実機に載せました。
7.1 失敗1:シミュレータのアクチュエータが理想的すぎた
最初の実機テストは惨敗でした。シミュレータ上の関節は指令にほぼ瞬時に追従しますが、実機のサーボには、
- 減速機の摩擦(静止摩擦・粘性摩擦)
- バックラッシ・デッドバンド
- 内部制御ループと通信による遅れ
などがあります。最初はポリシーはこれらをある程度の合わせこみと推察での設定値で学習していたので、おそらく実機の応答遅れを「外乱」と誤認して発振しました。
発振の原因はアクチュエータのモデル化だと判断し、まずサーボ単体の特性を測ることにしました。
改善:アクチュエータのシステム同定
実機の関節に既知の指令(ステップ応答など)を入れ、応答を記録します。同じ指令をシミュレータに与え、応答が一致するようにパラメータを最適化します。
同定するパラメータはシミュレータ内アクチュエータ設定値のkp / kv / armature / frictionloss 等です。
同定は無負荷だけではなく、実際の脚の慣性がかかった状態でも行いました。単軸を空中で振って合わせたパラメータは、機体に組み込むと動作領域の違いで合わない印象です。
同定したパラメータでシミュレータを合わせ直して再学習させると、実機が自分で立てるようになりました。
7.2 失敗2:質量・慣性パラメータのズレ
CADから出したURDFの慣性テンソルは、ケーブル・基板・バッテリの位置で簡単にズレます。スピロは軽量な機体なので、ハーネスや基板・ねじの質量の比率が相対的に大きく、影響が出やすい構成でした。特に重心高さのズレは歩容に直撃します。
改善:ドメインランダム化
同定で完全に一致させるのは不可能なので、「多少ズレていても歩けるポリシー」を作る方針としました。
| ランダム化対象 | 範囲 |
|---|---|
| リンク質量 | ±10〜20% |
| 重心位置 | ±10〜20% |
| 床面摩擦係数 | ±10% |
| サーボゲイン | ±10% |
| 外力プッシュ | ランダムなタイミングと大きさ |
範囲を広げすぎると保守的で鈍い歩容になり、狭すぎると実機が幅に入らないのでポリシーが実機環境を経験できません。
なお、外力プッシュのランダム化がそのままプッシュリカバリーの元になっていると考えられます。
7.3 失敗3:遅延の見積もり不足
観測を取得してから、ポリシーが推論し、シリアル経由でサーボに届き、サーボ内部の制御ループが応答するまでには、実時間の遅れが積み上がります。この遅延を学習時にモデル化していないと、ポリシーは「観測した瞬間の状態」に対して制御していると信じたまま動くため、発振しやすくなります。
7.4 うまくいった手順のまとめ
sim-to-realギャップの詰め方は、この順番が効率的でした。
- アクチュエータを合わせる(システム同定)← 効果が最も大きい
- 遅延を合わせる(推論時間・通信時間を実測して反映)
- 残差をドメインランダム化で吸収する
- sim2simで検証してから実機へ
3から始めると、いくらランダム化の幅を広げても実機で歩かず、原因特定も難易度が跳ね上がります。
8. ここまで来た
7章の手順を回した結果、実機がやっと歩き始めました。
まだぎこちなく、歩幅も出ていません。ここからドメインランダム化の範囲と報酬の重みなどを詰めました。
現在、実機で以下が実現できています。
- 前後移動:速度指令に追従して前進・後進
- 左右移動:横歩き(昨年のパラメトリック実装では実装中のままだった動作)
- その場旋回:ヨー方向の角速度指令に追従
- プッシュリカバリー:横から押されても踏み出して姿勢を回復する
昨年からの一番の変化は、「押されたときの動き」を誰も書いていないことです。学習中にランダムな外力を受け続けた結果、ポリシーが自分で足を踏み出す反応を獲得しました。
昨年までは、歩行周期や足上げ高さなど歩行パラメータを自分で調整して歩容を作っていました。それが今回は歩容を設計するのではなく、環境と報酬を設計するという作業に変わっています。ここが従来手法との決定的な違いだと感じています。
直近の状態がこちらです。
これからやりたいこと
- 不整地(斜面)への対応
- 歩行速度域の拡大
- 腕の動きの統合
- きれいな動き
9. Maker Faire Tokyo 2026 に出展しました
ロボット・AIカテゴリでの出展で、当日たくさんの方に実機を見たり触ったりしていただきました。ほかにも四脚ロボットをもっていっていたのであまりスピロをメインでお見せしたりお話しする時間が取れなかったですが、実機の動きを見ていただき、議論もたくさんできて大変いい機会になりました。お越しいただいた皆さん、ありがとうございました!
おわりに
パラメトリックな軌道生成からRLに移行しても、泥臭い作業がなくなるわけではないということは改めて痛感しています。作業の中身が変わりますが、学習結果がうまくいくとも限らないため時間が無駄になる部分も多く、もっと効率的に進める方法を模索しています。
ただ、8MBのPSRAMを積んだ小さなマイコンの上で、学習済みのポリシーがスタンドアロンで動作し実際に歩行できているという状態は作っていて素直に面白いし、よくよく考えると自分でもこの規模で実現できたことに驚いています。
同じように自作ロボットでsim2realに挑む方の参考になれば幸いです。質問やツッコミはコメントでお願いします。
