3. Gazebo 仿真环境搭建

好,咱们进入正题。Gazebo 这个工具,说白了就是机器人界的「物理沙盒」。你写好的算法,不敢直接往真机上跑吧?那就先在 Gazebo 里摔打摔打。我当年第一次用 Gazebo 时,差点被它的依赖库搞崩溃——嗯,今天我就把这些坑给你填平。

3.1 安装与配置:别让环境卡住你

我个人习惯用 Gazebo 11(搭配 ROS Noetic)。为什么?稳定。Gazebo 9 太老,Gazebo 13 又太新,社区支持还没跟上。

核心安装命令(Ubuntu 20.04 + ROS Noetic):

# 1. 安装 Gazebo 11
curl -sSL http://get.gazebosim.org | sh

# 2. 安装 ROS 集成包
sudo apt install ros-noetic-gazebo-ros-pkgs ros-noetic-gazebo-ros-control

# 3. 验证安装
gazebo --version  # 应该显示 Gazebo 11.x.x

我曾经踩过的坑: 直接 sudo apt install gazebo11 会装到一半卡住。因为 Gazebo 的官方源在国内访问很慢。建议用 curl 脚本安装,它会自动选择最快的镜像。

装完后,跑一下 gazebo 命令。如果看到一只小海龟在空荡荡的世界里,恭喜你,环境通了。如果报错 libGL error,别慌——这是显卡驱动问题。加个环境变量就好:

export LIBGL_ALWAYS_SOFTWARE=1
gazebo

你想想看,一个仿真器连图形界面都打不开,后面还怎么玩?所以这一步必须稳。

3.2 理解模型文件:SDF vs URDF

这是很多新手懵圈的地方。Gazebo 里到底用 SDF 还是 URDF?我直接给你结论:

特性 URDF SDF
起源 ROS 原生格式 Gazebo 原生格式
支持多机器人 ❌ 只能描述单个机器人 ✅ 支持世界、多机器人
物理属性 需要额外扩展 内置完整物理参数
闭链机构 ❌ 不支持 ✅ 支持

我的建议: 如果你只是做单个机器人的运动学仿真,用 URDF 就够了。但如果你要搞多机器人协同、复杂环境交互——老老实实用 SDF。我在项目中遇到过用 URDF 描述四足机器人,结果因为闭链问题折腾了两天,换成 SDF 半小时搞定。

3.2.1 URDF 快速示例

一个最简单的两轮机器人 URDF:

<robot name="simple_robot">
  <link name="base_link">
    <visual>
      <geometry><box size="0.4 0.3 0.1"/></geometry>
    </visual>
    <collision>
      <geometry><box size="0.4 0.3 0.1"/></geometry>
    </collision>
  </link>

  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0 -0.2 0" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
  </joint>
</robot>

注意看,URDF 里 <visual> 和 <collision> 是分开写的。说白了,视觉模型可以很花哨,但碰撞模型一定要简单——这能大幅提升仿真速度。

3.2.2 SDF 的优势

SDF 文件可以包含整个世界的信息。比如地面、光照、甚至重力参数:

<sdf version="1.6">
  <world name="my_world">
    <include>
      <uri>model://ground_plane</uri>
    </include>
    <include>
      <uri>model://sun</uri>
    </include>
    <gravity>0 0 -9.81</gravity>
  </world>
</sdf>

小技巧: 用 gz sdf -p your_model.sdf 可以打印出 SDF 文件的完整结构。调试时特别好用。

3.3 创建简单世界:从空白到有料

咱们来搭一个测试用的世界。别搞太复杂,就一个地面、几堵墙、几个障碍物。

我个人习惯用 Building Editor 来画墙,但命令行方式更可控。这里给一个纯代码的世界文件:

<?xml version="1.0" ?>
<sdf version="1.6">
  <world name="test_world">
    <include>
      <uri>model://sun</uri>
    </include>
    <include>
      <uri>model://ground_plane</uri>
    </include>

    <!-- 一堵墙 -->
    <model name="wall">
      <static>true</static>
      <link name="body">
        <pose>2 0 0.5 0 0 0</pose>
        <collision name="collision">
          <geometry><box size="0.2 2 1"/></geometry>
        </collision>
        <visual name="visual">
          <geometry><box size="0.2 2 1"/></geometry>
          <material><ambient>0.8 0.2 0.2 1</ambient></material>
        </visual>
      </link>
    </model>

    <!-- 一个障碍物 -->
    <model name="obstacle">
      <static>true</static>
      <link name="body">
        <pose>-1 -1 0.25 0 0 0</pose>
        <collision name="collision">
          <geometry><cylinder radius="0.3" length="0.5"/></geometry>
        </collision>
        <visual name="visual">
          <geometry><cylinder radius="0.3" length="0.5"/></geometry>
          <material><ambient>0.2 0.8 0.2 1</ambient></material>
        </visual>
      </link>
    </model>
  </world>
</sdf>

保存为 test.world,然后运行:

gazebo test.world

你会看到一堵红墙和一个绿柱子。嗯,这就是你的第一个仿真世界。

3.4 创建机器人模型:让轮子转起来

光有世界不够,得有个能动的机器人。咱们做一个差速驱动小车,两个主动轮、一个万向轮。

这里我直接给一个完整的 URDF 文件,包含传动和控制器配置:

<robot name="diff_drive_robot">
  <link name="base_footprint">
    <visual><geometry><box size="0.001 0.001 0.001"/></geometry></visual>
  </link>

  <joint name="base_joint" type="fixed">
    <parent link="base_footprint"/>
    <child link="base_link"/>
    <origin xyz="0 0 0.05"/>
  </joint>

  <link name="base_link">
    <visual>
      <geometry><box size="0.4 0.3 0.1"/></geometry>
      <material><color rgba="0.2 0.2 0.8 1"/></material>
    </visual>
    <collision>
      <geometry><box size="0.4 0.3 0.1"/></geometry>
    </collision>
    <inertial>
      <mass value="2.0"/>
      <inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.02"/>
    </inertial>
  </link>

  <!-- 左轮 -->
  <link name="left_wheel">
    <visual>
      <geometry><cylinder radius="0.05" length="0.04"/></geometry>
      <material><color rgba="0.8 0.2 0.2 1"/></material>
    </visual>
    <collision>
      <geometry><cylinder radius="0.05" length="0.04"/></geometry>
    </collision>
    <inertial>
      <mass value="0.2"/>
      <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0002"/>
    </inertial>
  </link>

  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0 -0.2 0" rpy="-1.57 0 0"/>
    <axis xyz="0 0 1"/>
  </joint>

  <!-- 右轮(对称) -->
  <link name="right_wheel">
    <visual>
      <geometry><cylinder radius="0.05" length="0.04"/></geometry>
      <material><color rgba="0.2 0.8 0.2 1"/></material>
    </visual>
    <collision>
      <geometry><cylinder radius="0.05" length="0.04"/></geometry>
    </collision>
    <inertial>
      <mass value="0.2"/>
      <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0002"/>
    </inertial>
  </link>

  <joint name="right_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel"/>
    <origin xyz="0 0.2 0" rpy="-1.57 0 0"/>
    <axis xyz="0 0 1"/>
  </joint>

  <!-- 万向轮 -->
  <link name="caster_wheel">
    <visual>
      <geometry><sphere radius="0.03"/></geometry>
      <material><color rgba="0.2 0.2 0.2 1"/></material>
    </visual>
  </link>

  <joint name="caster_joint" type="fixed">
    <parent link="base_link"/>
    <child link="caster_wheel"/>
    <origin xyz="-0.15 0 -0.05"/>
  </joint>
</robot>

注意: 惯性参数 <inertia> 不能随便填。我曾经偷懒全填 0.001,结果机器人一启动就原地爆炸——物理引擎算出来惯性矩阵奇异,直接崩了。至少保证 ixx + iyy > izz 这个条件。

3.5 知识体系总览

下面这张图,是我梳理的本章知识脉络。你照着这个顺序学,不会乱:

Gazebo 仿真环境搭建知识体系 1. 安装与配置 2. 模型文件理解 3. 创建仿真世界 Gazebo 11 安装 ROS 集成包 环境验证 URDF 格式 SDF 格式 格式对比选择 地面与光照 障碍物摆放 物理参数设置 最终目标:可运行的 Gazebo 仿真环境 + 自定义机器人模型 安装 → 模型 → 世界 → 联调

3.6 避坑指南与个人经验

最后,分享几个我这些年攒下来的经验:

  • 模型坐标系: URDF 里 base_link 的坐标系一定要和 Gazebo 世界坐标系对齐。我见过有人把机器人放在地下半米处,结果一启动就穿模。
  • 物理引擎: Gazebo 默认用 ODE。如果你发现机器人抖动严重,试试换成 Bullet:<physics type="bullet">。我在做四足机器人时,Bullet 的稳定性明显更好。
  • 性能优化: 别把视觉模型做得太精细。一个 10 万面的 STL 文件,Gazebo 能卡成幻灯片。用 mesh 时记得简化。
  • 调试技巧: 启动 Gazebo 时加 --verbose 参数,能看到详细的日志输出。很多奇怪的问题,看日志就能找到线索。

一个小彩蛋: Gazebo 里按住 Ctrl + Shift 再拖动模型,可以精确调整位置。这个快捷键我用了三年才发现,别走我的弯路。