目录
- 〇、概述
- 一、自定义消息(msg)类型
- 1.1 ROS 1 和ROS 2 消息(msg)的相互关联步骤
- 1.2 为消息(msg)指定自定义映射规则
- 1.3 示例映射规则文件
- 1.4 安装映射规则文件
- 二、自定义服务(srv)类型
- 2.1 ROS 1 和ROS 2 服务(service)的相互关联步骤
- 2.2 为服务(srv)指定自定义映射规则
- 2.3 示例映射规则文件
- 2.4 安装映射规则文件
- 三、
ros1_bridge
桥接自定义接口- 3.1 工作区文件目录结构
- 3.2 编译
- 3.3 运行
- 四、从外部包定义外部包的映射规则
- 五、完整的自定义消息功能包
- 5.1 TestFoxy.msg
- 5.2 mapping_rules.yaml
- 5.3 CMakeLists.txt
- 5.4 package.xml
- 5.5 编译ros2下的custom_msgs功能包
〇、概述
使用自定义消息(msg)和服务(srv)类型作为通讯接口时,需要分别在ROS1和ROS2消息包内定义消息类型,然后在ROS2的消息包内定义yaml
映射规则文件,最后将ROS1_bridge必须用源代码重新编译,
一、自定义消息(msg)类型
1.1 ROS 1 和ROS 2 消息(msg)的相互关联步骤
ROS 1 和ROS 2 消息(msg)之间的自动映射是根据名称执行的。
第一步:
_msgs
名称结尾的 ROS 1 包与_msgs
或_msgs_interfaces
名称结尾的 ROS 2 包相关联。第二步:在ROS1和ROS2的消息(msg)包相关联后,包内具有相同名称的消息(msg)进一步相互关联。
第三步:在ROS1和ROS2的相同名称的消息(msg)相互关联后,则对相同名称消息(msg)内的相同名称字段进一步相互关联。
注意:
- 如果两条关联消息(msg)之一的字段不是另一条消息(msg)的一部分,则它们将被忽略;
- 如果两个消息(msg)中均包含彼此不存在的字段,则会判断映射不完整并且无法建立关联。
1.2 为消息(msg)指定自定义映射规则
ROS 2 包使用yaml文件提供映射规则,映射规则具三种类型,分别是包映射规则、消息映射规则、字段映射规则。
- 包映射规则:
ros1_package_name
ros2_package_name
ROS1的包名称和ROS2包名称对应,表示彼此相互映射。
默认情况下,ros2_package_name
必须与定义此映射规则的 ROS 2 包相同。
- 消息(msg)映射规则:
ros1_message_name.msg
ros2_message_name.msg
ROS1包中的消息(msg)名称和ROS2包中的消息(msg)名称对应,表示彼此相互映射。
- 字段映射规则:
fields_1_to_2:
foo: 'foo'
ros1_bar: 'ros2_bar'
fields_1_to_2
:将 ROS 1 消息(msg)内的字段映射到 ROS 2 消息(msg)内的字段。
消息(msg)要映射的字段什么呢?
消息(msg)要映射的字段是.
分隔的消息类型字段名称,如消息类型header.stamp
,header
和stamp
均是字段。在映射时,会递归映射该字段的所有子数据成员,即字段指定从.
开始一直到最底层的所有子字段。例如,映射header
时,则stamp
也会自动被映射,但映射stamp
时,header
的其它子字段不会被映射。
在映射时,所有字段都必须明确列出,未列出的字段在名称匹配时不会隐式映射。
1.3 示例映射规则文件
ROS2提供包、消息、字段三种不同层次的映射规则。
- 映射ROS1和ROS2包内名称和字段相同的所有消息(msg)
my_mapping_rules.yaml
-
ros1_package_name: 'ros1_pkg_name'
ros2_package_name: 'ros2_pkg_name'
- 映射ROS1和ROS2包内字段相同的特定消息(msg)
my_mapping_rules.yaml
-
ros1_package_name: 'ros1_pkg_name'
ros1_message_name: 'ros1_msg_name'
ros2_package_name: 'ros2_pkg_name'
ros2_message_name: 'ros2_msg_name'
- 映射ROS1和ROS2包内特定消息(msg)内的相同字段
-
ros1_package_name: 'ros1_pkg_name'
ros1_message_name: 'ros1_msg_name'
ros2_package_name: 'ros2_pkg_name'
ros2_message_name: 'ros2_msg_name'
fields_1_to_2:
foo: 'foo'
ros1_bar: 'ros2_bar'
注意:ROS1和ROS2的消息包的文件名和内部变量名不一样,所以需要定义映射文件my_mapping_rules.yaml
;若文件名和内部变量名一样,不需要定义映射文件my_mapping_rules
。
1.4 安装映射规则文件
如果存在my_mapping_rules.yaml
文件,则yaml
文件还必须在以_msgs
或_msgs_interfaces
名称结尾的 ROS 2消息包的CMakeLists.txt
中进行install
:
install( FILES my_mapping_rules.yaml
DESTINATION share/${PROJECT_NAME})
映射规则文件必须在以_msgs
或_msgs_interfaces
名称结尾的 ROS 2消息包中的package.xml
进行export
,才能由该包处理:
二、自定义服务(srv)类型
ROS 1 和 2 服务(service)之间的映射类似于消息(msg),但服务不支持名称不同的字段进行映射,即ROS1和ROS2的服务包内.srv
文件中定义的服务名称必须一样。
2.1 ROS 1 和ROS 2 服务(service)的相互关联步骤
ROS 1 和ROS 2 服务(service)之间的自动映射是根据名称执行的。
第一步:
_srvs
名称结尾的 ROS 1 包与_srvs
或_srvs_interfaces
名称结尾的 ROS 2 包相关联。第二步:在ROS1和ROS2的服务(service)包相关联后,包内具有相同名称的服务(srv)进一步相互关联。
第三步:在ROS1和ROS2的相同名称的服务(service)相互关联后,则对相同名称服务(srv)内的相同名称字段进一步相互关联。
注意:ROS1和ROS2的服务包内.srv
文件中定义的服务名称必须一样。
2.2 为服务(srv)指定自定义映射规则
ROS 2 包使用yaml文件提供映射规则,映射规则具两种类型,分别是包映射规则、服务映射规则。
- 包映射规则:
ros1_package_name
ros2_package_name
ROS1的包名称和ROS2包名称对应,表示彼此相互映射。
默认情况下,ros2_package_name
必须与定义此映射规则的 ROS 2 包相同。
- 服务(srv)映射规则:
ros1_service_name.srv
ros1_service_name.srv
- 服务目前不支持自定义字段映射
即不支持字段名称不同的服务进行相互映射,但字段名称相同的服务仍然可以相互映射。
2.3 示例映射规则文件
ROS2提供包、服务两种不同层次的映射规则。
- 映射ROS1和ROS2包内名称和字段相同的所有服务(srv)
my_mapping_rules.yaml
-
ros1_package_name: 'ros1_pkg_name'
ros2_package_name: 'ros2_pkg_name'
- 映射ROS1和ROS2包内字段相同的特定服务(srv)
my_mapping_rules.yaml
-
ros1_package_name: 'ros1_pkg_name'
ros1_service_name: 'ros1_srv_name'
ros2_package_name: 'ros2_pkg_name'
ros2_service_name: 'ros2_srv_name'
- 映射ROS1和ROS2包内特定服务(srv)内的相同字段
-
ros1_package_name: 'ros1_pkg_name'
ros1_service_name: 'ros1_srv_name'
ros2_package_name: 'ros2_pkg_name'
ros2_service_name: 'ros2_srv_name'
request_fields_1_to_2:
foo: 'foo'
ros_bar: 'ros_bar'
response_fields_1_to_2:
foo: 'foo'
ros_bar: 'ros_bar'
2.4 安装映射规则文件
如果存在my_mapping_rules.yaml
文件,则yaml
文件还必须在以_srvs
或__srvs_interfaces
名称结尾的 ROS 2服务包的CMakeLists.txt
中进行install
:
install( FILES my_mapping_rules.yaml
DESTINATION share/${PROJECT_NAME})
映射规则文件必须在以_srvs
或_srvs_interfaces
名称结尾的 ROS 2服务包中的package.xml
进行export
,才能由该包处理:
三、ros1_bridge
桥接自定义接口
ROS 1 和 ROS 2 消息(msg)和服务(srv)包需要位于单独的工作区中,以便每个工作区都可以获取其相应的 ROS1/ROS2环境变量,而ros1_bridge
应该在它自己的工作区中,因为它需要同时获取 ROS 1 和 ROS 2 版本。
3.1 工作区文件目录结构
测试自定义的消息类型需要三个工作区,分别是
- ROS 1 工作区:ros1_msgs_ws
- ROS 2 工作区:ros2_msgs_ws
-
ros1_bridge
工作区:bridge_ws
ROS 1 和 ROS 2 自定义接口的包、消息和字段使用相同的名称。
目录布局如下所示:
.
├─ ros1_msgs_ws/
│ └─ src/
│ └─ bridge_msgs/
│ └─ msg/
│ └─ JointCommand.msg
├─ ros2_msgs_ws/
│ └─ src/
│ └─ bridge_msgs/
│ ├─ msg/
│ │ └─ JointCommand.msg
│ └─ my_mapping_rules.yaml
└─ bridge_ws/
└─ src/
└─ ros1_bridge
其中JointCommand.msg
文件内容是:
float64 position
注意:ros2的msg文件命名有正则表达式的规定,要以大写字母开头,文件内容中的每个变量不可以存在大写字母,更详细的规则请参考官方文档。
3.2 编译
- 编译ROS 1消息
source /opt/ros/melodic/setup.bash
cd /ros1_msgs_ws
catkin_make_isolated --install
- 编译ROS 2消息
source /opt/ros/crystal/setup.bash
cd /ros2_msgs_ws
colcon build --packages-select bridge_msgs
- 编译
ros1_bridge
source /opt/ros/melodic/setup.bash
source /opt/ros/crystal/setup.bash
source /ros1_msgs_ws/install_isolated/setup.bash
source /ros2_msgs_ws/install/local_setup.bash
cd /bridge_ws
colcon build --packages-select ros1_bridge --cmake-force-configure
- 查看ROS1/2消息是否配对成功
通过打印所有桥接类型对来验证自定义类型是否被ros1_bridge
识别:
ros2 run ros1_bridge dynamic_bridge --print-pairs
3.3 运行
打开四个终端,分别运行下列命令:
Terminal 1 |
Terminal 2 |
Terminal 3 |
Terminal 4 |
|
---|---|---|---|---|
ROS环境变量 | source ros1 |
source ros2; source |
source ros1; source ros2; source |
source ros1; source |
命令 | roscore |
ros2 topic pub /joint_command bridge_msgs/JointCommand "{position: 0.123}" |
ros2 run ros1_bridge dynamic_bridge --bridge-all-topics |
rostopic list; rostopic echo /joint_command |
四、从外部包定义外部包的映射规则
在前面的部分中,已经指出 ros2_package_name
映射规则必须与定义映射规则的 ROS 2 包相同。虽然建议这样做以防止冲突和/或重复规则,但可以覆盖检查 使用 enable_foreign_mappings
字段强制执行此操作。
这意味着,对于 yaml 文件中定义的每个包映射规则,将跳过对 ROS 2 包名称相等性的检查。 再次,请注意,这是一种应负责任地使用的黑暗艺术,请务必小心! 如果存在冲突的映射规则,则使用按排序顺序解析的最后一个! 这通常很难预测,所以要非常小心!
将 enable_foreign_mappings
设置为true
后,可以为 ROS 2 包指定与映射规则文件所在的包不同的映射规则:
-
enable_foreign_mappings: true
ros1_package_name: 'ros1_pkg_name'
ros1_service_name: 'ros1_srv_name'
ros2_package_name: 'ros2_FOREIGN_pkg_name' # the package with the service definition
ros2_service_name: 'ros2_srv_name'
同时还必须使ros1_bridge_foreign_mapping
资源可用于映射包的 CMakeLists.txt 中的索引。 放置该行的好地方是在映射规则的安装规则之前执行此操作,如下所示:
-
ament_index_register_resource("ros1_bridge_foreign_mapping")
install(
FILES YOUR_MAPPING_RULE_FILE.yaml
DESTINATION share/${PROJECT_NAME})
注意:在这种情况下,应该在 `ros2_package_name 中输入的包名称是带有消息定义的包的名称。 实际上,它是一个外部包,相对于在其中定义映射规则的映射包。
一个示例目录布局如下所示:
.
├─ ros1_msgs_ws
│ └─ src
│ └─ ros1_bridge_msgs
│ └─ msg
│ └─ ros1_msg_name.msg
├─ ros2_msgs_ws
│ └─ src
│ └─ ros2_bridge_msgs
│ │ ├─ msg
│ │ │ └─ ros2_msg_name.msg
│ └─ ros2_bridge_mappings
│ └─ my_mapping_rules.yaml
└─ bridge_ws
└─ src
└─ ros1_bridge
在上面的示例中,映射规则如下所示:
-
enable_foreign_mappings: true
ros1_package_name: 'ros1_bridge_msgs'
ros1_message_name: 'ros1_msg_name'
ros2_package_name: 'ros2_bridge_msgs' # this is a foreign package, relative to ros2_bridge_mappings!
ros2_message_name: 'ros2_msg_name'
五、完整的自定义消息功能包
5.1 TestFoxy.msg
string test_str1
int32 test_int1
5.2 mapping_rules.yaml
-
ros1_package_name: 'custom_msgs'
ros1_message_name: 'TestNoetic'
ros2_package_name: 'custom_msgs'
ros2_message_name: 'TestFoxy'
fields_1_to_2:
test_str1: 'test_str2'
test_int1: 'test_int2'
5.3 CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(custom_msgs)
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
find_package(ament_cmake REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(custom_msgs
msg/TestFoxy.msg
DEPENDENCIES
builtin_interfaces
)
install(FILES mapping_rules.yaml
DESTINATION share/${PROJECT_NAME}
)
ament_export_dependencies(rosidl_default_runtime)
ament_package()
5.4 package.xml
custom_msgs
0.0.0
The custom_msgs package
weibw
TODO
rclpy
builtin_interfaces
rosidl_default_generators
rosidl_interface_packages
ament_cmake
5.5 编译ros2下的custom_msgs功能包
source /opt/ros/foxy/setup.bash
cd colcon_ws
colcon build --packages-select custom_msgs
参考:
在ros2下使用ros1_bridge与ros1自定义消息桥接:https://blog.csdn.net/weixin_38274206/article/details/123062134
ros1_bridge官方文档:https://github.com/ros2/ros1_bridge/blob/master/doc/index.rst