1. Gazebo与ROS2双雄会:环境搭建与核心概念

说实话,每次带新人入门机器人仿真,我最怕听到的问题就是:「老师,我装了一整天,Gazebo和ROS2就是连不上。」

嗯,这确实是个坎。Gazebo Garden + ROS2 Humble这套组合,就像两个高手要联手打天下,但前提是你得先把它们的「通信协议」对好。今天我们就从零开始,把这件事彻底讲透。

1.1 为什么是Garden + Humble?

你可能要问:Gazebo版本那么多,为什么偏偏选Garden?

我个人习惯是追新不追旧。Gazebo Garden是Ignition系列的最新稳定版,底层架构大改过,性能比老版Gazebo Classic强了不止一个量级。而ROS2 Humble是长期支持版,2024年之前都不会过时。

说白了,这对组合就是「新引擎 + 稳底盘」。我在去年一个仓储机器人项目里用过这对组合,跑了三个月仿真,一次都没崩过。

核心要点: Gazebo Garden 使用 gz-sim 包,不再兼容旧版 gazebo_ros_pkgs。你需要用 ros_gz_bridge 来搭桥。

1.2 从零搭建开发环境

别急着复制粘贴命令。先理清思路:我们要装三样东西——ROS2 Humble、Gazebo Garden、以及它们之间的桥梁。

第一步:安装ROS2 Humble

这个网上教程很多,我只说几个坑:

  • 系统版本:必须用Ubuntu 22.04,别想着在20.04上硬装Humble,我试过,依赖冲突能让你怀疑人生。
  • 语言环境:记得设 LC_ALL=en_US.UTF-8,否则编译时中文乱码会把你逼疯。
  • 验证安装:跑一下 ros2 run demo_nodes_cpp talker,能看到「Hello World」就对了。

第二步:安装Gazebo Garden

这里有个小技巧:别用apt直接装,用二进制包更干净。

# 添加Gazebo官方源
sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/gazebo-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gazebo-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list

# 安装Garden
sudo apt update
sudo apt install gz-garden

装完后,终端输入 gz sim,如果能看到一个空荡荡的仿真世界,恭喜你,环境成了。

注意: 如果你之前装过Gazebo Classic,记得先卸载干净。两个版本共用同一套端口,会打架。我曾经因为这个排查了整整一下午。

第三步:安装ros_gz_bridge

这才是重头戏。ROS2和Gazebo Garden之间通信,全靠这个桥。

# 从源码编译
mkdir -p ~/ros2_humble_ws/src
cd ~/ros2_humble_ws/src
git clone https://github.com/gazebosim/ros_gz.git -b humble

# 安装依赖
cd ~/ros2_humble_ws
rosdep install --from-paths src --ignore-src -r -y

# 编译
colcon build --packages-select ros_gz_bridge

编译时间大概5-10分钟,趁这个时间喝杯咖啡。我第一次编译时忘了装 rosdep,结果报了一堆错,后来才发现是依赖没装全。

1.3 理解仿真中的坐标系

环境搭好了,但别急着跑。先搞清楚一个关键问题:坐标系怎么对齐?

Gazebo Garden用的是ENU坐标系(东-北-天),而ROS2默认是FLU坐标系(前-左-上)。你想想看,如果两个系统各说各话,机器人往「前」走,在仿真里可能就变成往「东」飘了。

坐标系 X轴 Y轴 Z轴 典型应用
ENU (Gazebo) 东 北 天 全局地图、GPS
FLU (ROS2) 前 左 上 机器人本体、传感器
NED (无人机) 北 东 地 飞行控制、IMU

我在做AGV项目时,就吃过这个亏。仿真里机器人定位明明是对的,但一接到真实里程计数据,轨迹就歪了。后来才发现是坐标系没转换。

避坑指南: 在 ros_gz_bridge 的配置文件中,显式指定坐标系转换。比如:frame_id: "base_link" 对应ROS2的FLU,child_frame_id: "world" 对应Gazebo的ENU。

1.4 时间流:仿真时间 vs 真实时间

另一个容易懵的概念是时间。Gazebo里有自己的仿真时钟,和你的系统时钟是两码事。

为什么会这样?因为仿真可以加速、减速、甚至暂停。你想想看,如果仿真时间直接绑定真实时间,那你想让机器人跑100倍速做强化学习训练,就完全不可能了。

ROS2里通过 /clock 话题来同步时间。Gazebo Garden默认会发布 /clock,ROS2节点订阅它,就能感知到仿真时间的流逝。

# 查看仿真时间
ros2 topic echo /clock

# 输出示例
---
clock:
  sec: 1234
  nanosec: 567890000

注意:如果你在仿真里用了 ros::Time::now(),它拿到的就是仿真时间,不是你的电脑时间。我有个同事没注意这点,在仿真里做延时控制,结果真实世界过了10秒,仿真里才过了2秒,整个逻辑全乱了。

1.5 通信机制:话题、服务、动作

ROS2和Gazebo之间的通信,说白了就是三个套路:

  • 话题(Topic): 单向数据流,适合传感器数据、状态发布。比如激光雷达数据从Gazebo发到ROS2。
  • 服务(Service): 请求-响应模式,适合一次性操作。比如「请加载这个模型」。
  • 动作(Action): 带反馈的长时间任务。比如「让机器人走到A点」,过程中不断汇报进度。

实际项目中,90%的场景用话题就够了。我一般这样配置桥接:

# 在 launch 文件中配置桥接
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    bridge = Node(
        package='ros_gz_bridge',
        executable='parameter_bridge',
        arguments=[
            '/lidar/points@sensor_msgs/msg/PointCloud2@gz.msgs.PointCloudWithIntensity',
            '/cmd_vel@geometry_msgs/msg/Twist@gz.msgs.Twist',
            '/odom@nav_msgs/msg/Odometry@gz.msgs.Odometry'
        ],
        output='screen'
    )
    return LaunchDescription([bridge])

格式是固定的:话题名@ROS2消息类型@Gazebo消息类型。注意方向箭头:@ 表示双向,[ 表示Gazebo到ROS2,] 表示ROS2到Gazebo。

经验之谈: 刚开始别贪多,先桥接3-5个核心话题(激光、里程计、速度指令)。等跑通了,再慢慢加。我见过有人一口气配了20个桥接,结果启动时卡死,排查了半天才发现是某个消息类型写错了。

1.6 知识体系总览

说了这么多,其实核心就一张图。我画了个SVG,帮你把整个体系串起来:

Gazebo Garden + ROS2 Humble 核心架构 ROS2 Humble • 节点 / 话题 / 服务 / 动作 • FLU坐标系 (前-左-上) • 真实时间 / 仿真时间 • 控制逻辑 / 导航 / 感知 Gazebo Garden • 物理引擎 / 传感器仿真 • ENU坐标系 (东-北-天) • 仿真时钟 / 步进控制 • 模型加载 / 场景管理 ros_gz_bridge 通信桥梁 话题映射 | 坐标系转换 | 时间同步 核心流程:ROS2发布指令 → 桥接转换 → Gazebo执行仿真 → 传感器数据返回 坐标系对齐:ENU ↔ FLU 时间同步:/clock 话题 消息映射:ROS2 msg ↔ Gazebo msg

这张图我建议你保存下来。每次遇到通信问题,先看看是哪个环节出了岔子——是ROS2内部的问题,还是Gazebo的问题,还是桥接没配好。定位清楚了,解决起来就快。

1.7 验证你的环境

最后,跑一个最简单的测试,确保一切正常:

# 终端1:启动Gazebo空世界
gz sim empty.sdf

# 终端2:启动桥接
ros2 run ros_gz_bridge parameter_bridge /clock@rosgraph_msgs/msg/Clock@gz.msgs.Clock

# 终端3:查看时间同步
ros2 topic echo /clock

如果你能看到 /clock 话题在不断更新,说明ROS2和Gazebo已经成功「握手」了。这时候,你可以自豪地说:环境搭建完成!

小技巧: 如果 /clock 没数据,先检查Gazebo是否在运行。有时候你关了仿真窗口,但后台进程没退出,用 ps aux | grep gz 查一下,手动kill掉再重试。

嗯,到这里,第一章的核心内容就差不多了。环境搭好了,坐标系、时间流、通信机制也理清了,接下来就可以真正开始写你的第一个仿真机器人了。

可可精品资料库