IsaacSim上でのテスト。本記事のゴール。
こんにちは。株式会社センシンロボティクスでロボティクス開発をしています。神谷です。
四足ロボットの強化学習をIsaacLabで学習してGenesisで動かすところまで一通り通してみたので、その記録です。
対象読者
- 強化学習でロボットの歩行を学習させたい人
- sim2sim, sim2realを検討中の人
必要なもの: NVIDIA GPU搭載のLinuxマシン + Docker
シリーズ構成
- その1(本記事): IsaacLab の公式Docker上に学習環境を作り、DR+特権学習で歩行ポリシーを学習する
- その2: 学習した
policy.ptを Genesis 上で動かす(sim2sim)
まとめ
- 全体の狙いは 学習は実績のある Isaac 系で行い、できたポリシーを Genesis 上のいろいろな不整地で試すこと。本記事はその学習側
- IsaacLab (v2.3.2) の公式Dockerをベースに、DeepRobotics M20(車輪付き四足)向けの学習環境を構築した
- IsaacLab本体はforkせず、docker-compose に bindマウントを1行足すだけで学習コードを注入する構成にした
- 学習コードは DeepRoboticsLab/rl_trainingベース。Domain Randomization(DR)+ 特権学習(非対称Actor-Critic) で歩行ポリシーを学習
-
rl_trainingはリリース版 Isaac Lab 2.3.2 ではそのまま動かなかった(main前提のコードが混ざっている)ので注意。対処法も本記事に記載。
検証済みバージョン: Isaac Sim 5.1.0 / Isaac Lab 2.3.2 / RSL-RL 5.0.1 / Python 3.11
1. はじめに
やりたいこと: Isaac 系で学習 & Genesisで評価
ロボットの強化学習を始めるなら、まずは実績と情報量が十分にある Isaac 系(Isaac Sim / Isaac Lab)でやるのが良いと思います。
isaaclabにはロボティクスの強化学習事例もアセットも多く、詰まったときに参照できるものやDR用の環境も揃っていて手軽に始めやすいのが良い感じです。
一方で、できたポリシーをいろいろな環境でテストする場としては別のシミュレータも触っておきくて Genesis に前々から注目していました。Genesis は剛体だけでなく MPM / SPH / PBD のソルバを統一APIで置けるのが嬉しいです。
最近正式リリース版も出ていて安定して動くようになってきているので将来性を期待しています。
そのために必要なのが、学習成果物(policy.pt / env.yaml)を Genesis に持っていくブリッジ。それを作ったのが今回の一連の作業で、ブリッジ本体はその2で扱います。
学習環境ごと Genesis に移す(Genesis上で学習を回す)のもやりたいですが、そこは将来的な話。今回はその前段として 学習は Isaac Lab、評価は Genesis の分業でやっていきます。
sim2sim を挟む副産物
ついでの利点として、実機に持っていく前に別の物理エンジンで動くか(sim2sim)を確認しておくと、学習環境に過剰適合した「そのシミュレータでしか歩けないポリシー」を早期に弾けるのも利点です。一般的にはこれがsim2simの目的かもしれません。
全体像
[IsaacLab + rl_training] [bridge] [Genesis]
DR + 特権学習で PPO 学習 → 学習ログから → 汎用ランタイムで
policy.pt / env.yaml 出力 config自動生成 推論ループ実行
← ここまでが その1(本記事) → ← ここから その2 →
→ その先: 不整地・連続体地形での評価
本記事(その1)では左半分——IsaacLab上に学習環境を立てて、DR+特権学習でポリシーを出すところまでを扱います。右半分の sim2sim はその2で。
2. システム構成
| リポジトリ | 役割 | その1で使う |
|---|---|---|
| IsaacLab (v2.3.2) | 物理シミュレーション×RLエンジン。Docker土台 | ✅ |
| rl_training(DeepRoboticsLab/rl_training) | M20向け学習環境定義+学習スクリプト | ✅ |
| Genesis | sim2sim検証先のシミュレータ | その2 |
| isaaclab-genesis-runner(自作) | 学習成果物 → Genesis実行のブリッジ+ランタイム | その2 |
リポジトリはワークスペース直下に並列で配置します。
<workspace>/
├── IsaacLab/ # v2.3.2 タグをcheckout。Docker一式
├── rl_training/ # 学習コード
├── Genesis/ # sim2sim実行環境(Docker)… その2
└── isaaclab-genesis-runner/ # bridge / runtime … その2
3. 環境構築(IsaacLab Docker + 学習コードのマウント)
学習は IsaacLab 公式 Docker をそのまま使い、学習コードはbindマウントで注入する方式をとりました。
IsaacLab本体のイメージを作り直さずに済むので、IsaacLabのバージョン更新と学習コードの開発を分離できます。
3.1 compose にマウントを1つ追記
IsaacLab/docker/docker-compose.yaml の x-default-isaac-lab-volumes アンカー末尾に追記する。IsaacLab側への変更はこれだけです。
# Mount the rl_training repo (sibling of IsaacLab on the host) into the container
- type: bind
source: ../../rl_training
target: /workspace/rl_training
3.2 コンテナ起動〜インストール
# ホスト側: クローン(ロボットモデル M20.usd は submodule なので --recurse-submodules 必須)
git clone --recurse-submodules <rl_training のURL>
cd IsaacLab/docker
./container.py start base
./container.py enter base
# コンテナ内(この順序を守る)
python -m pip install --no-build-isolation flatdict==4.0.1
cd /workspace/isaaclab && ./isaaclab.sh --install # マウントで上書きされるため再install
cd /workspace/rl_training && python -m pip install -e source/rl_training
python scripts/tools/list_envs.py # 環境一覧が出れば成功
3.3 環境構築トラブルシュート
| 症状 | 原因と対処 |
|---|---|
学習開始時に FileNotFoundError: ... M20.usd
|
submodule 未取得。git submodule update --init --recursive
|
ModuleNotFoundError: No module named 'isaaclab' |
bindマウントで source が上書きされている。コンテナ内で ./isaaclab.sh --install を再実行 |
isaaclab.sh --install が pkg_resources 絡みで失敗 |
sdist依存(flatdict等)を --no-build-isolation で先にinstall |
ホストで git すると Permission denied
|
コンテナ内で git した結果 .git がroot所有に。git操作はホスト側のみで行う |
| pip を upgrade したら環境が壊れた | コンテナ内の python/pip は Isaac Sim ランチャのalias。同梱pipはupgradeしない。壊したらコンテナ作り直し |
4. 【注意点】学習リポジトリがリリース版 Isaac Lab で動かないことがある
rl_training は README で Isaac Lab 2.3.2 を指定しています、実際には Isaac Lab main ブランチ前提のコードが混ざっていて、タグ版 2.3.2 では2箇所がエラーになりました。
-
handle_deprecated_rsl_rl_cfgのImportError(train.py / play.py) — このシンボルは Isaac Labmainにしか存在せず、2.3.2 リリースに無い -
VIS_ENABLEdのNameError(play.py) — 歩容リファレンス可視化ブロックが未定義の名前を参照していて、再生時にクラッシュ
どちらもエラーメッセージがきちんと出るので、対処自体(importをガードする / 該当ブロックを無効化する)はAIにおしえるとすぐ直してくれる、はずです。
5. 学習: 特権学習PPO + Domain Randomization
5.0 Actor と Critic
PPO(Proximal Policy Optimization:近接方策最適化)ではActorとCriticという2つのモデルを同時に学習します。
Actor(policy) |
Critic(value) |
|
|---|---|---|
| 入力 | 観測 | 観測 |
| 出力 | 行動(16次元) | その状況の価値(スカラー1つ) |
| 役割 | 実際にロボットを動かす | Actorをどう更新するか(勾配)を決めるための採点役 |
| 学習後 |
policy.pt としてデプロイ |
使わない |
Criticは行動を出しません。「今の状況はこの先どれくらい報酬が取れそうか」を数値で予想するだけのモデルで、その予想と実際に得られた報酬とのズレが、Actorを更新する勾配の元になります。逆に言うとCriticの予想が的確だと、Actorの学習が速く安定します。
Criticは学習中にしか動かないので、実機では絶対に取れない情報を渡しても問題ありません。これを利用するのが5.3の特権学習です。
5.1 環境定義の構造(IsaacLab Manager-Based)
IsaacLab の Manager-Based 環境では、観測・報酬・DR などを @configclass で宣言的に書きます。
M20 の環境は LocomotionVelocityRoughEnvCfg をベースに、観測57次元 → 行動16次元(脚12関節+車輪4輪)で構成されています。
観測57次元の内訳は次のとおりです(ObservationsCfg.PolicyCfg に宣言した順にそのまま連結される)。
| # | 項目 | 次元 | 中身 |
|---|---|---|---|
| 1 | base_ang_vel |
3 | ベースの角速度(body frame, IMU相当) |
| 2 | projected_gravity |
3 | 重力ベクトルをbody frameに落としたもの(=姿勢) |
| 3 | velocity_commands |
3 | 速度コマンド (vx, vy, ωz)
|
| 4 | joint_pos_rel_without_wheel |
16 | 関節角のデフォルト姿勢からの差分 (wheel0埋め) |
| 5 | joint_vel_rel |
16 | 関節角速度 |
| 6 | last_action |
16 | 前ステップの行動(そのまま) |
| 合計 | 57 |
5.1.1 Actorに渡さない観測
この57次元は すべて自己受容感覚(IMU+関節エンコーダ)+ コマンド + 前回行動 で、外界センサが一切入っていません。IsaacLab の locomotion 環境で標準で用意されているこれらは、policyグループでは無効(None)です。
-
base_lin_vel(ベース並進速度) — シミュレータなら真値が取れます、実機で正確に取るのが難しいです。特権情報として今回使用します。 -
height_scan(地形高さスキャン) — LiDAR/深度センサ前提の観測。今回は使っていません。
この2つはcritic(学習時のみ使う側)にのみ真値で渡すことができます。Actorに渡す観測は実機で取れるものだけに絞ります。
5.2 Domain Randomization(EventCfg)
EventCfg に DR 項目を列挙するだけで、リセット時・一定間隔でランダム化が走ります。今回入れたのは次です。
@configclass
class EventCfg:
randomize_rigid_body_material = ... # 接地摩擦・反発係数
randomize_rigid_body_mass = ... # リンク質量
randomize_rigid_body_mass_base = ... # ベース質量(ペイロード相当)
randomize_rigid_body_inertia = ... # 慣性
randomize_com_positions = ... # 重心位置
randomize_apply_external_force_torque = ... # 外乱力・トルク
randomize_reset_joints = ... # 初期関節状態
randomize_actuator_gains = ... # アクチュエータ Kp/Kd
randomize_reset_base = ... # 初期ベース姿勢・速度
randomize_push_robot = ... # 定期的に突き飛ばす
sim2sim 的には摩擦・質量・アクチュエータゲインのランダム化が重要らしいです。
移行先のGenesisは接触モデルもソルバも違うので、物理パラメータへの過剰適合を防ぐためです。
5.3 特権学習(非対称 Actor-Critic)
PPO の Actor と Critic に別々の観測を与えます。IsaacLab では ObservationsCfg に policy / critic の2グループを定義するだけで実現できます。
@configclass
class ObservationsCfg:
@configclass
class PolicyCfg(ObsGroup):
base_ang_vel = ObsTerm(func=mdp.base_ang_vel,
noise=Unoise(n_min=-0.2, n_max=0.2), ...)
joint_pos = ObsTerm(..., noise=Unoise(n_min=-0.01, n_max=0.01))
# ... 実機で得られる観測に、実機相当のノイズを載せる
def __post_init__(self):
self.enable_corruption = True # ノイズあり
@configclass
class CriticCfg(ObsGroup):
# base速度を観測に入れ、ノイズも載せない
def __post_init__(self):
self.enable_corruption = False # ノイズなし
policy: PolicyCfg = PolicyCfg()
critic: CriticCfg = CriticCfg()
- Actor(デプロイされる側): ノイズ付き観測のみ。実機・移行先simで手に入るものだけで動く
- Critic(学習時のみ使う側): ノイズなしの真値で価値推定。学習が安定・高速化する
5.4 学習の実行
# 学習(GPUメモリ節約のためheadless推奨)
python scripts/reinforcement_learning/rsl_rl/train.py --task Rough-Deeprobotics-M20-v0 --headless
# 再生(重ければ --num_envs 32〜64 に下げる)
python scripts/reinforcement_learning/rsl_rl/play.py --task Rough-Deeprobotics-M20-v0
5.5 学習の結果
学習の履歴は自動で保存されるのでTensor Boardで確認することができます。
tensorboard --logdir logs/rsl_rl/deeprobotics_m20_rough
次のコマンドでポリシーをisaac sim上で動かすことができます。
python scripts/reinforcement_learning/rsl_rl/play.py \
--task=Rough-Deeprobotics-M20-v0 \
--load_run <run名> --keyboard
なかなか可愛く動きます。
6. 学習成果物 —— その2への受け渡し
成果物は logs/rsl_rl/... に出力される。その2(sim2sim)で使うのは次の3ファイルだけです:
| ファイル | 中身 | sim2simでの役割 |
|---|---|---|
policy.pt |
学習済みポリシー(TorchScript) | 推論本体 |
env.yaml |
環境定義のダンプ | 観測構成・関節順・ゲイン・スケール等の真値 |
agent.yaml |
PPO/ネットワーク構成 | ネットワーク形状の確認 |
特に env.yaml が重要で、その2ではこの情報をもとにgenesis用の設定を生成します。
7. 次回
次回(その2)は、ここで得た policy.pt / env.yaml を Genesis 上で動かす sim2simをテーマに関節順・quaternion規約・観測スケールといったポイント回避するブリッジを紹介します。そこが通ればisaaclab上で学習したポリシーを砂やぬかるみのような連続体を含む地形での評価にも展開できます。
→ その2: 学習済みポリシーをGenesisで動かす(sim2sim)

