文章目录
1. ROS话题名称重映射
1.1 简介
在ROS中,有时会出现话题名称重名现象,导致信息发布,接收不匹配;有时也需要话题名称不同的节点相互通信。这时,就需要使用话题名称重映射的方法来解决问题
1.2 实现方法
在ROS操作系统中,提供了ros-noetic-teleop-twist-keyboard键盘控制包,话题名为cmd_vel,在turtlesim功能包中,其键盘控制话题为/turtle1/cmd_vel,通过话题重映射,来实现二者的通信
1.2.1 rosrun设置话题重映射
- 格式: rosrun 功能包 节点名 话题名:=新节点名
1.2.1.1 方案一
- 目标: /cmd_vel 映射到 /turtle1/cmd_vel
- 代码实现:
bash1:启动乌龟节点 rosrun turtlesim turtlesim_node bash2:启动键盘控制节点,并进行映射 rosrun teleop_twist_keyboard teleop_twist_keyboard.py /cmd_vel:=/turtle1/cmd_vel
1.2.1.2 方案二
- 目标:/turtle1/cmd_vel 映射到/cmd_vel
- 代码实现:
bash1:启动键盘控制节点 rosrun teleop_twist_keyboard teleop_twist_keyboard.py bash2:启动乌龟节点,并进行话题映射 rosrun turtlesim turtlesim_node /turtle1/cmd_vel:=/cmd_vel
1.2.2 launch文件设置话题重映射
- 格式:
<node pkg="" type="" name=""> <remap from="原话题" to="新话题"/> </node>
1.2.2.1 方案一
- 目标:将teleop_twist_keyboard节点的话题设置为/turtle1/cmd_vel
- 代码实现:
<launch> <node pkg="turtlesim" type="turtlesim_node" name="t1" /> <node pkg="teleop_twist_keyboard" type="teleop_twist_keyboard.py" name="t2"> <remap from="/cmd_vel" to="/turtle1/cmd_vel" /> </node> </launch>
1.2.2.2 方案二
- 目标:将turtlesim节点的话题名设置为/cmd_vel
- 代码实现
<launch> <node pkg="teleop_twist_keyboard" type="teleop_twist_keyboard.py" name="t1" /> <node pkg="turtlesim" type="turtlesim_node" name="t2"> <remap from="/turtle1/cmd_vel" to="/cmd_vel" /> </node> </launch>
1.2.3 编码设置话题名称
- 话题的名称与命名空间,节点的名称有关,按照所属关系不同,话题名称大致可分为三类(可以理解为在话题前加的前缀不同):
- 全局:参考整个ROS系统,与命名空间平级
- 相对:参考命名空间,与节点名平级
- 私有:参考节点名,是节点的子级
1.2.3.1 C++实现
- 全局话题
- 格式:已 / 开头
- 代码实现:
#include"ros/ros.h" #include"std_msgs/String.h" int main(int argc,char *argv[]){ ros::init(argc,argv,"topic_name"); ros::NodeHandle nh; //全局话题:在话题前加 / ros::Publisher pub = nh.advertise<std_msgs::String>("/chtter",1000); //设置自己的命名空间 ros::Publisher pub1 = nh.advertise<std_msgs::String>("/xxx/chtter",1000); while (ros::ok()) { } return 0; }
- 运行结果:
bash1: 启动节点 rosrun rename_01 topic_name bash2:查看话题列表 rostopic list /chtter //全局话题 /rosout /rosout_agg /xxx/chtter //加入了自己的命名空间
- 相对话题
- 格式:非 / 开头的话题
- 代码实现:
#include"ros/ros.h" #include"std_msgs/String.h" int main(int argc,char *argv[]){ ros::init(argc,argv,"topic_name"); ros::NodeHandle nh; //全局话题:在话题前加 / ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",1000); //设置自己的命名空间 ros::Publisher pub1 = nh.advertise<std_msgs::String>("yyy/chatter",1000); while (ros::ok()) { } return 0; }
- 运行结果:
bash1:启动节点,并加入命名空间 rosrun rename_01 topic_name __ns:=xxx bash2:查看话题 rostopic list /rosout /rosout_agg /xxx/chatter /xxx/yyy/chatter
- 私有话题
- 格式: ros::NodeHandle nh(“~”);
- 代码实现:
#include"ros/ros.h" #include"std_msgs/String.h" int main(int argc,char *argv[]){ ros::init(argc,argv,"topic_name"); //私有话题,与NH结合使用,在其后加入~ ros::NodeHandle nh("~"); ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",1000); //若以 / 开头,则为全局话题 ros::Publisher pub1 = nh.advertise<std_msgs::String>("/chatter",1000); while (ros::ok()) { } return 0; }
- 运行结果:
bash1: 启动节点 rosrun rename_01 topic_name __ns:=xxx bash2:查看节点列表 rostopic list /chatter /rosout /rosout_agg /xxx/topic_name/chatter
1.2.3.2 Python实现
- 代码实现:
#! /usr/bin/env python from ast import Str import rospy from std_msgs.msg import String if __name__ == "__main__": rospy.init_node("topic_name_p") # 1.全局 pub1 = rospy.Publisher("/chatter1",String,queue_size=10) # 设置自己的命名空间,不受 __ns:=xxx 的影响 pub2 = rospy.Publisher("/zzz/chatter2",String,queue_size=10) # 2.相对 pub3 = rospy.Publisher("chatter3",String,queue_size=10) # 设置自己的命名空间 pub4 = rospy.Publisher("yyy/chatter4",String,queue_size=10) # 3.私有 pub5 = rospy.Publisher("~chatter5",String,queue_size=10) # 设置自己的命名空间 pub6 = rospy.Publisher("~ns/chatter6",String,queue_size=10) while not rospy.is_shutdown(): pass
- 运行结果:
bash1:启动节点 rosrun rename_01 topic_name_p.py __ns:=xxx bash2:查看节点列表 rostopic list /chatter1 /rosout /rosout_agg /xxx/chatter3 /xxx/topic_name_p/chatter5 /xxx/topic_name_p/ns/chatter6 /xxx/yyy/chatter4 /zzz/chatter2