【ROS2概念】系列(十四)——ROS 1 和 ROS 2 之间的桥接通信

目录

一、ROS1和RO2之间的桥接概述

ROS2提供了一个ROS2 package,这个包提供了一个桥(bridge),可以在 ROS 1 和 ROS 2 之间交换消息。

该桥目前在 C++ 中实现,因为当时 ROS 2 的 Python API 尚未开发。因此,它的支持仅限于桥编译时可用的消息/服务类型。

目前ros1_bridge这个包的功能有限,还不提供python实现,预构建 ROS 2 二进制文件提供的桥包括对通用 ROS 接口(消息/服务)的支持,仅支持ros2_common_interfaces中列出的通讯类型和tf2_msgs

如果想使用自定义类型的ros1_bridge,则必须在单独的 ROS 1 和 ROS 2 工作区中构建自定义类型后,从源代码构建ros1_bridge

出于效率原因,只有当匹配的发布者-订阅者对在ros1_bridge的任一侧都处于活动状态时,才会桥接topic。因此,如果没有其他订阅者存在,使用命令行工具ros2 topic echo <topic-name>不起作用,但会失败并显示错误消息Could not determine the type for the passed topic,因为dynamic_bridge尚未桥接topic。

作为解决方法,可以明确指定topic类型ros2 topic echo <topic-name> <topic-type>,这会触发topic的桥接,因为该echo命令表示必要的订阅者。

但在 ROS 1 端rostopic echo没有明确指定topic类型的选项。因此,如果没有其他订阅者,它不能与ROS2的dynamic_bridge一起使用。作为替代方案,可以使用ros2 run ros1_bridge dynamic_bridge --bridge-all-2to1-topics选项把所有 ROS 2的topic桥接到 ROS 1,以便即使没有匹配的 ROS 1 订阅者,rostopic echorostopic listrqt这些工具也会看到topic。运行ros2 run ros1_bridge dynamic_bridge -- --help以获得更多选项。

注意,ROS2官方提示目前ros1_bridge已经存在的一些问题:

  • 可能需要 ros2 run ros1_bridge dynamic_bridge --bridge-all-topics 才能正确桥接。 经过测试并报告说,当至少一种自定义消息类型在 ROS 2 中发布并在 ROS 1 中订阅时,--bridge-all-topics是必需的。还有非正式地报告说,在相同条件下,内置消息类型需要--bridge-all-topics选项
  • 最后ros1_bridge一旦与 ROS 1 主服务器建立了映射,就可以在没有 --bridge-all-topics的情况下重新运行ros1_bridge,以便有选择地桥接主题。 但是,这不能保证。

二、桥接流程

桥接过程至少需要开启四个终端:

Terminal 1 Terminal 2 Terminal 3 Terminal 4
ROS环境变量 source ros1 source ros1 source ros1, source ros2 source ros2
命令 roscore 运行你需要使用的ros1的包 export ROS_MASTER_URI=http://localhost_IP:11311
ros2 run ros1_bridge dynamic_bridge
运行你需要使用的ros2的包

注意:当运行这些demo时,确保仅提供指定ROS版本的环境变量。如果在某些节点中有两个ROS工作区,将收到错误消息。

三、ROS 1 talker -> ROS 2 listener

3.1 运行命令

Terminal 1 Terminal 2 Terminal 3 Terminal 4
ROS环境变量 source ros1 source ros1 source ros1, source ros2 source ros2
命令 roscore rosrun rospy_tutorials talker export ROS_MASTER_URI=http://localhost_IP:11311
ros2 run ros1_bridge dynamic_bridge
ros2 run demo_nodes_cpp listener

首先启动roscore(左上角),接着运行自己的ROS1节点(左下角),ROS 1 节点开始将发布的消息打印到控制台。

然后启动ros1_bridge(右上角),它将监视可用的 ROS 1 和 ROS 2 主题,一旦检测到匹配的主题,它就会开始桥接关于该主题的消息。ros1_bridge开始定期输出 ROS 1 和 ROS 2 中当前可用的主题。

最后运行自己的ROS2节点(右下角),ROS 2 节点开始将收到的消息打印到控制台。

3.2 输出结果

在桥接的过程中,Terminal 3(右上角)有一行说明该topic的bridge已创建:

created 1to2 bridge for topic '/chatter' with ROS 1 type 'std_msgs/String' and ROS 2 type 'std_msgs/String'

在停止了 talker 或 listener 中的任何一个,就会有一行表明桥已被拆除:

removed 1to2 bridge for topic '/chatter'

四、ROS 2 talker -> ROS 1 listener

4.1 运行命令

Terminal 1 Terminal 2 Terminal 3 Terminal 4
ROS环境变量 source ros1 source ros1 source ros1, source ros2 source ros2
命令 roscore rosrun roscpp_tutorials listener export ROS_MASTER_URI=http://localhost_IP:11311
ros2 run ros1_bridge dynamic_bridge
ros2 run demo_nodes_py talker

首先启动roscore(左上角),接着运行自己的ROS2节点(左下角),ROS 2 节点开始将发布的消息打印到控制台。

然后启动ros1_bridge(右上角),它将监视可用的 ROS 1 和 ROS 2 主题,一旦检测到匹配的主题,它就会开始桥接关于该主题的消息。ros1_bridge开始定期输出 ROS 1 和 ROS 2 中当前可用的主题。

最后运行自己的ROS1节点(右下角),ROS 1 节点开始将收到的消息打印到控制台。

4.2 输出结果

在桥接的过程中,Terminal 3(右上角)有一行说明该topic的bridge已创建:

created 2to1 bridge for topic '/chatter' with ROS 2 type 'std_msgs/String' and ROS 1 type 'std_msgs/String'

在停止了 talker 或 listener 中的任何一个,就会有一行表明桥已被拆除:

removed 2to1 bridge for topic '/chatter'

五、ROS 2 拍摄图像 -> ROS 1 显示图像

ros1_bridge也可以传输大数据消息,如图像数据。

ROS 2 节点发布相机图像,ROS 1 使用rqt_image_view在 GUI 中渲染图像。

5.1 运行命令

Terminal 1 Terminal 2 Terminal 3 Terminal 4
ROS环境变量 source ros1 source ros1 source ros1, source ros2 source ros2
命令 roscore rqt_image_view /image export ROS_MASTER_URI=http://localhost_IP:11311
ros2 run ros1_bridge dynamic_bridge
ros2 run image_tools cam2image

首先启动roscore(左上角),接着运行自己的ROS1节点(左下角)。

然后启动ros1_bridge(右上角),它将监视可用的 ROS 1 和 ROS 2 主题,一旦检测到匹配的主题,它就会开始桥接关于该主题的消息。ros1_bridge开始定期输出 ROS 1 和 ROS 2 中当前可用的主题。

最后运行自己的ROS2节点(右下角)。

5.2 输出结果

六、传输Service

在这个例子中,我们将桥接来自 ros/roscpp_tutorials的服务 TwoInts和来自 ros2/roscpp_examples 的 AddTwoInts

在构建时,ros1_bridge 会查找所有已安装的 ROS 和 ROS2 服务。通过比较请求和响应中的包名称、服务名称和字段来匹配找到的服务。如果 ROS 和 ROS2 服务中的所有名称都相同,则将创建网桥。也可以通过创建包含相应服务名称的 yaml 文件来手动配对服务。

为了使这个示例正常运行,请确保在构建 ros1_bridge 时系统上安装了 roscpp_tutorials 包并且环境设置正确。

6.1 运行命令

Terminal 1 Terminal 2 Terminal 3 Terminal 4
ROS环境变量 source ros1 source ros1 source ros1, source ros2 source ros2
命令 roscore rosrun roscpp_tutorials add_two_ints_server export ROS_MASTER_URI=http://localhost_IP:11311
ros2 run ros1_bridge dynamic_bridge
ros2 run demo_nodes_cpp add_two_ints_client

首先启动roscore(左上角),接着运行自己的ROS1节点(左下角)。

然后启动ros1_bridge(右上角),它将监视可用的 ROS 1 和 ROS 2 服务,一旦检测到匹配的服务,它就会开始桥接关于该服务的消息。ros1_bridge开始定期输出 ROS 1 和 ROS 2 中当前可用的服务。

最后运行自己的ROS2节点(右下角)。

6.2 输出结果

七、仅桥接选定的主题和服务

ros1_bridge通过配置文件可以选择性桥接自己需要的主题和服务。

ros1_bridge包使用dynamic_bridge节点来桥接所有主题和服务,使用parameter_bridge节点通过ROS1的参数服务器来选择桥接哪些主题和服务。

桥接所有主题和服务
ros2 run ros1_bridge dynamic_bridge

通过ROS1的参数服务器来选择桥接指定的主题和服务
ros2 run ros1_bridge parameter_bridge

注意:service的bridge是单向的,必须相应地使用services_2_to_1桥接 ROS 2 -> ROS 1 和services_1_to_2来桥接 ROS 1 -> ROS 2 的service。

例如,使得主题/chatter时双向桥接的,而服务/add_two_ints service仅从 ROS 2 -> ROS 1,可以创建如下配置文件bridge.yaml

topics:
  -
    topic: /chatter  # Topic name on both ROS 1 and ROS 2
    type: std_msgs/msg/String  # Type of topic to bridge
    queue_size: 1  # Queue size
services_2_to_1:
  -
    service: /add_two_ints  # ROS 1 service name
    type: roscpp_tutorials/TwoInts  # The ROS 1 service type name

7.1 运行命令

Terminal 1 Terminal 2 Terminal 3 Terminal 4 Terminal 5 Terminal 6
ROS环境变量 source ros1 source ros1 source ros1 source ros2 source ros2 source ros2
命令 roscore rosparam load bridge.yaml;
rosrun rospy_tutorials talker
rosrun roscpp_tutorials add_two_ints_server ros2 run ros1_bridge parameter_bridge ros2 run demo_nodes_cpp listener ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 1, b: 2}"

首先启动roscore,接着加载 bridge.yaml 配置文件,然后启动 talker和server。

启动ros1_bridge中的parameter_bridge,日志显示它正在为主题和服务创建桥梁,如果一切顺利,就能够调用该服务并从 ROS 2 收听 ROS 1 talker。

对于ROS2的listener,这时应该输出I heard: [hello world ...]带有时间戳的文本。

对于ROS2的client,这时应该输出example_interfaces.srv.AddTwoInts_Response(sum=3)

八、参数化服务质量

ROS 2 优于 ROS 1 的一个优势是可以为每个主题定义不同的服务质量设置。

parameter_bridge 也可以通过ROS 1的参数配置文件修改ROS2相应的话题的服务质量(Qos)。

ROS 1 中的/tf_static话题用来描述不同静态坐标系的变换关系,在ROS1中只会发布一次,若ROS2节点需要该数据,可以通过ROS 2 中parameter_bridge设置Qos中的history参数来获取数据,该/tf_static的主题配置为:

topics:
  -
    topic: /tf_static
    type: tf2_msgs/msg/TFMessage
    queue_size: 1
    qos:
      history: keep_all
      durability: transient_local

所有其他 QoS 选项(如https://docs.ros.org/en/foxy/Concepts/About-Quality-of-Service-Settings.html中所述)均可用:

topics:
  -
    topic: /some_ros1_topic
    type: std_msgs/msg/String
    queue_size: 1
    qos:
      history: keep_last  # OR keep_all, then you can omit `depth` parameter below
      depth: 10  # Only required when history == keep_last
      reliability: reliable  # OR best_effort
      durability: transient_local  # OR volatile
      deadline:
          secs: 10
          nsecs: 2345
      lifespan:
          secs: 20
          nsecs: 3456
      liveliness: liveliness_system_default  # Values from https://design.ros2.org/articles/qos_deadline_liveliness_lifespan.html, eg. LIVELINESS_AUTOMATIC
      liveliness_lease_duration:
          secs: 40
          nsecs: 5678

请注意,该qos部分可以完全省略,未设置的选项保留为默认值。

参考:
ros1_bridge官方:https://github.com/ros2/ros1_bridge
ros1_bridge无法建立通讯解决办法:https://blog.csdn.net/weixin_37669024/article/details/122348311
ros1_bridge运行结果不成功,报错No executable found:https://blog.csdn.net/wsc820508/article/details/81408251

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容