本页文档聚焦于将 Isaac Lab 中训练得到的强化学习策略迁移至 MuJoCo 物理仿真环境进行验证(Sim2Sim),并梳理从仿真到真机部署的关键对齐要素。我们将从模型导出管线、MuJoCo 部署脚本架构、观测-动作接口对齐、以及多算法变体的适配策略四个维度展开,帮助开发者建立一条从训练日志到实体机器人控制器的可靠迁移路径。
Sim2Sim 整体架构与数据流
Sim2Sim 的核心目标是验证策略在不同物理引擎下的鲁棒性,并生成可供真机部署的模型产物。整个管线分为三个阶段:训练产物导出、MuJoCo 仿真加载、以及可视化与数据分析。下图为整体架构概览:
flowchart LR
subgraph A[IsaacLab 训练端]
A1[训练日志目录<br/>logs/rsl_rl/...] --> A2[play.py / play_amp.py<br/>加载 checkpoint]
A2 --> A3[export_policy_as_jit<br/>导出 policy.pt]
A2 --> A4[export_policy_as_onnx<br/>导出 policy.onnx]
end
subgraph B[MuJoCo 仿真端]
B1[sim2sim_atom01*.py] --> B2[mujoco.MjModel<br/>加载 MJCF]
B2 --> B3[get_obs 观测提取]
B3 --> B4[torch.jit.load<br/>推理策略]
B4 --> B5[PD Control<br/>扭矩输出]
B5 --> B6[mujoco.mj_step<br/>物理推演]
end
A3 --> B1
训练端通过 play.py 系列脚本加载 checkpoint,利用 export_policy_as_jit 将策略网络封装为 Torch JIT 模块,同时导出 ONNX 作为备用格式。MuJoCo 端则通过 torch.jit.load 加载该模块,在 1000Hz 的物理仿真循环中按 decimation 间隔执行策略推理,输出位置指令经 PD 控制器转为力矩后驱动机器人。Sources: play.py, sim2sim_atom01.py
模型导出:从 Checkpoint 到部署产物
在 Isaac Lab 环境中运行 play 脚本时,模型导出是自动完成的。开发者需要关注导出路径、格式选择以及注意力编码器等特殊架构的自定义导出逻辑。
标准策略导出流程
标准 PPO 策略(包括 AMP、BeyondMimic)使用 isaaclab_rl.rsl_rl 提供的 export_policy_as_jit 函数,其本质是将策略的 actor 模块与观测归一化器(actor_obs_normalizer)组合,并通过 torch.jit.script 生成可序列化的 ScriptModule。导出目录位于 checkpoint 同级路径下的 exported/ 文件夹中。 Sources: play_bm.py, play_amp.py
注意力编码器策略的自定义导出
对于使用注意力编码器(Attention Encoder)感知地形的策略,play.py 中定义了 TorchAttnEncPolicyExporter 类。该导出器在 forward 中显式复现了推理链路:先对本体观测做归一化,经可选的观测编码器与价值估计器处理后,再与地形感知特征拼接,最终输入 actor 网络。此封装确保了 MuJoCo 端只需调用一次 policy(input) 即可获得动作,无需手动处理编码器分支。 Sources: play.py
| 导出格式 | 适用场景 | 关键函数/类 | 文件产物 |
|---|---|---|---|
| Torch JIT | MuJoCo Sim2Sim、真机 Python 部署 | export_policy_as_jit / TorchAttnEncPolicyExporter |
policy.pt |
| ONNX | 嵌入式 C++ 推理(如 NVIDIA Jetson)、ROS2 节点 | export_policy_as_onnx / OnnxAttnEncPolicyExporter |
policy.onnx |
Sources: play.py, play_amp.py
MuJoCo 部署脚本详解
robolab/scripts/mujoco/ 目录下包含五种 Sim2Sim 部署脚本,分别对应不同的训练算法与任务变体。它们共享一套底层控制循环,但在观测构造、交互方式和特殊输入上存在差异。
脚本变体与功能定位
| 脚本文件 | 对应算法/任务 | 特殊功能 | 交互方式 |
|---|---|---|---|
sim2sim_atom01.py |
标准 PPO / Direct RL | 基础部署、数据绘图 | 固定指令或程序控制 |
sim2sim_atom01_amp.py |
AMP 模仿学习 | 实时键盘控制、相机跟随、状态重置 | pynput 键盘监听(8/2/4/6/7/9/0/F) |
sim2sim_atom01_attn_enc.py |
注意力编码器 + 地形感知 | 地形射线扫描、注意力可视化 | 固定指令 |
sim2sim_atom01_bm.py |
BeyondMimic 运动先验 | 运动参考输入(motion_file)、循环播放 | 有限键盘控制(F/0) |
sim2sim_atom01_interrupt.py |
中断恢复任务 | 模拟外部中断信号(is_interrupt 标志) |
固定指令 |
Sources: sim2sim_atom01.py, sim2sim_atom01_amp.py, sim2sim_atom01_attn_enc.py, sim2sim_atom01_bm.py, sim2sim_atom01_interrupt.py
控制循环时序
所有脚本均采用双层控制循环:外层 MuJoCo 物理步进运行在 1000Hz(dt=0.001),内层策略推理按 decimation 间隔触发。例如 decimation=20 时策略以 50Hz 运行。此设计与 Isaac Lab 中 step_dt = decimation * physics_dt 的设定严格对应,是 Sim2Sim 与训练环境行为一致的关键。 Sources: sim2sim_atom01.py
sequenceDiagram
participant M as MuJoCo (1000Hz)
participant O as get_obs
participant P as Policy Network
participant PD as PD Controller
loop 每物理步
M->>O: 提取 q, dq, quat, v, omega, gvec
alt count % decimation == 0
O->>P: 构造 obs (含 history stacking)
P->>PD: 输出 action -> target_q
Note over O,P: 同时采集低频数据用于绘图
end
PD->>M: tau = kp*(target_q - q) + kd*(0 - dq)
M->>M: mj_step(model, data)
end
Sources: sim2sim_atom01.py
观测-动作接口对齐
Sim2Sim 与训练环境之间最脆弱的环节在于观测空间的逐维对齐。任何维度的错位或语义偏差都会导致策略输出完全失效。
观测构造细节
get_obs 函数从 MuJoCo 的 MjData 中提取以下物理量:关节位置 q、关节速度 dq、IMU 四元数 quat、基座线速度 v(转换到基座坐标系)、角速度 omega、以及重力向量 gvec。这些量经过坐标系转换和关节顺序重排后,拼接为策略输入。 Sources: sim2sim_atom01.py
在 sim2sim_atom01.py 中,单帧观测 num_single_obs=78 的拼接顺序为:
| 维度区间 | 内容 | 说明 |
|---|---|---|
[0:3] |
omega |
基座角速度(IMU,基座坐标系) |
[3:6] |
gvec |
重力方向向量(基座坐标系) |
[6] |
cmd.vx |
指令线速度 X |
[7] |
cmd.vy |
指令线速度 Y |
[8] |
cmd.dyaw |
指令角速度 Yaw |
[9:32] |
q_obs |
23 个关节的相对位置(q - default_pos) |
[32:55] |
dq_obs |
23 个关节速度 |
[55:78] |
action |
上一策略步输出的动作 |
Sources: sim2sim_atom01.py
关节顺序映射(usd2urdf)
Isaac Lab 中 USD/URDF 的关节枚举顺序与 MuJoCo MJCF 中的顺序可能不同。robot_config.usd2urdf 数组定义了从策略输出索引到 MuJoCo 关节索引的映射。ATOM01 的映射为 [0, 6, 12, 1, 7, 13, 18, 2, 8, 14, 19, 3, 9, 15, 20, 4, 10, 16, 21, 5, 11, 17, 22],涵盖了 23 个驱动关节。 Sources: sim2sim_atom01.py, sim2sim_atom01.py
History Stacking 与 Frame Stack
为保留时序信息,训练环境通常采用 frame_stack 机制叠加最近若干帧观测。在 MuJoCo 端,hist_obs 被维护为一个 (frame_stack, num_single_obs) 的缓冲区,首帧通过 np.tile 初始化,之后以滚动窗口方式更新。最终输入策略的形状为 (1, frame_stack * num_single_obs)。 Sources: sim2sim_atom01.py
注意力编码器的地形观测扩展
sim2sim_atom01_attn_enc.py 在基础观测之上增加了地形射线扫描。它通过 get_rays 调用 mujoco.mj_ray 从机身正上方垂直向下发射射线,测量地形高度,再将结果裁剪至 [-1.0, 1.0] 作为感知观测。该感知向量与历史观测拼接后共同输入策略。 Sources: sim2sim_atom01_attn_enc.py, sim2sim_atom01_attn_enc.py
PD 控制与执行层参数
MuJoCo 部署脚本中的执行层完全由 PD 控制器驱动,这与 Isaac Lab 中的 DelayedPDActuatorCfg 形成对应关系。控制参数在 Sim2simCfg.robot_config 中集中定义:
| 参数 | 典型值 | 说明 |
|---|---|---|
kps |
各关节 [100, 100, ..., 30, 20] |
PD 比例增益,腿部关节较高,手臂关节较低 |
kds |
对应 [3.3, 3.3, ..., 1.5, 1.0] |
PD 微分增益,与刚度匹配抑制振荡 |
default_pos |
23 维数组 | 默认站立姿态,用于计算相对关节位置观测 |
action_scale |
0.25 |
策略输出缩放系数,限制单步位置变化幅度 |
tau_limit |
200.0 |
力矩饱和上限,保护执行器 |
decimation |
20(标准)/ 4(AMP/BM) |
策略推理与物理步进的频率比 |
PD 控制公式为 tau = (target_q - q) * kp + (target_dq - dq) * kd,其中 target_dq 通常置零。输出力矩经 np.clip 限幅后写入 data.ctrl。 Sources: sim2sim_atom01.py, sim2sim_atom01.py
结果分析与可视化
部署脚本在运行结束后自动生成两类分析图表,用于量化策略在 MuJoCo 中的跟踪性能:
- 关节位置跟踪图(
joint_positions.png):对比每个关节的指令位置(Commanded)与实际位置(Actual),评估 PD 跟踪精度与策略稳定性。 - 基座速度跟踪图(
base_velocities.png):对比指令线速度vx、vy与角速度dyaw的实际值,反映速度指令的响应特性。
在 headless 模式下,脚本还会通过 OpenCV 将仿真画面编码为 simulation.mp4,便于离线审阅。 Sources: sim2sim_atom01.py
真机迁移的关键对齐检查清单
从 MuJoCo Sim2Sim 迈向实体机器人时,以下四项对齐是决定成败的核心:
物理接口对齐
确保真机底层驱动接受位置指令(position command)而非直接力矩控制,因为本项目训练的策略输出的是目标关节位置增量。真机控制器的 PD 参数应与 MuJoCo 中的 kps/kds 尽量接近,以缩小 sim-to-real 执行器动力学差异。
观测接口对齐
真机需通过 IMU 提供基座角速度和重力向量,通过编码器提供关节位置与速度。必须严格保证观测向量各维度的物理含义、单位、坐标系与训练环境一致。尤其注意 usd2urdf 映射——真机控制器的关节枚举顺序必须与 MuJoCo 中的定义相同。
时序对齐
Sim2Sim 中策略以 50Hz(标准)或 250Hz(AMP/BM)运行。真机控制回路的推理频率必须与该值严格匹配,否则历史观测 frame_stack 的时间尺度会发生漂移,导致策略行为异常。
模型格式对齐
若真机部署平台为 ARM 嵌入式设备(如 NVIDIA Jetson),推荐使用 ONNX 格式配合 TensorRT 推理;若为 x86 工控机或支持 PyTorch 的算力平台,可直接加载 torch.jit.load 导出的 policy.pt。注意在导出时通过 .to("cpu") 确保模型权重位于 CPU,避免 JIT 模块包含设备特定的张量常量。
Sources: sim2sim_atom01.py, play.py
常见问题排查
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 机器人瞬间倒地/抽搐 | usd2urdf 映射错误 |
核对关节索引与 MJCF 中 actuator 顺序 |
| 策略输出全为 0 或饱和 | 观测归一化器未加载 | 确认 normalizer 在导出时被正确嵌入 JIT 模块 |
| 头部姿态异常但腿部正常 | IMU 四元数顺序或坐标系差异 | 检查 quat 的 wxyz/xyzw 顺序与 scipy.Rotation 处理 |
| 视频/画面渲染异常 | MUJOCO_GL 环境变量未配置 |
在 Linux 上设置 MUJOCO_GL=glfw |
| AMP 策略在 MuJoCo 中行为与 IsaacLab 差异大 | dt 与 decimation 不匹配 |
AMP 使用 dt=0.005, decimation=4(250Hz),勿与标准配置混淆 |
Sources: sim2sim_atom01.py, sim2sim_atom01_amp.py
延伸阅读与后续步骤
完成 Sim2Sim 验证后,下一步通常是将策略集成到真机软件栈中。在继续之前,建议回顾以下关联页面以确保对训练端和算法端有充分理解:
- 若需回顾策略训练与 checkpoint 的产生机制,请参阅 On-Policy Runner 训练循环 与 AMP Runner 与模仿学习训练。
- 若部署的是注意力编码器策略,其感知模块的网络架构详见 注意力编码器感知机制。
- 若需为 Sim2Sim 定制新的地形或场景,参考 地形生成与场景配置。
- 对于自定义任务的扩展开发,可查阅 自定义任务与环境扩展指南。