Parkour Sim2Sim Report

IsaacLab Parkour是Extreme Parkour (Cheng et al., ICRA 2024) 的 IsaacLab 复现,在此基础上进行的新探索
以及IsaacLab→MuJoCo sim2sim 部署研究

teacher 50k MuJoCo 87.5% 42 / 48 case 通过 · 同 ckpt IsaacLab 100%
5-ckpt aggregate 98% / 35% IsaacLab 236/240 MuJoCo 84/240 
平地步态差异 < 1.5% cmd 0.3/0.5/0.8 三档稳定
评测基建 480 tests 2平台 · 5 ckpt × 4 地形 × 6 摩擦 × 2 关节随机初始化

1LP 基础上的前置探索 — 策略改动尝试

1.1 9 个实验速览

ID 改动 关键参数 指标 判定
A1 特权正则提前衰减 让 encoder 表征更早稳定下来, 不被持续的特权监督拖住 priv_reg衰减提早 terrain 6.39 / base 5.18 ✗ 短预算取巧
A2 加大 goal 速度奖励 引导更强朝 waypoint 推进 tracking_goal_vel1.5 → 2.5 terrain 5.77 ✗ 弃用
A3 抬熵系数 策略更倾向探索 entropy_coef0.01 → 0.025 terrain 0.00 (训练崩) ✗ 弃用
A4 提升学习率 learning_rate2e-4 → 5e-4 terrain 5.62 ✗ 弃用
A5 软化 collision 容忍轻微碰撞换更激进通过姿态 碰撞惩罚-10 → -5 terrain 6.39 ✗ 弃用
A6 Critic LN critic 每层后插 LayerNorm (NeurIPS 2024 抗 plasticity loss) waypoints 0.91 / base 0.90 ≈ 不显著
A7 Estimator detach PPO 主回路切断 estimator 输出梯度 waypoints 0.99 ⚠ 事后推翻
A8 Cosine latent student 蒸馏加余弦损失, depth latent 对齐 teacher scan latent 权重0.2, 3 seed waypoints 0.80 → 0.87 ✓ 正向倾向
A9 ELU → SELU 把激活函数换成 SELU (自归一化) waypoints 0.90 ≈ 无效

2效果演示

摩擦 μ0.4 – 1.9 (演示 1.0)ckpt对应对齐
初始姿态固定 / 随机waypoint 位置对齐
地形尺寸精确对齐速度指令对齐
🪨 parkour stones (踏石)
IsaacLab
MuJoCo
🦘 parkour hurdle (跨栏)
IsaacLab
MuJoCo
🪜 parkour step (上下阶)
IsaacLab
MuJoCo
🌉 parkour gap (跳缝)
IsaacLab
MuJoCo

3Pipeline - sim2sim

3.1 数据流 (一图概览)

1
🏋️ 训练端
IsaacLab · PhysX · GPU
teacher (PPO) + student (DAgger 蒸馏) 离线训练, 产 actor/estimator 网络权重
2
📦 打包结果
teacher_deploy.pt
torch.jit 把 Normalizer + Estimator + Actor 串成单文件, 不带训练栈依赖
3
🦿 部署端
MuJoCo · CPU · 50 Hz ctrl
load .pt → 闭环推理 (obs → action → mj_step) → 480-case 评测

3.2 对齐 7 维度 (主要工作量)

训练 (PhysX) 和部署 (MuJoCo) 是两个不同物理引擎. policy 同一个, 但跑出来的轨迹常常不一样. 真正的工程量是把各个维度逐个对齐

# 对齐维度 状态 本质 / 备注
1
DoF / Joint 顺序
✅ done 关节编号映射. 错位则"左前腿指令"跑到"右后腿", 一动就翻车.
2
PD / 控制频率 / Decimation
✅ done 控制节奏 (sim dt / policy 周期 / delay). 对不上则快动作抖、慢动作卡.
3
Obs 753 维 · 五段布局
✅ done 神经网络输入张量布局. 任一段错位整张读错, 后果不可预测.
4
Action Scale + Filter
✅ done 输出力度 + 滤波平滑. 太大乱抖、太小走不动, 滤波不一致响应滞后.
5
Contact / 接触动力学
🟡 部分 引擎差异 (MJ Coulomb vs PhysX TGS). sim2sim 最隐蔽杀手, 靠 per-box 重建 + DR 吸收.
6
Heightmap (Raycast / 几何)
✅ done 机器人看地面的眼睛. 高度图偏一点, 前面是坑变前面是地, 直接踩空.
7
Latency / 时序
✅ done 时序延迟. 命令到转动有 delay, 不一致快一拍或慢一拍.
额外 N=1 维度 (A-LP 专属, 6 维之外):
  • ⚠️ Hscale 不对称 — teacher hscale=0.08 / student hscale=0.10, hurdle 顶宽 24 cm vs 10 cm (student 仅 42 %). 已识别, 未根治. 大白话: 师傅练的是"指尖大平台", 徒弟得跳"手掌大平台", 尺寸根本不对.
  • 🟡 Per-stone box 重建 — 训练侧 trimesh, 部署侧改用积木盒重新拼 (避开 MJ 把 mesh 自动凸包成奇怪形状). parkour d=0.6 ✅ done, hurdle / step / gap 仍待补.
  • ⚠️ Footgun 红线 — F1 相机光轴 (文字 70° 实际 20° 下倾) / F2 Estimator ×2 标度全 pipeline 锁死 / F3 student 的 yaw 由 depth encoder 直出无 GT 兜底. 概念层易写错, 写 doc 必须按正确版引用.

4实验数据汇总

3.1 评判标准 — 怎么算"通过"

progress = 机器狗在跑酷方向走过的距离, 除以整段路程长. 取值 0~1, 1 就是走到终点.

progress  =  最远到达 x  ÷  路程总长
通过  =  踩到最后一个 goal 圆盘    progress ≥ 0.86

阈值 0.86 取自 8 个地形配置 (4 种 × 2 高度) 的实测下界 — 每个配置"刚跨过最后障碍"瞬时的 progress 落在 0.864 ~ 0.898 区间:

地形h scale跨过瞬时 progress
🪨 parkour (踏石)0.080.876
🪨 parkour (踏石)0.100.864 ← 最低
🪜 step (上下阶)0.080.889
🪜 step (上下阶)0.100.884
🦘 hurdle (跨栏)0.080.886
🦘 hurdle (跨栏)0.100.875
🌉 gap (跳缝)0.080.893
🌉 gap (跳缝)0.100.898 ← 最高

综合取 0.86 作为通过标准

3.2 跑酷 4 地形

测试集: 1 个 ckpt 跑 4 地形 × 6 摩擦 × 2 关节扰动 = 48 case, 5 个 ckpt 合 240 case/仿真器. 难度 d=0.6, seed=42, episode 20 s. 原始数据 TSV (480 行) 在仓库 sim2sim/ 下.

teacher 50k 主 baseline 🥇
IsaacLab
48 / 48 · 100%
MuJoCo
42 / 48 · 87.5%
student 50k 见 §5.2 训练分布
IsaacLab
48 / 48 · 100%
MuJoCo
20 / 48 · 41.7%
teacher 10k 训练欠收敛
IsaacLab
48 / 48 · 100%
MuJoCo
20 / 48 · 41.7%
student 10k baseline 训练欠收敛
IsaacLab
47 / 48 · 98%
MuJoCo
2 / 48 · 4%
student 10k a4 (cosine) 变体跑炸
IsaacLab
45 / 48 · 94%
MuJoCo
0 / 48 · 0%
5-ckpt 合计 sim2sim 上限
IsaacLab
236 / 240 · 98%
MuJoCo
84 / 240 · 35%

3.3 平地地形

只跑纯平面 + 各种参数 hardcode. IsaacLab 5 次取分布, MuJoCo 单次. teacher 50k 数据:

cmd_vel = 0.3 m/s
IsaacLab 速度
0.421
MuJoCo 速度
0.386
IsaacLab base高度
0.321
MuJoCo base高度
0.314
vx 差异-8.3%
cmd_vel = 0.5 m/s
IsaacLab 速度
0.601
MuJoCo 速度
0.572
IsaacLab base高度
0.324
MuJoCo base高度
0.316
vx 差异-4.8%
cmd_vel = 0.8 m/s
IsaacLab 速度
0.876
MuJoCo 速度
0.831
IsaacLab base高度
0.323
MuJoCo base高度
0.321
vx 差异-5.1%
结论: 平地两边几乎一致, 物理引擎本身对齐. 跑酷地形上的差距不来自动力学, 而来自感知 / 几何 / 训练分布层.

3.4 拆开看: 4 种地形 × 2 仿真器

每种地形单独看, 哪种最难 (踏石 / 跳缝) 哪种最易 (上下阶).

🪜 parkour_step (上下阶) -55 pp
IsaacLab
60 / 60
MuJoCo
27 / 60
teacher 50k MuJoCo12 / 12 ✓
🦘 parkour_hurdle (跨栏) -58 pp
IsaacLab
57 / 60
MuJoCo
22 / 60
teacher 50k MuJoCo12 / 12 ✓
🌉 parkour_gap (跳缝) -70 pp
IsaacLab
60 / 60
MuJoCo
18 / 60
teacher 50k MuJoCo8 / 12
🪨 parkour (踏石) -70 pp
IsaacLab
59 / 60
MuJoCo
17 / 60
teacher 50k MuJoCo10 / 12

3.5 进阶指标 — 平均通过 waypoint 数

pass% 是二元判定, student 10k 两个变体在 MuJoCo 上都接近 0%, 看不出谁更接近收敛. 引入 maxgoal (平均通过 waypoint 数, 满分 7) 这个连续计数区分 student 间差别.

teacher 50k 主 baseline 🥇
IsaacLab
7.00
MuJoCo
6.75
student 50k
IsaacLab
7.00
MuJoCo
2.40
teacher 10k
IsaacLab
7.00
MuJoCo
4.48
student 10k baseline
IsaacLab
5.77
MuJoCo
1.90
student 10k a4 (cosine) ✨ 深度略胜
IsaacLab
6.88
MuJoCo
2.04

3.6 摩擦 sweep (MuJoCo 6 档)

μ = 0.4(分布外极端)
12.5%
μ = 0.7
27.5%
μ = 1.0(训练标称)
40%
μ = 1.3
37.5%
μ = 1.6★ peak
47.5%
μ = 1.9
45%

5三个代表性对齐问题

5.1 射线打到机器人自己身上 ✓ 已修

现象

teacher 在 MuJoCo 上前进速度锁在 0.65 m/s, estimator 估出来的速度比真值低 13–29%, 步态节奏不稳, 出现明显跳跃式触地.

真因

scandot 采样栅格的 x 方向前向偏移设得不够, 132 个采样点的栅格盖在机身正下方而非机身前方; 向下发射的射线大量被自身腿部遮挡, 回传的"地面高度"实为"到腿顶的距离", scandots 整体失真.

修复

把 scandot 栅格的 x-offset 调到与训练端一致, 让采样落在机身前方目标地形上; 射线起点同步从 5 m 抬至 20 m 对齐训练端规范. 修后 estimator 误差收敛至 +3%, 速度指令恢复线性跟随.

5.2 跑酷地形几何对齐 ✓ 已修

现象

同一 policy, 在 IsaacLab 上四种跑酷地形通过率较高, 迁到 MuJoCo 后大幅掉点. 排除观测与动力学后, 定位到地形几何两端不一致.

三次尝试
  1. 第一次: 用高度图。MuJoCo 对高度图做双线性插值, 训练端的垂直墙在此被插成一格宽的斜坡, 无法对齐训练端的锐利边界.
  2. 第二次: 用网格。改用网格三角面, 沿用训练端"保锐利边"参数. 数字看似对齐 (gap 通过率 0.45 → 0.72, 与训练端 0.72 一致). 但落球验证发现小球悬停在石块上方 13–30 cm: MuJoCo 对非凸网格默认取整体凸包做碰撞, 跑酷的不平整地形被一个大顶盖罩住, gap 凹陷亦被凸包填实, 真实失败被掩盖. 该批"四地形全过"数据全部作废.
  3. 第三次: 逐块重建。部署端用 numpy 重放训练端的放置过程, 将每块石/桥/凹陷的位置与尺寸输出为 JSON; MuJoCo 端读 JSON 直接拼 box, 绕开网格与凸包. 关键细节: 训练端放置时带有种子级抖动 (固定 seed 下可复现, 非真随机), 且抖动混用了两套不同的库; 旧脚本只对上其中一套, 摆位整体偏移. 此版严格按训练端顺序走完两套库, 位置才完全一致.
最终修复

对比脚本验证: 四地形几何 max 误差全 0.000, 训练端与部署端字节级一致. 同期修复三个细项: 格子与顶点 off-by-one 错位, 桥位置偏半个 gap, 地形高度配置参数被覆盖.

5.3 学生深度相机姿态错配 — 视野始终朝向脚下 ✓ 已修

现象

student 策略迁入 MuJoCo, 起步即栽倒, 无法越过第一块石头. 任何速度指令都不响应. 同 ckpt 的 teacher 在同地形 100% 通过, student 直接 0 通过.

真因

配置文件写"相机俯角 70°", 字面理解为接近垂直俯视. 但训练端代码里有一步隐藏操作: 算完相机姿态后, 将其中一项翻转正负号. 该步执行后, 相机实际仅下倾 20°, 视野落在前方 3-5 m 地面.

部署代码未跟进此步, 按字面 70° 装相机, 实际接近垂直俯视, 仅能看到机身前 12 cm 一小片地面. 网络训练时见"远视野", 部署时输入"近脚下视野", 两套画面完全错位. 输出失常, actor 不敢迈步.

修复

部署不再字面采用"70°", 改为完整复现训练端的相机姿态计算 (含翻转正负号步骤), 再转成 MuJoCo 的相机坐标格式. 验收: 单帧渲染, 视野中心应落在前方 3-5 m, 而非脚下 0.5 m.

效果

student 在 4 个 parkour 地形: 修前 0 / 4 通过 → 修后 3 / 4 完整穿越. 机身高度 0.27-0.31 m 与训练端 0.26-0.34 m 接近, 步态恢复正常. 是项目中"配置字面值 ≠ 实际行为"最典型的一例.

6其他坑总览 (33 项)

除上面 3 例, 整个项目还积了大概 33 项 silent bug, 按层分类:

📐
7
几何 / 接触
👁️
7
观测 pipeline
🗃️
1
运行时 cache
📏
7
Metric pipeline
⏱️
4
测量窗口
🔀
7+
cfg drift
分类条数典型例
几何 / 接触 7 <mesh> 自动凸包 → 浮空 wedge / <hfield> off-by-one / per-box 重建避 wedge
观测 pipeline 7 raycast miss token 符号反 / 相机 pitch 70° 实际 20° / depth buffer 旧帧 1 cycle 延迟
运行时 cache 1 friction cache 启动后不更新, CLI 覆盖 model 没覆盖 Python 端
Metric pipeline 7 regex 缺正号丢行 / pass 阈值 cliff 漏算 / auto-reset 跨 episode 污染
测量窗口 4 post-goal fall 拖死指标 / vx_mean plateau-stuck 时误读为"在走"
训练 / 部署 cfg drift 7+ DR 漏抄 (质心扰动紧 10× / 电机增益注释掉) / hist_encoding 训练动态部署硬编码 / hscale 三层取整