ROS 2 集成
本教程介绍如何使用 ROS 2 与 Gazebo 进行通信。这种双向通信非常实用:既可以将 ROS 侧的数据(如关节状态、TF)或控制命令传递给 Gazebo,也可以反过来将 Gazebo 的数据发送到 ROS。此外,还支持在 RViz 中可视化由 Gazebo 世界仿真的机器人模型。
ros_gz_bridge
Section titled “ros_gz_bridge”ros_gz_bridge 提供了一个网络桥接,能够在 ROS 2 与 Gazebo Transport 之间交换消息。它只支持特定的消息类型,请查看此 README 确认所需的消息类型是否受支持。
使用示例可在 ros_gz_sim_demos 中找到,其中包含覆盖所有主要驱动和传感器类型的演示 launch 文件。
手动启动桥接
Section titled “手动启动桥接”可以初始化一个双向桥接,让 ROS 作为发布者、Gazebo 作为订阅者,也可以反过来。语法为 /TOPIC@ROS_MSG@GZ_MSG,其中 TOPIC 是 Gazebo 内部话题,ROS_MSG 是该话题的 ROS 消息类型,GZ_MSG 是 Gazebo 消息类型。
例如:
ros2 run ros_gz_bridge parameter_bridge /scan@sensor_msgs/msg/LaserScan@gz.msgs.LaserScanros2 run ros_gz_bridge parameter_bridge 命令用于运行 ros_gz_bridge 包中的 parameter_bridge 节点,其后指定消息要发布到的话题 /TOPIC。第一个 @ 符号分隔话题名称与消息类型,紧随其后的第一个类型就是 ROS 消息类型。
ROS 消息类型后面可以跟 @、[ 或 ] 符号,其中:
@表示双向桥接。[表示从 Gazebo 到 ROS 的桥接。]表示从 ROS 到 Gazebo 的桥接。
请查看这些 示例,了解如何建立从 ROS 到 Gazebo(以及反向)的通信连接。
也可以将 ros_gz_bridge 与 ROS Launch 配合使用,以 YAML 格式定义话题映射,在启动时交给桥接节点。
- ros_topic_name: "scan" gz_topic_name: "/scan" ros_type_name: "sensor_msgs/msg/LaserScan" gz_type_name: "gz.msgs.LaserScan" direction: GZ_TO_ROS # BIDIRECTIONAL or ROS_TO_GZ配置文件是一个 YAML 文件,定义了要桥接的 ROS 话题和 Gazebo 话题之间的映射。每一对要桥接的话题支持以下参数:
ros_topic_name:ROS 侧的话题名称。gz_topic_name:Gazebo 侧对应的话题名称。ros_type_name:该 ROS 话题的消息类型。gz_type_name:该 Gazebo 话题的消息类型。subscriber_queue:ROS 订阅者队列的大小。publisher_queue:ROS 发布者队列的大小。lazy:是否启用惰性订阅。如果没有真正的订阅者,桥接节点不会创建内部订阅者,这有助于提升性能。direction:可指定为GZ_TO_ROS、ROS_TO_GZ或BIDIRECTIONAL。
完整的有效配置文件示例见 此文件。
使用 ros_gz_bridge 包自带的 launch 文件启动桥接
Section titled “使用 ros_gz_bridge 包自带的 launch 文件启动桥接”ros_gz_bridge 包中包含一个名为 ros_gz_bridge.launch.py 的 launch 文件,可用于启动 ROS 2 与 Gazebo 之间的桥接。
下面是一个示例:
ros2 launch ros_gz_bridge ros_gz_bridge.launch.py bridge_name:=ros_gz_bridge config_file:=<path_to_your_YAML_file>使用组合(composition)启动:
ros2 launch ros_gz_bridge ros_gz_bridge.launch.py bridge_name:=ros_gz_bridge config_file:=<path_to_your_YAML_file> use_composition:=True create_own_container:=True如果已经有一个正在运行的 container,也可以在启动桥接时通过 container_name 参数传入它的名称。关于组合的更多信息,请参阅 组合。
查看 源代码中的这一段,了解该 launch 文件接受的所有参数。
QoS 覆盖:
QoS 覆盖可以通过 launch 文件的 bridge_params 参数作为额外参数传给桥接节点。示例:
ros2 launch ros_gz_bridge ros_gz_bridge.launch.py bridge_name:=ros_gz_bridge config_file:=<path_to_your_YAML_file> bridge_params:={'qos_overrides./topic_name.publisher.durability': 'transient_local', 'qos_overrides./another_topic_name.publisher.durability': 'transient_local'}传入 bridge_params 的内容可以省略以下字符:{}、空格( )、"、'。
关于使用 QoS 覆盖的更多信息,请参阅 ROS 文档。
从自定义 XML launch 文件启动桥接
Section titled “从自定义 XML launch 文件启动桥接”你可以从自定义 launch 文件启动桥接。为此提供了 <ros_gz_bridge/> 标签,可以在 XML 或 YAML launch 文件中使用。此时,参数通过该标签的属性传入。下面是一个简化示例,更完整的示例请参阅 此处:
<launch> <arg name="bridge_name" /> <arg name="config_file" /> <ros_gz_bridge bridge_name="$(var bridge_name)" config_file="$(var config_file)"> </ros_gz_bridge></launch>此时,<ros_gz_bridge> 的参数从命令行读取。这只是其中一种方式——也可以硬编码部分值,或者完全不使用命令行参数。
从自定义 Python launch 文件启动桥接
Section titled “从自定义 Python launch 文件启动桥接”下面是一个从 Python 加载桥接的简化 launch 文件示例,更完整的示例请参阅 这里:
from launch import LaunchDescriptionfrom launch.actions import DeclareLaunchArgumentfrom launch.substitutions import LaunchConfiguration, TextSubstitutionfrom ros_gz_bridge.actions import RosGzBridge
def generate_launch_description():
bridge_name = LaunchConfiguration('bridge_name') config_file = LaunchConfiguration('config_file')
declare_bridge_name_cmd = DeclareLaunchArgument( 'bridge_name', description='Name of ros_gz_bridge node' )
declare_config_file_cmd = DeclareLaunchArgument( 'config_file', description='YAML config file' )
# Create the launch description and populate ld = LaunchDescription([ RosGzBridge( bridge_name=LaunchConfiguration('bridge_name'), config_file=LaunchConfiguration('config_file'), ), ])
# Declare the launch options ld.add_action(declare_bridge_name_cmd) ld.add_action(declare_config_file_cmd)
return ld将按键发布到 ROS
Section titled “将按键发布到 ROS”下面使用 Gazebo 的 Key Publisher 插件向 ROS 发送消息。
注意: 确保所有需要的工作空间(ROS、Gazebo 和 ros_gz 等)都已 source。
首先,启动一个 ROS 与 Gazebo 之间的桥接,指定 Key Publisher 插件发送消息的话题以及消息类型,如下所示:
ros2 run ros_gz_bridge parameter_bridge /keyboard/keypress@std_msgs/msg/Int32@gz.msgs.Int32这里在 /keyboard/keypress 话题上建立了桥接,消息类型为 Int32。ROS 侧为 std_msgs/msg/Int32,Gazebo 侧为 gz.msgs.Int32。
在另一个终端中启动一个 Gazebo 世界,例如 empty.sdf:
gz sim empty.sdf然后从右上角的下拉菜单中添加 Key Publisher 插件。

在另一个终端中启动 ROS 监听器:
ros2 topic echo /keyboard/keypress该命令用于监听 /keyboard/keypress 话题上的消息。
在 Gazebo 窗口中按下键盘按键,监听器终端中应能看到接收到的数据。
接下来,可以尝试将数据从 ROS 发送到 Gazebo,或换用不同的数据类型和通信方向。
本教程的视频演示可在 YouTube 频道观看:Gazebo tutorials: ROS 2 Foxy integration。
在 RViz 中可视化
Section titled “在 RViz 中可视化”进一步,可以试试 ros_gz_sim_demos 中的演示。
对于 sdf_parser 演示,需要在 colcon 工作空间中从源码安装 ros_gz 和解析器插件 sdformat_urdf。关于 sdformat_urdf 的更多信息,请参阅 其文档。
设置 RViz 启动参数并运行演示 launch 文件:
ros2 launch ros_gz_sim_demos sdf_parser.launch.py rviz:=True在 Gazebo 中启动仿真,等待几秒钟让 TF 发布。
在另一个终端中,发送 ROS 或 Gazebo 命令让车辆绕圈行驶:
gz topic -t "/model/vehicle/cmd_vel" -m gz.msgs.Twist -p "linear: {x: 1.0}, angular: {z: -0.1}"ros2 topic pub /model/vehicle/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 5.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.1}}然后验证车辆在 Gazebo 和 RViz 中的轨迹是否一致。

关于该演示的实现细节,请参阅 ROS 2 互操作。
使用 ROS 2 仿真接口
Section titled “使用 ROS 2 仿真接口”ROS 2 仿真接口是一组用于控制和交互仿真环境的标准 ROS 2 service、message 和 action 定义。这些接口与具体的仿真器无关,不同的仿真器可以实现相同的接口,同时保持 API 一致。
Gazebo 已经实现了这些接口,支持以下操作:
- 生成和删除实体
- 控制仿真状态和时间步进
- 查询实体和世界状态
- 获取仿真器信息
完整的教程(包括每个接口的使用示例)请参阅 使用 ROS 2 仿真接口与 Gazebo 交互。