4. 仿真环境搭建:Gazebo与ROS2安装、基础世界文件创建
好,咱们正式开始动手了。这一章说白了就是给你的机器人搭一个「虚拟训练场」。没有仿真环境,你写的算法就只能对着空气跑,或者直接怼到真车上——嗯,后者我干过,代价是一块激光雷达的镜片。
我个人习惯把仿真环境拆成三块:ROS2 负责通信和调度,Gazebo 负责物理和渲染,世界文件 负责描述场地里有什么。这三块装好了,后面的传感器集成才有地方放。
4.1 为什么选Gazebo + ROS2?
你可能听过别的仿真器,比如 Webots、CoppeliaSim、Unity 加插件。但 Gazebo 在机器人圈子里有个不可替代的优势:它和 ROS 是原生兄弟。消息类型、TF 树、插件接口,几乎不用额外适配。
| 特性 | Gazebo Classic | Gazebo Ignition (Fortress+) | Webots |
|---|---|---|---|
| ROS2 集成度 | 高(有 ros_ign_bridge) | 原生支持 | 需 ros2_webots_bridge |
| 物理引擎 | ODE / Bullet / DART | DART / TPE | ODE 定制版 |
| 传感器仿真 | 激光、相机、IMU、声纳 | 同上 + 更精确的噪声模型 | 相机、激光、雷达 |
| 社区资源 | 非常丰富 | 增长中 | 中等 |
我建议你直接上 Gazebo Ignition Fortress 或更高版本。为什么?因为 Gazebo Classic 已经停止大版本更新了,新功能都在 Ignition 里。我在一个项目里吃过亏——用 Classic 搭了三个月的仿真,结果发现它不支持多雷达的精确时间戳同步,最后全重写了。
4.2 安装ROS2(Humble为例)
ROS2 的安装其实很机械,但有几个坑。我列一个我验证过的步骤清单,你照着走就行。
- 设置语言环境
sudo apt update sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8 - 添加ROS2源
sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update && sudo apt install curl -y sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null - 安装桌面版(推荐)
sudo apt update sudo apt install ros-humble-desktop这个包包含了 rviz2、tf2、常用消息类型。如果你硬盘吃紧,可以装
ros-humble-ros-base,但后面做传感器可视化时还得补装 rviz2,不如一步到位。 - 配置环境变量
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc小技巧: 我习惯在.bashrc里加一行export ROS_DOMAIN_ID=42。默认是 0,如果你在实验室里同时跑多台机器,容易串消息。设一个不同的 ID 能避免很多诡异问题。 - 验证安装
ros2 run demo_nodes_cpp talker # 另开终端 ros2 run demo_nodes_py listener看到 "I heard" 就说明 ROS2 活了。
4.3 安装Gazebo Ignition Fortress
ROS2 装好了,接下来是仿真核心。Gazebo Ignition 的安装比 Classic 简单,但要注意版本匹配。
sudo apt-get update
sudo apt-get install wget
sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list'
wget http://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -
sudo apt-get update
sudo apt-get install ignition-fortress
sudo apt remove gazebo* 清理干净。
装完后跑一下:
ign gazebo --version
如果输出 Ignition Fortress X.X.X,就对了。我第一次装的时候忘了加 --version,直接敲 ign gazebo,结果弹出一个空窗口,我还以为死机了——其实它在等世界文件。
4.4 安装ros_ign_bridge
ROS2 和 Gazebo 之间需要一座桥。这座桥负责把 Gazebo 里的传感器数据转成 ROS2 话题。
sudo apt install ros-humble-ros-ign-bridge
装完后你可以测试一下:
# 终端1:启动 Gazebo 空世界
ign gazebo empty.sdf
# 终端2:启动桥接
ros2 run ros_ign_bridge parameter_bridge /lidar@sensor_msgs/msg/LaserScan@ignition.msgs.LaserScan
这个命令的意思是:把 Gazebo 里的 /lidar 话题(Ignition 格式)转成 ROS2 的 LaserScan 消息。后面我们集成激光雷达时,这个命令会反复用到。
4.5 创建你的第一个世界文件
世界文件就是仿真场地的「蓝图」。它用 SDF(Simulation Description Format)描述地面、光照、物体、传感器等。我带你写一个最简版本,包含地面、一堵墙和一个箱子。
<?xml version="1.0" ?>
<sdf version="1.8">
<world name="terrain_lab">
<!-- 光照 -->
<include>
<uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Sun</uri>
</include>
<!-- 地面 -->
<include>
<uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Ground_Plane</uri>
</include>
<!-- 一堵墙 -->
<model name="wall">
<pose>2 0 0.5 0 0 0</pose>
<link name="body">
<collision name="collision">
<geometry>
<box>
<size>0.2 2.0 1.0</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>0.2 2.0 1.0</size>
</box>
</geometry>
<material>
<ambient>0.8 0.2 0.2 1</ambient>
</material>
</visual>
</link>
</model>
<!-- 一个箱子 -->
<model name="box">
<pose>-1 1 0.25 0 0 0</pose>
<link name="body">
<collision name="collision">
<geometry>
<box>
<size>0.5 0.5 0.5</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>0.5 0.5 0.5</size>
</box>
</geometry>
<material>
<ambient>0.2 0.6 0.8 1</ambient>
</material>
</visual>
</link>
</model>
</world>
</sdf>
保存为 terrain_lab.sdf,然后启动:
ign gazebo terrain_lab.sdf
你会看到一个红色墙和一个蓝色箱子。嗯,就这么简单。但别小看它——后面所有的地形感知实验,都是在这个基础上加传感器和复杂地形。
<model> 就是一个物体。物体可以有 <visual>(看得见的)和 <collision>(物理碰撞的)。这两个可以不一样——比如你可以让一个物体看起来是圆形的,但碰撞体是方形的,这样计算更快。
4.6 知识结构图
下面这张图帮你理清本章的核心逻辑。从安装到运行,每一步都依赖上一步。
4.7 常见问题与避坑
- Gazebo 启动后黑屏? 大概率是显卡驱动问题。试试
export IGN_GPU_INDEX=0,或者用ign gazebo --headless-rendering跑无头模式。 - ros_ign_bridge 连不上? 检查 ROS_DOMAIN_ID 是否一致。我曾经在两个终端里设了不同的 ID,折腾了半小时才发现。
- 世界文件加载慢? 第一次启动时 Gazebo 会从 Fuel 下载模型。你可以把常用模型缓存到本地:
ign fuel download -u <模型URI>。