歩行方策を自分で学習する#

第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 で、 それ自体は単体で動くプログラムではありません。

ファイル

中身

robot_cfg.py

機体定義(アクチュエータ、初期姿勢、home 角)

env_cfgs.py

観測・コマンド・ドメインランダマイゼーション(摩擦や質量などを学習中にランダムに変えること。学習のコード)

rewards.py

報酬項(速度追従、歩容、姿勢、エネルギー等)

rl_cfg.py

PPO のハイパーパラメータとネットワーク構成 [96, 64]

runner.py

ERFI(extended random force injection。トルク外乱)を足した学習ランナー

scripts/

環境構築・学習・再生・動画書き出し

cpu/

同じタスクを mjlab なしで学習する CPU 版(下の「GPU なしで学習する(CPU 版)」)

setup.sh が上流を .upstream/unitree_rl_mjlab に clone し、rl/ を src/tasks/velocity/config/arduino_quad としてシンボリックリンクで 置きます。上流は src/tasks/ 配下を自動 import するので、これだけで 次の 4 タスクが登録されます。

タスク ID

用途

ArduinoQuad-Flat

平地・素の velocity レシピ(立ち上げ確認用)

ArduinoQuad-Walk

平地 + 歩容シェーピング(本命。トロット歩行はこれ)

ArduinoQuad-Robust

Walk と同じだが初期状態を崩す(実機前の頑健化)

ArduinoQuad-Recovery

転倒姿勢から立ち上がる

Google Colab で学習する(GPU が無い人向け)#

ブラウザだけで、環境構築から Arduino 用ヘッダの書き出しまで通せる ノートブックを用意しました。

Open In Colab

ノートブックの流れ:

  1. GPU の確認(ランタイム → ランタイムのタイプを変更 → T4 GPU)

  2. コードを取ってきて、学習環境(mjlab + MuJoCo Warp + rsl_rl)を入れる

  3. 配布済みの学習済み方策を再生して動画で見る — ここまでで 「シミュレータ・方策・エクスポート」が揃って動いていることを確認できます

  4. 割り当てられた GPU で 30 iteration 回して学習速度を実測し、 所要時間を見積もる

  5. 学習する(チェックポイントは Google Drive に保存)

  6. セッションが切れたら続きから再開する

  7. 学習した方策を動画で確認して、arduino_quad_policy.h に書き出す

注釈

Colab の無料枠はセッションが数時間で切れます。学習ログを Google Drive に 逃がしておけば、--agent.resume True で何度でも続きから再開できます。 ノートブックの 6 章がその設定です。

無料枠の T4 でどれくらいかかるか#

2026-08-31 に Colab の無料枠(Tesla T4 15 GB、Python 3.13)で、環境構築から .h の書き出しまで実際に通しました。そのときの実測です。

環境構築(setup.sh)

約 1 分

学習(2048 環境)

1.42 秒/iteration、34,900 steps/s

書籍と同じ 4,500 iteration に必要な時間

約 1.8 時間

方策の再生(300 ステップの動画)

初回 5〜6 分(GPU カーネルの生成を含む)、2 回目以降 3〜4 分

.h の書き出し

約 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

サーボの逆起電力 (viscous_damping) と 27 ms の指令遅れ (delay_min/max_lag) が 1.2.0 に無い。後者は sim2real の要なので外せない

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 つです。

ファイル

使うところ

arduino_quad_policy.h

ファームウェア(13_quadruped/include/ に置き換える)

arduino_quad_policy.npz

PC 直結版(13_quadruped/host/quad_host.py)

arduino_quad_policy.json

同じ情報の機械可読版

重みだけでなく、観測の並び・履歴の順序・正規化の統計・home 角・action の スケールまで、学習時の環境から読み出して書き込みます。ここを人間が 書き写すと、エラーも出ないまま「震えるだけのロボット」になるためです。 書き出したあとで numpy 実装と PyTorch の出力を突き合わせて検証します。

実機で動かす手順は 歩行を学習させる(強化学習) の「実機で歩かせる」を読んでください。 最初は必ず機体を吊るしてから動かすこと。

つまずきやすいポイント#

症状

原因と対処

wandb のログインを求められて止まる

mjlab の既定ロガーが wandb(Weights & Biases。学習の経過を記録するクラウドサービス)です。--agent.logger tensorboard を付けると、TensorBoard(学習の経過をグラフで見るローカルのツール)に記録します

MJCF が見つかりません

source rl/scripts/env.sh を忘れています($ARDUINO_QUAD_XML)

画面が無い環境で play.sh が止まる

ビューアを開こうとしています。record_video.py を使ってください

home 姿勢が環境と方策で違います

方策と環境の学習設定が食い違っています。メッセージが出す ARDUINO_QUAD_HOME_HEIGHT=... を付けて実行し直す

学習が「その場で止まる」方策に収束する

到達できない速度を指令しています。この機体でサーボの余裕の中に収まるのは 0.05〜0.09 m/s です

(読者からの質問に応じて随時追記します。質問は GitHub Issues へどうぞ)