概念
主题是一种节点间的通信方式,某个节点充当发布特定(主题)消息(数据)的角色,另外一些节点则可以订阅接收该特定(主题)消息(数据)。两者(发布者和订阅者)间可以一对一(一个订阅该主题的节点 + 一个发布该主题的节点),也可以一对多(一个发布多个订阅),也可以多对一,更可以多对多,理论上并没有节点数量的限制(但可能会受到到某些平台环境资源的限制,此处不表),下面两张图分别代表了一对一和一对多及多对多的情况。
(一对一)
(一对多&多对多)
主题这种通信方式比较适合一些[不断更新的数据传输相关]的场景,比如不断更新的雷达数据,就适合用这种方式。
动动手
启动小海龟
分别执行如下命令启动海龟节点及控制节点(不熟悉的出口在右手边):
$ros2 run turtlesim turtlesim_node
$ros2 run turtlesim turtle_teleop_key
新工具rqt_graph
下面我们介绍个新朋友rqt_graph,这个其实已经集成在之前安装的rqt工具中了,通过它可以看到节点与主题之间的微妙关系(可视化),在复杂的系统中,我们可以利用它理清各自的逻辑关系。
有两种方式可以打开,其一直接执行rqt_graph,其二在rqt窗口中,选择Plugins > Introspection > Node Graph,这两种方法都行,我们试试第一种,打开的界面如下所示(将鼠标挪动到图形上面会变色),
左边是节点/turtlesim,右边是节点/teleop_turtle,中间的三条箭头连线,上面两个是动作(本篇不提),最下面的是主题/turtle1/cmd_vel,箭头是从节点/teleop_turtle指向节点/turtlesim,代表的是数据流向,/teleop_turtle节点负责发布主题(/turtle1/cmd_vel)数据,该数据是通过键盘产生的,而节点/turtlesim订阅了该主题数据,所以数据从主题发布者流向主题订阅者。
主题列表
$ros2 topic list
通过上面的命令会列出当前活动节点的主题信息,非常简单概括,如下图所示,咱们开启了两个节点,一共产生了5个主题,
我们再查看各个主题详细的信息,返回了各个主题对应的数据类型(可类比成结构体),只有相同的数据类型,才能正常进行通信。
$ros2 topic list -t
在rqt_graph中我们Hide那一行所有的勾选后,我们会看到一幅包含所有主题信息的完整图,此刻不必深究。
主题数据
大家好不好奇从发布者节点发出的主题数据是怎样的呢,该怎么查看呢? 别急,往下瞧,
$ros2 topic echo <topic_name>
我们通过上面的初步摸索已经了解到小海龟例子中/teleop_turtle节点通过/turtle1/cmd_vel主题发布位姿数据到/turtle_sim节点,我们就来看看/turtle1/cmd_vel这个主题数据到底是何方神圣,执行如下命令进行查看:
$ros2 topic echo /turtle1/cmd_vel
输入为命令后你会发现,咋啥都没有,不是骗人嘛,还是别急,接着往下瞧。我们切换到启动了/teleop_turtle节点的终端,鼠标点击一下这个终端,使得焦点在这里,随便摁下之前说过的那些键(F周遭),确认小海龟游动了之后,大家再切换回echo那个终端,看看它返回了什么,如下所示,
我们再来瞅瞅rqt_graph里面会相应发生些什么,打开后我们会看到下面的图形,
里面比之前多了一个节点(/_ros2cli_43366),而主题/turtle1/cmd_vel也有个箭头连线指向了这个节点,目前为止,一共有两个订阅者节点和一个发布者节点,发布者节点会通过主题/turtle1/cmd_vel实时将键盘产生的位姿数据发布给两个订阅者。
主题信息
如果我们想要了解某个活动的主题的相关信息(如主题数据类型、该主题对应的发布者和订阅者各自数量),我们可以通过下面的命令得到:
$ros2 topic info <topic_name>
来看看/turtle1/cmd_vel这个活动主题的信息(ros2 topic info /turtle1/cmd_vel),结果如下:
主题数据消息类型
订阅者和发布者之间通过消息通信,二者会共用同样数据结构类型的消息,否则牛头对马嘴,胡拉乱扯。之前我们通过ros2 topic list -t
命令获取到当前活动的一些主题的概括信息,对于主题/turtle1/cmd_vel我们查看得知,它的消息类型是geometry_msgs/msg/Twist(geometry_msgs功能包下消息类型Twist),那这个Twist类型到底长的啥样,我们可以直接找到geometry_msgs/msg/Twist文件打开查看(文本文件),当然我们要做符合身份的事,通过命令看:
$ros2 interface show <msg_type>
对于geometry_msgs/msg/Twist,我们这样输入:
$ros2 interface show geometry_msgs/msg/Twist
结果来了:
可以看见Twist数据类型为两个向量(线性及角度)构成,如果你要主动发布主题消息控制小海龟,你必须得按照这个格式来。
发布主题消息
我们来试试上个小标题最后提到的发布主题消息,它的命令是这样的:
$ros2 topic pub <topic_name> <msg_type> '<args>'
需要注意的是最后一个参数'<args>',它就是按照对应消息类型填充的参数,必须得是YAML语式:
$ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
--once表示只发生一次主题消息就退出,看看效果,
如果要让它自动(一定频率)发布下去呢,我们可以将--once变为--rate 1,表示按1Hz的频率(1次/秒)周期发布消息,来试试:
$ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
我们再来看看rqt_graph又变成啥样了,
又多了一个发布者节点(/_ros2cli_43523),它通过/turtle1/cmd_vel主题发布Twist消息数据,/turtlesim和/_ros2cli_43366作为订阅者节点不断接收消息数据。
最后我们可以尝试echo一下pose主题并查看一下rqt_graph,
$ros2 topic echo /turtle1/pose
可以看到/turtlesim节点发布了一个/turtle1/pose主题,/_ros2cli_43706节点(刚刚echo pose的那个终端)订阅了该主题。
如果我们想在发布主题消息里面加入时间戳呢,我们有下面这个主题,该主题消息包含了时间戳字段,geometry_msgs/msg/PoseStamped,我们来看看这个主题的详细信息(还记得查看命令吧),ros2 interface show geometry_msgs/msg/PoseStamped,
如上,该主题消息由两部分组成,第一部分为标准消息头结构(std_msgs/msg/Header),stamp字段我们可以用auto填充,我们再来试试,
$ros2 topic pub /pose geometry_msgs/msg/PoseStamped '{header: "auto", pose: {position: {x: 1.0, y: 2.0, z: 3.0}}}'
时间戳有啦(小海龟此时此刻会有什么反应呢,思考一下,如果将命令行中的/pose变成/turtle1/pose呢)。
还有一种带时间的主题,sensor_msgs/msg/TimeReference,看它的消息结构有点头大吧,其中builtin_interfaces/Time消息类型变量time_ref,我们可以填充now(先暂时留个印象吧)。
主题消息发布频率
当我们想要知道某些主题消息的发布频率时,我们可以通过hz查询,如下:
$ros2 topic hz /turtle1/pose
通过键盘控制小海龟,再来查看/turtle1/cmd_vel主题消息频率(大家可以试试上面讲的--rate 1方式发布主题,看看打印出来个啥)。
本篇完。