歩行方策を自分で学習する#
第13章の四脚を歩かせている方策は、配布済みのものをそのまま使えば 学習しなくても動きます。ここではそれを自分で学習し直す手順をまとめます。 報酬を変えたい、速度の上限を上げてみたい、別の歩容を出したい——そういう ときの入口です。
学習の入口は 2 つあります。NVIDIA GPU があれば mjlab 版、無ければ CPU 版です。CPU 版は同じタスクを素の MuJoCo で回すもので、6 コアのノート PC で 2048 環境 × 2300 iteration が約 69 分です(環境は並列に動かす 1 台ぶんのシミュレーション、iteration は方策を 1 回更新するまでの区切り)。GPU が無くても、Google Colab (無料枠の T4)で mjlab 版を通す道もあります。どれで学習してもチェックポイント(途中で保存した学習結果(重み))の 形式は同じで、同じ手順で実機用のヘッダに書き出せます。
学習コードの構成#
学習は unitree_rl_mjlab
(mjlab + rsl_rl の PPO 学習基盤)の上で
行います。docs/os-on-arduino/code/13_quadruped/rl/ はその上流に被せる overlay で、
それ自体は単体で動くプログラムではありません。
ファイル |
中身 |
|---|---|
|
機体定義(アクチュエータ、初期姿勢、 |
|
観測・コマンド・ドメインランダマイゼーション(摩擦や質量などを学習中にランダムに変えること。学習のコード) |
|
報酬項(速度追従、歩容、姿勢、エネルギー等) |
|
PPO のハイパーパラメータとネットワーク構成 [96, 64] |
|
ERFI(extended random force injection。トルク外乱)を足した学習ランナー |
|
環境構築・学習・再生・動画書き出し |
|
同じタスクを mjlab なしで学習する CPU 版(下の「GPU なしで学習する(CPU 版)」) |
setup.sh が上流を .upstream/unitree_rl_mjlab に clone し、rl/ を
src/tasks/velocity/config/arduino_quad としてシンボリックリンクで
置きます。上流は src/tasks/ 配下を自動 import するので、これだけで
次の 4 タスクが登録されます。
タスク ID |
用途 |
|---|---|
|
平地・素の velocity レシピ(立ち上げ確認用) |
|
平地 + 歩容シェーピング(本命。トロット歩行はこれ) |
|
Walk と同じだが初期状態を崩す(実機前の頑健化) |
|
転倒姿勢から立ち上がる |
Google Colab で学習する(GPU が無い人向け)#
ブラウザだけで、環境構築から Arduino 用ヘッダの書き出しまで通せる ノートブックを用意しました。
ノートブックの流れ:
GPU の確認(ランタイム → ランタイムのタイプを変更 → T4 GPU)
コードを取ってきて、学習環境(mjlab + MuJoCo Warp + rsl_rl)を入れる
配布済みの学習済み方策を再生して動画で見る — ここまでで 「シミュレータ・方策・エクスポート」が揃って動いていることを確認できます
割り当てられた GPU で 30 iteration 回して学習速度を実測し、 所要時間を見積もる
学習する(チェックポイントは Google Drive に保存)
セッションが切れたら続きから再開する
学習した方策を動画で確認して、
arduino_quad_policy.hに書き出す
注釈
Colab の無料枠はセッションが数時間で切れます。学習ログを Google Drive に
逃がしておけば、--agent.resume True で何度でも続きから再開できます。
ノートブックの 6 章がその設定です。
無料枠の T4 でどれくらいかかるか#
2026-08-31 に Colab の無料枠(Tesla T4 15 GB、Python 3.13)で、環境構築から
.h の書き出しまで実際に通しました。そのときの実測です。
環境構築( |
約 1 分 |
学習(2048 環境) |
1.42 秒/iteration、34,900 steps/s |
書籍と同じ 4,500 iteration に必要な時間 |
約 1.8 時間 |
方策の再生(300 ステップの動画) |
初回 5〜6 分(GPU カーネルの生成を含む)、2 回目以降 3〜4 分 |
|
約 1 分 |
参考までに、同じ設定を RTX 4090 で回すと 0.77 秒/iteration・63,700 steps/s でした。T4 は 4090 の半分強の速度で、無料枠でも書籍と同じ規模の学習が 現実的な時間で終わります。
何 iteration で歩くようになるか#
ノートブック既定の設定(ArduinoQuad-Walk、2048 環境)で 1500 iteration
回し、100 iteration ごとのチェックポイントを指令 0.09 m/s で 6 秒ずつ
再生した実測です(RTX 4090、1 シード。シードは乱数の初期値)。
iteration |
実測 前進 [m/s] |
iteration |
実測 前進 [m/s] |
|---|---|---|---|
0 |
−0.000 |
800 |
0.086 |
100 |
−0.219 |
900 |
0.071 |
200 |
−0.194 |
1000 |
0.072 |
300 |
0.005 |
1100 |
0.096 |
400 |
0.014 |
1200 |
0.072 |
500 |
0.046 |
1300 |
0.086 |
600 |
0.046 |
1400 |
0.101 |
700 |
0.058 |
1499 |
0.089 |
100〜200 iteration では後ろに進みます。 前進報酬を拾うより先に 「転ばない」を覚えるためで、失敗ではありません。前進に転じるのが 300 付近、 指令の速度に届くのが 800 前後、そこから先は 0.07〜0.10 の範囲で揺れながら 追従します。各点は 1 エピソード(ロボットを置いてから倒れるか時間切れになるまでの 1 回)の測定なので、隣り合う点の ±0.02 m/s は 誤差の範囲です。
注釈
これは既定の設定で学習した別の方策であって、配布済み方策 (home 高さ 0.11 m、歩容周期 0.32 s、3999 iteration、指令 0.12 m/s で 0.120 m/s)の再現では ありません。エクスポートされるヘッダには学習時の home 角が書き込まれるので、 実機側の整合はそのまま取れます。
手元の GPU で学習する#
推奨環境は Ubuntu です。Windows でも WSL(Windows の上で Linux を動かす仕組み)を 入れれば動くはずですが、まだ確かめていません。どちらも用意できなければ、下の GPU なしで学習する(CPU 版) を使ってください。
cd 13_quadruped # docs/os-on-arduino/code から
./rl/scripts/setup.sh # 上流を clone して overlay を置き、依存を入れる
source rl/scripts/env.sh # 機体の MJCF の場所を教える
./rl/scripts/train.sh ArduinoQuad-Walk --env.scene.num-envs=4096
setup.sh --no-install にすると、clone と配置だけ行って依存の導入を飛ばせます。
版の固定について#
setup.sh は依存を版で固定して入れます。上流 (unitree_rl_mjlab) の
setup.py が指すままでは、この機体の設定が読み込めません。
なぜ固定するか |
||
|---|---|---|
mjlab |
1.3.0 |
サーボの逆起電力 ( |
mujoco-warp |
3.7.0.1 |
mjlab 1.3.0 が要求する版 |
mujoco |
3.7.0 |
最新版が入ると mujoco-warp の import が落ちる |
warp-lang |
1.14.0 |
1.16 では学習開始時のカーネル生成が落ちる |
scipy |
1.15 以上 |
mjlab 1.3.0 が使っているのに宣言していない |
setup.sh は加えて、上流のロボット定義が使う update_assets(mjlab 1.3.0 で
削除された)を補う小さな互換パッチを、clone したチェックアウトに当てます。
当てないと src/assets/robots 全体が ImportError になり、ArduinoQuad-* の
登録まで巻き添えになります。
この組み合わせは 2026-08-31 に RTX 4090 で、環境構築から .h の書き出しまで
通して確認しています(2048 環境で 0.77 秒/iteration、63,700 steps/s)。
学習した方策を見るには:
./rl/scripts/play.sh ArduinoQuad-Walk # ビューアを開く(画面のある環境)
画面の無いサーバや Colab では、ビューアではなく mp4 に落とします:
source rl/scripts/env.sh
cd "$ARDUINO_QUAD_UPSTREAM"
python "$ARDUINO_QUAD_ROOT/rl/scripts/record_video.py" \
--ckpt logs/rsl_rl/arduino_quad_velocity/<run>/model_1500.pt \
--vx 0.09 --steps 300 --out walk.mp4
<run> は、学習を始めるたびに logs/rsl_rl/arduino_quad_velocity/ の下に作られる、
日時の付いたフォルダの名前に置き換えてください。
--bundle を渡すと、チェックポイントの代わりにエクスポート済みの方策
(13_quadruped/ の .npz + .json。--bundle "$ARDUINO_QUAD_ROOT" のように
13_quadruped のディレクトリを渡す)を、実機と同じ numpy 実装で再生します。
GPU なしで学習する(CPU 版)#
rl/cpu/ は、同じタスク(ArduinoQuad-Walk / -Robust)を mjlab を使わずに
素の MuJoCo で学習するものです。物理は CPU の mujoco.rollout(C++ の
スレッドプール)で回し、PPO は mjlab 版と同じ rsl-rl-lib 5.0.1 を使います。
ネットワークの更新だけを GPU に置くこともできます(--device cuda。CUDA は NVIDIA の GPU で計算するための仕組み)。
cd 13_quadruped/rl/cpu # docs/os-on-arduino/code から
uv sync # mujoco 3.7.0 + rsl-rl-lib 5.0.1 + torch
uv run train.py # ArduinoQuad-Walk、2048 環境、CPU
uv run train.py --device cuda # 物理は CPU のまま、更新だけ GPU
uv run evaluate.py --checkpoint logs/rsl_rl/arduino_quad_velocity/<run>/model_2299.pt
mjlab 版(rl/scripts/train.sh)はそのまま残っています。両者は同じタスクで、
チェックポイントの形式も同じなので、どちらで学習したものもどちらで続きから
学習でき、同じエクスポータでヘッダに書き出せます。CPU 版のチェックポイントを
書き出すときは --backend cpu を付けます。
uv run ../../host/export_quad_policy.py \
logs/rsl_rl/arduino_quad_velocity/<run>/model_2299.pt 出力先 --backend cpu
注釈
画面の無いサーバで evaluate.py --video を使うときは MUJOCO_GL=egl を付けて
ください。付けないと MuJoCo が GL のコンテキストを作れず、Renderer の生成で
落ちます。
どれくらいかかるか#
ノート PC(Core i9-8950HK、6 コア 12 スレッド、2018 年)での実測です。
環境数 |
物理(24 ステップ分) |
1 iteration(PPO 更新込み、CPU) |
|---|---|---|
2048 |
0.78 秒 |
1.55 秒 |
4096 |
1.50 秒 |
3.13 秒 |
約 63,000 env-steps/s で、mjlab 版を RTX 4090 で回したとき(63,700 steps/s)と 同じくらいです。同じノート PC で 2048 環境 × 2300 iteration を通しで回すと 68.9 分でした(1.80 秒/iteration)。上の表の 1.55 秒はベンチだけを測った値で、 実際の学習ではログとチェックポイントの書き出しが乗ります。
何 iteration で歩くようになるか#
上の通し(ARDUINO_QUAD_HOME_HEIGHT=0.11 ARDUINO_QUAD_GAIT_PERIOD=0.32、2048 環境、
1 シード)の 100 iteration ごとのチェックポイントを、evaluate.py で指令
0.09 m/s・32 環境・12 秒ずつ再生した実測です。接地率は 4 本の足それぞれが
接地している時間の割合(最小〜最大)、対角の同期は対角 2 本が同時に接地/離地して
いる割合、滑りは接地中の足先の水平速度です。
iteration |
前進 [m/s] |
接地率 |
対角の同期 |
滑り [mm/s] |
転倒 |
|---|---|---|---|---|---|
0 |
0.000 |
0.00–1.00 |
0.00 |
0 |
0 |
100 |
— |
— |
— |
— |
全機 |
200 |
— |
— |
— |
— |
全機 |
300 |
−0.003 |
0.00–0.99 |
0.33 |
19 |
0 |
400 |
0.036 |
0.21–0.86 |
0.44 |
75 |
0 |
600 |
0.026 |
0.28–0.82 |
0.31 |
79 |
0 |
800 |
0.088 |
0.38–0.78 |
0.53 |
73 |
0 |
1000 |
0.089 |
0.38–0.78 |
0.56 |
68 |
0 |
1500 |
0.088 |
0.36–0.77 |
0.55 |
62 |
0 |
1800 |
0.092 |
0.46–0.72 |
0.65 |
45 |
0 |
2000 |
0.090 |
0.46–0.67 |
0.69 |
41 |
0 |
2299 |
0.089 |
0.47–0.68 |
0.70 |
41 |
0 |
100〜200 iteration では全機が転びます。 まだ立っていられないので、 「転ばない」を覚えるまでの区間です。300 で転ばなくなり、400〜600 は前に出ようと して横に流れ(このとき旋回速度が 0.36 rad/s まで出ます)、指令の速度に届くのが 800 前後です。
速さは 1000 iteration で頭打ちですが、歩容はそこから 2300 まで良くなり続けます。
接地率が 4 本そろい(0.38–0.78 → 0.47–0.68)、対角の同期が 0.53 → 0.70 に上がり、
滑りが 73 → 41 mm/s に減ります。1500〜1800 でひと段落良くなるのは、trot_guidance
(歩容を教える報酬)の重みが 1400 iteration で 0 になった直後です。前進の速さだけを
見て学習を止めると、この区間を捨てることになります。
注釈
CPU 版が mjlab 版と同じタスクになっていることは rl/cpu/parity_check.py で
確認しています(同じ初期状態・同じ行動列で両方を回し、関節角・観測・報酬 26 項を
ステップごとに比較)。検査のやり方と、残っている差は rl/cpu/README.md にあります。
Genesis で学習する#
同じタスクを物理シミュレータ Genesis(GPU)で学習するコードが rl/genesis/ に
あります。学習した方策は MuJoCo でも歩きます。手順と、2 つのシミュレータでの
比較は Genesis で学習して MuJoCo で歩かせる(sim2sim) にまとめました。Genesis 版にも Google Colab で学習から
書き出しまで通すノートブックがあります(Genesis で学習して MuJoCo で歩かせる(sim2sim) の「Google Colab で学習する」)。
実機に持っていく#
チェックポイントから Arduino 用のヘッダを書き出します。
cd "$ARDUINO_QUAD_UPSTREAM"
python "$ARDUINO_QUAD_ROOT/host/export_quad_policy.py" \
logs/rsl_rl/arduino_quad_velocity/<run>/model_1500.pt \
出力先ディレクトリ ArduinoQuad-Walk
出てくるのは 3 つです。
ファイル |
使うところ |
|---|---|
|
ファームウェア( |
|
PC 直結版( |
|
同じ情報の機械可読版 |
重みだけでなく、観測の並び・履歴の順序・正規化の統計・home 角・action の スケールまで、学習時の環境から読み出して書き込みます。ここを人間が 書き写すと、エラーも出ないまま「震えるだけのロボット」になるためです。 書き出したあとで numpy 実装と PyTorch の出力を突き合わせて検証します。
実機で動かす手順は 歩行を学習させる(強化学習) の「実機で歩かせる」を読んでください。 最初は必ず機体を吊るしてから動かすこと。
つまずきやすいポイント#
症状 |
原因と対処 |
|---|---|
wandb のログインを求められて止まる |
mjlab の既定ロガーが wandb(Weights & Biases。学習の経過を記録するクラウドサービス)です。 |
|
|
画面が無い環境で |
ビューアを開こうとしています。 |
|
方策と環境の学習設定が食い違っています。メッセージが出す |
学習が「その場で止まる」方策に収束する |
到達できない速度を指令しています。この機体でサーボの余裕の中に収まるのは 0.05〜0.09 m/s です |
(読者からの質問に応じて随時追記します。質問は GitHub Issues へどうぞ)