目录
- 目录
- 一、ROS1和RO2之间的桥接概述
- 二、桥接流程
- 三、ROS 1 talker -> ROS 2 listener
- 四、ROS 2 talker -> ROS 1 listener
- 五、ROS 2 拍摄图像 -> ROS 1 显示图像
- 六、传输Service
- 七、仅桥接选定的主题和服务
- 八、参数化服务质量
一、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 echo
、rostopic list
和rqt
这些工具也会看到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