3.5 话题重名
问题描述
节点名称可能出现重名的情况,同理话题名称也可能重名,不过与节点重名不同的是,有些场景下需要避免话题重名的情况,但有些场景下又需要将不同的不同的话题名称修改为相同。
在 ROS2 不同的节点之间通信都依赖于话题,话题名称也可能出现重名的情况,话题重名时,系统虽然不会抛出异常,但是通过相同话题名称关联到一起的节点可能并不属于同一通信逻辑,从而导致通信错乱,甚至出现异常。这种情况下可能就需要将相同的话题名称设置为不同。
又或者,两个节点是属于同一通信逻辑的,但是节点之间话题名称不同,导致通信失败。这种情况下就需要将两个节点的话题名称由不同修改为相同。
那么如何修改话题名称呢?
解决思路
与节点重名的解决思路类似的,为了避免话题重名问题,一般有两种策略:
名称重映射,也即为话题名称起别名;
命名空间,是为话题名称添加前缀,可以有多级,格式:/xxx/yyy/zzz。
需要注意的是,通过命名空间设置话题名称时,需要保证话题是非全局话题。
解决方案
与节点重名解决方案类似的,修改话题名称的方式主要有如下三种:
ros2 run 命令实现;
launch 文件实现;
编码实现。
本节将逐一演示上述三种方案的实现语法。
3.5.1 ros2 run 修改话题名称
1.ros2 run设置命名空间
该实现与3.4.1 ros2 run设置节点名称中演示的语法使用一致。
1.1设置命名空间演示
语法:ros2 run 包名 节点名 --ros-args --remap __ns:=命名空间
示例:
ros2 run turtlesim turtlesim_node --ros-args --remap __ns:=/t1
1.2运行结果
使用ros2 topic list
查看节点信息,显示结果:

节点下的话题已经添加了命名空间前缀。
2.ros2 run话题名称重映射
2.1为话题起别名
语法: ros2 run 包名 节点名 --ros-args --remap 原话题名称:=新话题名称
示例:
ros2 run turtlesim turtlesim_node --ros-args --remap /turtle1/cmd_vel:=/cmd_vel
2.2运行结果
使用ros2 topic list
查看节点信息,显示结果:

节点下的话题/turtle1/cmd_vel已经被修改为了/cmd_vel。
注意:
当为节点添加命名空间时,节点下的所有非全局话题都会前缀命名空间,而重映射的方式只是修改指定话题。
3.5.2 launch 文件修改话题名称
1.Python方式实现的launch文件修改话题名称
在 Python 方式实现的 launch 文件中,可以通过类 launch_ros.actions.Node
的构造函数中的参数 remappings 修改话题名称,使用示例如下:

2.XML方式实现的launch文件修改话题名称
在 XML 方式实现的 launch 文件中,可以通过 node 标签的子标签 remap(属性from取值为被修改的话题名称,属性to的取值为修改后的话题名称) 修改话题名称,使用示例如下:

3.YAML方式实现的launch文件修改话题名称
在 YAML 方式实现的 launch 文件中,可以通过 node 属性中 remap(属性from取值为被修改的话题名称,属性to的取值为修改后的话题名称) 修改话题名称,使用示例如下:

4.测试
上述三种方式在修改话题名称时虽然语法不同,但是实现功能类似,都是启动了两个turtlesim_node
节点,一个节点添加了命名空间,另一个节点将话题从/turtle1/cmd_vel
映射到了/cmd_vel
。使用ros2 topic list
查看节点信息,显示结果:
添加命名空间的节点对应的话题为:

3.5.3 编码设置话题名称
话题分类
话题的名称的设置是与节点的命名空间、节点的名称有一定关系的,话题名称大致可以分为三种类型:
全局话题(话题参考ROS系统,与节点命名空间平级);
相对话题(话题参考的是节点的命名空间,与节点名称平级);
私有话题(话题参考节点名称,是节点名称的子级)。
总之,以编码方式设置话题名称是比较灵活的。本节将介绍如何在 rclcpp 和 rclpy 中分别设置不同类型的话题。
准备
请先分别创建 C++ 与 Python 相关的功能包以及节点,且假定在创建节点时,使用的命名空间为 xxx,节点名称为 yyy。
话题设置
1.1全局话题
格式:定义时以/
开头的名称,和命名空间、节点名称无关。
rclcpp示例:publisher_ = this->create_publisher<std_msgs::msg::String>("/topic/chatter", 10);
rclpy示例:self.publisher_ = self.create_publisher(String, '/topic/chatter', 10)
话题:话题名称为 /topic/chatter,与命名空间 xxx 以及节点名称 yyy 无关。
1.2相对话题
格式:非/
开头的名称,参考命名空间设置话题名称,和节点名称无关。
rclcpp示例:publisher_ = this->create_publisher<std_msgs::msg::String>("topic/chatter", 10);
rclpy示例:self.publisher_ = self.create_publisher(String, 'topic/chatter', 10)
话题:话题名称为 /xxx/topic/chatter,与命名空间 xxx 有关,与节点名称 yyy 无关。
1.3私有话题
格式:定义时以~/
开头的名称,和命名空间、节点名称都有关系。
rclcpp示例:publisher_ = this->create_publisher<std_msgs::msg::String>("~/topic/chatter", 10);
rclpy示例:self.publisher_ = self.create_publisher(String, '~/topic/chatter', 10)
话题:话题名称为 /xxx/yyy/topic/chatter,使用命名空间 xxx 以及节点名称 yyy 作为话题名称前缀。
综上,话题名称设置规则在rclcpp与rclpy中基本一致,且上述规则也同样适用于ros2 run指令与launch文件。

B站有完整的ros系列教程视频,可以观看完整内容ros课程ROS2理论与实践
更多内容将在猛狮知识星球社区更新最新课程,后续将推出更多优质内容——详情可关注猛狮集训营公众号和猛狮集训营官方网站。