引言
仿真在机器人开发中有三个不可替代的用途:在真机之前验证控制与规划逻辑、做大规模随机化回归测试(1000 次抓取比 10 次真机测试信息量大得多)、以及为强化学习提供并行环境。它不能替代真机,但能大幅降低真机上暴露低级错误的概率。
选型的现实是:Gazebo Classic 已于 2025 年 1 月结束支持(EOL),新项目应该用 gz-sim(Gazebo Harmonic 及之后)或 Isaac Sim。三者的定位差异明显:gz-sim 是 ROS 生态的原生选择、开源、物理精度中等、CPU 为主;Isaac Sim 基于 Omniverse 与 PhysX 5,GPU 加速、视觉逼真、支持大规模并行环境,但依赖 NVIDIA 硬件且是专有许可。
工程上的核心难点是 sim-to-real 差距。差距有四个主要来源:物理参数不准(摩擦、刚度、阻尼)、执行器模型简化(真实电机有延迟、饱和、齿隙)、传感器噪声模型失真(仿真相机无噪点、IMU 无零偏漂移)、以及接触模型的离散化误差。前两者影响控制与规划策略的迁移,后两者影响感知与状态估计策略的迁移。
本文按「引擎对比 → 描述格式 → 时间步与求解器 → 接触与摩擦 → 传感器仿真 → 并行与加速 → 域随机化 → sim-to-real 实践 → 工程流程」的顺序展开,给出可直接使用的参数取值与配置片段。
目录
- 引擎对比与选型
- URDF、SDF 与 USD 三种描述格式
- 时间步、求解器与数值稳定性
- 接触、摩擦与关节建模
- 传感器仿真与噪声模型
- 并行仿真与 GPU 加速
- 域随机化与课程学习
- sim-to-real:差距来源与对策
- 仿真驱动的开发流程
1. 引擎对比与选型
三个主流选择的能力边界很清楚,选型主要看「要验证什么」。
Gazebo Classic(gazebo 11,2025-01 EOL):
物理:ODE / Bullet / DART 可选
优势:ROS1/ROS2 集成最成熟、插件生态大
劣势:单线程物理、视觉渲染差、已停止维护
结论:新项目不要用;存量项目应规划迁移
gz-sim(Gazebo Harmonic / Ionic,原 Ignition):
物理:DART 为主(也有 Bullet、TPE)
优势:ROS2 原生集成、模块化、长期维护(LTS 版本 5 年)
劣势:CPU 物理、大规模并行受限、视觉中等
结论:通用 ROS2 开发的首选
Isaac Sim(4.x,基于 Omniverse + PhysX 5):
物理:PhysX 5(GPU 加速、支持大规模并行)
优势:视觉逼真(RTX 光线追踪)、数千并行环境、合成数据生成
劣势:依赖 NVIDIA GPU(RTX 系列)、专有许可、学习曲线陡
结论:强化学习训练、合成数据、视觉算法验证的首选
MuJoCo(开源,DeepMind 维护):
物理:软约束接触模型,精度与速度平衡好
优势:接触稳定、适合腿式与操作、MJX 支持 GPU 并行
劣势:无场景渲染生态、ROS 集成弱
结论:控制算法研究与腿式机器人首选
| 引擎 | 物理精度 | 并行能力 | 视觉质量 | ROS 集成 | 适用 |
|---|---|---|---|---|---|
| gz-sim | 中 | 低(单实例) | 中 | 最好 | 通用 ROS2 开发 |
| Isaac Sim | 高 | 极高(数千环境) | 最好 | 好 | RL、合成数据 |
| MuJoCo | 高(接触) | 高(MJX) | 无 | 弱 | 控制研究 |
| Gazebo Classic | 中 | 低 | 差 | 最好 | 存量项目 |
2. URDF、SDF 与 USD 三种描述格式
三种格式的抽象层次不同,混用是常见困惑来源。
URDF(Unified Robot Description Format):
描述:单个机器人的运动学与动力学(连杆、关节、惯量、碰撞体)
局限:不能描述闭链、不能描述场景、不支持多机器人
用途:ROS2 的标准机器人描述,MoveIt 与 ros2_control 都用它
SDF(Simulation Description Format):
描述:完整场景(机器人 + 环境 + 光照 + 传感器 + 插件)
优势:支持闭链、支持多机器人、可嵌套
用途:gz-sim 的原生格式,URDF 会被转换成 SDF 加载
USD(Universal Scene Description):
描述:Pixar 开发的场景描述,支持分层、引用、变体
优势:工业级场景管理、支持物理与材质、支持大规模组合
用途:Isaac Sim 的原生格式,Omniverse 的基础
<!-- URDF 的关键元素:惯量必须真实,否则动力学仿真失真 -->
<link name="upper_arm">
<inertial>
<origin xyz="0.15 0 0" rpy="0 0 0"/>
<mass value="1.85"/>
<inertia ixx="0.0123" ixy="0" ixz="0"
iyy="0.0281" iyz="0" izz="0.0256"/>
</inertial>
<collision>
<!-- 碰撞体用简化几何,不要用高精度网格 -->
<origin xyz="0.15 0 0" rpy="0 0 0"/>
<geometry><cylinder radius="0.035" length="0.3"/></geometry>
</collision>
<visual>
<origin xyz="0.15 0 0" rpy="0 0 0"/>
<geometry><mesh filename="package://arm/meshes/upper_arm.dae"/></geometry>
</visual>
</link>
两个实践要点:碰撞体与视觉网格分离——碰撞用圆柱、球、凸包等简化几何(快几个数量级),视觉用精细网格(好看);惯量必须用 CAD 计算的真实值,随手填的惯量会让仿真动力学完全失真,而且这种失真在慢速运动时看不出来,高速时才暴露。
3. 时间步、求解器与数值稳定性
物理仿真的时间步与求解器迭代次数是精度与速度的直接权衡。
时间步(time step):
gz-sim 默认 1 ms(max_step_size = 0.001)
接触密集场景(抓取、堆叠)建议 0.5 ms 甚至 0.25 ms
经验规则:时间步 < 系统最小时间常数的 1/10
机械臂关节刚度高时最小时间常数约几毫秒
求解器迭代次数(iterations):
ODE 默认 50,DART 默认 100
堆叠物体需要更多(200~500),否则会穿透或抖动
代价:迭代次数翻倍,物理计算时间约翻倍
实时因子(RTF, Real Time Factor):
RTF = 仿真时间 / 墙钟时间
RTF < 1 表示仿真比真实慢,开发效率下降
gz-sim 单实例复杂场景 RTF 常在 0.3~0.8
<!-- gz-sim 的物理配置(SDF 片段) -->
<physics name="1ms" type="dart">
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
<real_time_update_rate>1000</real_time_update_rate>
<dart>
<collision_detector>bullet</collision_detector>
<solver>
<solver_type>dantzig</solver_type>
<max_contacts>100</max_contacts>
</solver>
</dart>
</physics>
数值不稳定的典型表现是「物体自己抖动」「接触后弹飞」「关节缓慢漂移」。对策按优先级:减小时间步 → 增加求解器迭代 → 提高接触刚度与阻尼(但要避免过刚导致爆炸)→ 简化碰撞体几何。
4. 接触、摩擦与关节建模
接触模型是 sim-to-real 差距的最大来源之一,必须显式建模与调参。
接触模型的两个层次:
1. 接触力模型(法向)
弹簧-阻尼(Kelvin-Voigt):F_n = k·δ + d·δ̇
k 为接触刚度,d 为阻尼
典型值:k = 1e5 ~ 1e7 N/m,d = 10 ~ 1000 N·s/m
k 太大 → 数值爆炸;k 太小 → 物体陷入地面
2. 摩擦模型(切向)
库仑摩擦:F_t ≤ μ·F_n
μ 的典型值:
橡胶-纸:0.5~0.7
橡胶-金属:0.6~0.9
金属-金属:0.15~0.3
塑料-塑料:0.3~0.4
注意:静摩擦与动摩擦应分开设置(gz-sim 支持 mu/mu2)
<!-- 接触与摩擦参数 -->
<surface>
<friction>
<ode>
<mu>0.8</mu> <!-- 静摩擦系数 -->
<mu2>0.8</mu2> <!-- 第二方向摩擦系数(各向异性时不同) -->
</ode>
</friction>
<contact>
<ode>
<kp>1e6</kp> <!-- 接触刚度 -->
<kd>100</kd> <!-- 接触阻尼 -->
<max_vel>0.01</max_vel> <!-- 穿透修正的最大速度 -->
<min_depth>0.001</min_depth> <!-- 允许穿透深度 -->
</ode>
</contact>
</surface>
关节建模要包含真实电机的特性,否则控制策略迁移会失败:
关节模型应包含的要素:
1. 力矩上限(effort limit)——URDF 的 <limit effort>
2. 速度上限——<limit velocity>
3. 粘滞摩擦(viscous friction)——与速度成正比
4. 库仑摩擦(Coulomb friction)——与速度方向相反,常值
5. 转子惯量折算(rotor inertia)——通过减速比平方折算到关节侧
6. 控制延迟(1~5 ms)——真实电机与通信的延迟
gz-sim 的 JointFriction 插件可配置前四项
延迟需要用额外的插件或在控制器侧模拟
5. 传感器仿真与噪声模型
仿真传感器「太干净」是 sim-to-real 失败的常见原因。所有仿真传感器都应加噪声。
需要加噪声的传感器与典型噪声模型:
1. IMU
陀螺零偏:随机游走,典型 0.001~0.01 rad/s/√Hz
加计零偏:0.01~0.1 m/s²/√Hz
白噪声:陀螺 0.0005 rad/s,加计 0.005 m/s²
还要加量化误差与刻度因子误差
2. 深度相机
深度噪声 ∝ z²(见视觉与抓取一篇的误差公式)
边缘飞点、无效值(0 或 NaN)
建议在仿真中按真实相机的误差曲线注入
3. 激光雷达
测距噪声 1~3 cm
反射率导致的丢点(黑色物体)
运动畸变(真实雷达有扫描时间,仿真常忽略)
4. 轮式编码器
量化误差、轮径误差、打滑
<!-- gz-sim 的 IMU 传感器与噪声 -->
<sensor name="imu" type="imu">
<always_on>true</always_on>
<update_rate>200</update_rate>
<imu>
<angular_velocity>
<x><noise type="gaussian">
<mean>0</mean><stddev>0.0005</stddev>
<bias_mean>0.0001</bias_mean><bias_stddev>0.00001</bias_stddev>
</noise></x>
</angular_velocity>
<linear_acceleration>
<x><noise type="gaussian">
<mean>0</mean><stddev>0.005</stddev>
</noise></x>
</linear_acceleration>
</imu>
</sensor>
噪声参数不应凭感觉填,而应从真实传感器的数据手册或 Allan 方差分析得到。用一个真实的 IMU 静止采集 2 小时做 Allan 方差,能直接读出零偏不稳定性、随机游走等参数,填进仿真即可获得接近真实的噪声。
6. 并行仿真与 GPU 加速
强化学习与大规模回归需要数百到数千个并行环境,这是 Isaac Sim 与 MuJoCo MJX 的核心优势,其训练侧的工程问题与分布式训练 有不少共通之处。
并行策略对比:
gz-sim:单实例单进程,多实例靠起多个进程(内存开销大)
实测:16 个实例在 32 核机器上 RTF 约 0.2~0.4
适用:回归测试(几百次)、不需要实时性
Isaac Sim:单 GPU 上数千环境并行(PhysX 5 GPU 管线)
实测:4096 个 Franka 环境在 RTX 4090 上约 20000~50000 steps/s
适用:RL 训练、大规模域随机化
MuJoCo MJX:JAX 实现,GPU/TPU 上并行
实测:4096 环境在 A100 上可达 100 万 steps/s(简单场景)
适用:控制研究、腿式机器人
# Isaac Lab(原 Isaac Gym)的并行环境骨架
from isaaclab.envs import ManagerBasedRLEnv
from isaaclab.envs import ManagerBasedEnvCfg
class FrankaReachCfg(ManagerBasedEnvCfg):
scene = SceneCfg(num_envs=4096, env_spacing=2.5)
# ... 观测、动作、奖励、终止条件配置
env = ManagerBasedRLEnv(cfg=FrankaReachCfg())
obs, _ = env.reset()
for step in range(1000):
actions = policy(obs) # 4096 个环境同时推进一步
obs, reward, terminated, truncated, info = env.step(actions)
并行仿真的关键约束是显存与内存。4096 个环境的场景资产、状态缓冲、渲染缓冲都会占用大量显存。经验上 RTX 4090(24 GB)可承载约 4096 个简单操作任务环境,复杂场景降到 1024。环境数不足时增加随机化维度比增加环境数更有价值。
7. 域随机化与课程学习
域随机化(Domain Randomization)通过在训练时随机化物理与视觉参数,让策略对参数不确定性鲁棒,是 sim-to-real 的核心手段。
随机化维度(按收益排序):
1. 物理参数
摩擦系数:±30%
质量与惯量:±20%
关节阻尼与摩擦:±50%
接触刚度:一个数量级内随机
执行器延迟:1~5 ms 随机
2. 传感器噪声
噪声标准差:0.5~2 倍标称值
零偏:随时间随机游走
相机:曝光、白平衡、噪声、模糊
3. 视觉外观(视觉策略必需)
纹理、颜色、光照方向与强度、背景
相机位置与角度微扰
4. 任务参数
目标位置、物体尺寸与质量、初始位姿
课程学习(Curriculum Learning):
从简单场景开始(物体在中心、无干扰)
逐步增加难度(物体偏移、堆叠、动态障碍)
判据:当前难度的成功率超过阈值(如 80%)再升难度
随机化范围的确定要靠真机标定:先测量真实参数的分布(如实际摩擦系数的范围),再据此设定随机化区间。过大的随机化范围会降低策略在标称工况下的性能,因此范围不是越大越好。
8. sim-to-real:差距来源与对策
差距来源有四类,对策各不相同。
来源 1:物理参数不准
表现:策略在仿真中稳定,真机上振荡或打滑
对策:参数辨识(用真机数据拟合摩擦与惯量)、域随机化
优先级:高
来源 2:执行器模型简化
表现:真机响应比仿真慢、有力矩饱和、有齿隙
对策:建模延迟与饱和、辨识电机模型、控制侧加限幅
优先级:高
来源 3:传感器模型失真
表现:感知策略在真机上准确率骤降
对策:加真实噪声、用合成数据加真实背景、真机微调
优先级:中高(视觉策略必需)
来源 4:接触离散化误差
表现:抓取在仿真中成功,真机上物体被推走或滑脱
对策:减小时间步、提高求解器迭代、域随机化摩擦
优先级:中
一个实用的验证方法:在仿真中复现真机的失败案例。如果真机上某次抓取失败了,把当时的位姿、参数录下来在仿真里重放,看是否也失败。如果仿真里成功,说明仿真模型在这一点上与真实不符,可以针对性修正。这个「失败回放」流程比盲目调参数高效得多。
9. 仿真驱动的开发流程
把仿真纳入 CI 与开发流程,才能发挥它的价值。
流程建议:
1. 单元级:纯函数测试(运动学、规划、滤波)——不需要仿真,秒级
2. 组件级:单模块在仿真中跑,验证接口与数据流——分钟级
3. 集成级:完整栈在仿真中跑固定场景——5~15 分钟
4. 回归级:100~1000 次随机化场景,统计成功率——小时级(夜间跑)
5. 真机验证:只在仿真全绿后上真机
CI 集成:
用 headless 模式跑仿真(gz-sim 的 -s -r 参数、Isaac Sim 的 --headless)
断言:成功率 > 基线、无崩溃、无 NaN、周期抖动在预算内
保存失败场景的 rosbag 与仿真状态,便于复现
# gz-sim 无头模式跑回归
gz sim -s -r -v 2 world.sdf --iterations 10000
# Isaac Sim 无头模式
python train.py --headless --num_envs 1024 --episodes 500
回归测试的价值在于「防止退化」。任何改动(换规划器、调参数、升级依赖)都应先跑一遍回归,确认成功率没有下降。没有回归基线时,性能退化往往是渐进且不被察觉的,直到现场爆发。
权衡取舍
| 决策 | 选 A | 选 B |
|---|---|---|
| 引擎 | gz-sim:ROS2 通用开发 | Isaac Sim:RL、视觉、大规模 |
| 描述格式 | URDF:ROS 生态标准 | USD:Isaac Sim、复杂场景 |
| 时间步 | 1 ms:速度优先 | 0.25 ms:接触精度优先 |
| 碰撞体 | 简化几何:快 | 精确网格:准但慢 |
| 噪声 | 从数据手册填:快 | Allan 方差实测:准 |
| 随机化范围 | 窄:标称性能好 | 宽:鲁棒但保守 |
核心原则:仿真服务于具体问题。不要试图建一个「什么都像真的」的仿真,而要针对当前要验证的能力(控制稳定性?抓取成功率?感知鲁棒性?)把相关参数做准,其余简化。全保真仿真在成本上不可行,也没有必要。
常见坑清单
- 碰撞体用高精度视觉网格,物理计算慢十倍——碰撞用简化几何,视觉用精细网格。
- 惯量随手填,高速运动时动力学完全失真——从 CAD 计算真实惯量。
- 时间步 1 ms 跑抓取,物体穿透或抖动——接触密集场景降到 0.25~0.5 ms。
- 求解器迭代不足,堆叠物体互相穿透——堆叠场景迭代提到 200~500。
- 仿真传感器无噪声,感知策略迁移失败——所有传感器按真实特性加噪。
- 接触刚度过大导致数值爆炸——k 控制在 1e5~1e7,配足够阻尼。
- 忽略执行器延迟,真机上响应慢半拍——建模 1~5 ms 延迟并做域随机化。
- 域随机化范围过大,标称工况性能下降——范围依据真机标定的参数分布。
- 只用固定场景测试,上线遇到新场景全崩——回归测试必须包含随机化。
- 仿真全绿就直接上真机,无中间验证——真机先低速、小范围、有急停在旁验证。
小结
仿真的价值在于「安全地做大量实验」。引擎选择取决于要验证什么:ROS2 通用开发用 gz-sim,强化学习与视觉用 Isaac Sim,控制研究用 MuJoCo。物理参数、接触模型、传感器噪声这三处的保真度决定了 sim-to-real 的成败,而域随机化是把「参数不准」转化为「策略鲁棒」的关键手段。
下一步建议阅读机器人部署、实时性与安全 ,理解仿真验证与真机安全验证的边界;运动规划与轨迹优化 会讲清如何在仿真中做大规模规划回归;如果要做学习型抓取,机器人视觉与抓取 给出了仿真数据与真实数据的配合方式。
最后一句:仿真里失败一千次,好过真机上失败一次。把仿真当回归工具而不是演示工具,它的价值才能兑现。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。