机器人仿真:Gazebo 与 Isaac Sim

仿真是机器人开发中唯一能安全做大规模回归与并行训练的手段。本文对比 Gazebo Classic、gz-sim(Harmonic)与 Isaac Sim 的架构与适用边界,讲清 URDF/SDF/USD 三种描述格式、物理引擎的时间步与求解器参数、接触与摩擦建模、传感器仿真精度、域随机化与 sim-to-real 的差距来源。

引言

仿真在机器人开发中有三个不可替代的用途:在真机之前验证控制与规划逻辑、做大规模随机化回归测试(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 实践 → 工程流程」的顺序展开,给出可直接使用的参数取值与配置片段。

目录

  1. 引擎对比与选型
  2. URDF、SDF 与 USD 三种描述格式
  3. 时间步、求解器与数值稳定性
  4. 接触、摩擦与关节建模
  5. 传感器仿真与噪声模型
  6. 并行仿真与 GPU 加速
  7. 域随机化与课程学习
  8. sim-to-real:差距来源与对策
  9. 仿真驱动的开发流程

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 方差实测:准
随机化范围窄:标称性能好宽:鲁棒但保守

核心原则:仿真服务于具体问题。不要试图建一个「什么都像真的」的仿真,而要针对当前要验证的能力(控制稳定性?抓取成功率?感知鲁棒性?)把相关参数做准,其余简化。全保真仿真在成本上不可行,也没有必要。

常见坑清单

  1. 碰撞体用高精度视觉网格,物理计算慢十倍——碰撞用简化几何,视觉用精细网格。
  2. 惯量随手填,高速运动时动力学完全失真——从 CAD 计算真实惯量。
  3. 时间步 1 ms 跑抓取,物体穿透或抖动——接触密集场景降到 0.25~0.5 ms。
  4. 求解器迭代不足,堆叠物体互相穿透——堆叠场景迭代提到 200~500。
  5. 仿真传感器无噪声,感知策略迁移失败——所有传感器按真实特性加噪。
  6. 接触刚度过大导致数值爆炸——k 控制在 1e5~1e7,配足够阻尼。
  7. 忽略执行器延迟,真机上响应慢半拍——建模 1~5 ms 延迟并做域随机化。
  8. 域随机化范围过大,标称工况性能下降——范围依据真机标定的参数分布。
  9. 只用固定场景测试,上线遇到新场景全崩——回归测试必须包含随机化。
  10. 仿真全绿就直接上真机,无中间验证——真机先低速、小范围、有急停在旁验证。

小结

仿真的价值在于「安全地做大量实验」。引擎选择取决于要验证什么:ROS2 通用开发用 gz-sim,强化学习与视觉用 Isaac Sim,控制研究用 MuJoCo。物理参数、接触模型、传感器噪声这三处的保真度决定了 sim-to-real 的成败,而域随机化是把「参数不准」转化为「策略鲁棒」的关键手段。

下一步建议阅读机器人部署、实时性与安全 ,理解仿真验证与真机安全验证的边界;运动规划与轨迹优化 会讲清如何在仿真中做大规模规划回归;如果要做学习型抓取,机器人视觉与抓取 给出了仿真数据与真实数据的配合方式。

最后一句:仿真里失败一千次,好过真机上失败一次。把仿真当回归工具而不是演示工具,它的价值才能兑现。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「机器人」更多文章

  1. 机器人实时控制与嵌入式
  2. ROS 2 通信与 QoS
  3. 足式与人形机器人运动控制