Skip to main content

理解节点和话题通信

01. 目标及导学

  • 学习 ROS2 中节点的功能,以及如何与它们交互的工具。
  • 使用rqt_graph和命令行工具来检查 ROS 2 的 topics

02. ROS2 节点的概念及其作用

2.1 ROS2 中的图 (graph)

在接下来的几个教程中,你将学习一系列构成所谓 ROS2 图 (graph) 的核心 ROS2 概念。

如果将它们全部映射并可视化的话,ROS2 的 graph 是一个由若干协同处理数据的 ROS2 要素组成的网络。它包括所有的可执行文件 (executables) 及其之间的连接 (connections)。

2.2 ROS2 节点 (Node)

ROS 中的每个节点都应该负责一个单一、模块化的目的,例如控制轮子电机或发布来自激光测距仪的传感器数据。每个节点可以通过主题(topics)、服务(services)、动作(actions)或参数(parameters)发送和接收其他节点的数据。

节点示意图

一个完整的机器人系统由许多协同工作的节点组成。在 ROS2 中,单个可执行文件(C++ 程序、Python 程序等)可以包含一个或多个节点。

tip

让我们通过上机实践加深对 ROS2 节点的理解,并学习如何使用 ROS2 提供的工具与节点进行交互。

2.3 运行节点

命令ros2 run可以从一个包中启动一个可执行文件。它的命令格式如下:

命令格式
ros2 run <package_name> <executable_name>

要运行 turtlesim,请打开一个新的终端,并输入以下命令:

ros2 run turtlesim turtlesim_node

正如你在上一个教程中看到的那样,turtlesim 窗口将会打开。

这里的包名是turtlesim,可执行文件名是turtlesim_node

然而,我们还不知道节点的名字。你可以使用ros2 node list找到节点名称。

2.4 列出所有节点

ros2 node list会显示所有正在运行的节点的名称。当你想要与某个节点互动,或者当你的系统运行着很多节点时需要跟踪它们,这特别有用。

当 turtlesim 仍在另一个终端中运行时,打开一个新的终端,并输入以下命令。

ros2 node list

该终端将返回节点名称:

/turtlesim

打开另一个新终端,并使用以下命令启动 teleop 节点:

ros2 run turtlesim turtle_teleop_key

这里,我们再次引用了turtlesim包,但这次我们针对的是名为turtle_teleop_key的可执行文件。

返回到运行ros2 node list的终端,并再次运行它。

ros2 node list

你现在将看到两个活动节点的名称:

/turtlesim
/teleop_turtle

重映射

重映射允许你重新分配默认的节点属性,如节点名称、主题名称、服务名称等,为自定义值。在上一个教程中,你对turtle_teleop_key使用了重映射来改变 cmd_vel 主题并瞄准turtle2

现在,让我们重新分配我们的/turtlesim节点的名称。在新的终端中,运行以下命令:

ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle

由于你再次调用了turtlesim上的ros2 run,另一个 turtlesim 窗口将打开。但是,现在如果你返回到运行ros2 node list的终端,并再次运行它,你将看到三个节点名称:

/my_turtle
/turtlesim
/teleop_turtle

2.5 获取节点信息

既然你知道了节点的名称,就可以通过以下方式访问更多关于它们的信息,其命令的一般格式如下:

命令格式
ros2 node info <node_name>

为了检查你最新的节点my_turtle,运行以下命令:

ros2 node info /my_turtle

上述命令的输出大致如下:

/my_turtle
Subscribers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
/turtle1/cmd_vel: geometry_msgs/msg/Twist
Publishers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
/turtle1/color_sensor: turtlesim_msgs/msg/Color
/turtle1/pose: turtlesim_msgs/msg/Pose
Service Servers:
/clear: std_srvs/srv/Empty
/kill: turtlesim_msgs/srv/Kill
/my_turtle/describe_parameters: rcl_interfaces/srv/DescribeParameters
/my_turtle/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/my_turtle/get_parameters: rcl_interfaces/srv/GetParameters
/my_turtle/get_type_description: type_description_interfaces/srv/GetTypeDescription
/my_turtle/list_parameters: rcl_interfaces/srv/ListParameters
/my_turtle/set_parameters: rcl_interfaces/srv/SetParameters
/my_turtle/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
/reset: std_srvs/srv/Empty
/spawn: turtlesim_msgs/srv/Spawn
/turtle1/set_pen: turtlesim_msgs/srv/SetPen
/turtle1/teleport_absolute: turtlesim_msgs/srv/TeleportAbsolute
/turtle1/teleport_relative: turtlesim_msgs/srv/TeleportRelative
Service Clients:

Action Servers:
/turtle1/rotate_absolute: turtlesim_msgs/action/RotateAbsolute
Action Clients:

ros2 node info返回订阅者 (Subscribers)、发布者 (Publishers)、服务 (Service) 和动作 (Action) 的列表。即与该节点交互的 ROS 图连接。

探索实验

现在尝试对/teleop_turtle节点运行相同的命令,并查看它的连接与my_turtle有何不同?

ros2 node info /teleop_turtle

2.6 小结

节点是 ROS2 中的基本元素,它在机器人系统中服务于单一、模块化的目的。

在本教程中,你通过运行turtlesim_nodeturtle_teleop_key可执行文件利用了turtlesim包中创建的节点。

你学会了如何使用ros2 node list发现活动节点名称和ros2 node info内省单个节点。这些工具对于理解复杂的真实世界机器人系统中的数据流至关重要。

在接下来的教程中,我们将了解更多关于 ROS 图连接的概念,包括消息类型。

03. ROS2 话题通信机制及其应用

ROS 2 将复杂的系统分解为许多模块化的节点。主题(Topics)是 ROS 图中的重要元素,作为节点之间交换消息的总线。

单发布者与订阅者

一个节点可以向任意数量的主题发布数据,并同时订阅任意数量的主题。

多发布者与订阅者

主题是节点间传递数据的主要方式之一,因此也是系统不同部分之间传递数据的方式。

3.1 配置运行节点

到目前为止,你应该已经熟悉启动turtlesim了。

打开一个新的终端并运行:

ros2 run turtlesim turtlesim_node

再打开另一个终端并运行:

ros2 run turtlesim turtle_teleop_key

3.2 运行监控软件rqt_graph

在整个教程中,我们将使用rqt_graph来可视化变化的节点和主题以及它们之间的连接。

在前面的教程,我们已经安装rqt及其所有插件,包括rqt_graph。要运行rqt_graph,请打开一个新的终端并输入以下命令:

ros2 run rqt_graph rqt_graph

你也可以通过打开rqt并选择Plugins > Introspection > Node Graph来打开rqt_graph

rqt_graph 界面

你应该能看到上述节点和主题,以及图形外围的两个动作(暂时忽略它们)。如果你将鼠标悬停在中心的主题上,你会看到像上面图片那样的颜色高亮显示。

该图展示了/turtlesim节点和/teleop_turtle节点是如何通过主题相互通信的。/teleop_turtle节点正在向/turtle1/cmd_vel主题发布数据(你输入的按键以移动乌龟),而/turtlesim节点则订阅了该主题以接收数据。

当检查具有许多节点和主题以多种不同方式连接的更复杂系统时,rqt_graph的高亮功能非常有帮助。

rqt_graph是一个图形内省工具。现在我们将看看一些用于内省主题的命令行工具。

3.3 查看话题:ros2 topic list

在一个新的终端中运行ros2 topic list命令:

ros2 topic list

它将返回当前系统中所有活动主题的列表:

/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

ros2 topic list -t将返回相同主题列表:

ros2 topic list -t

上述命令的输出会在括号中附加主题类型:

/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/color_sensor [turtlesim_msgs/msg/Color]
/turtle1/pose [turtlesim_msgs/msg/Pose]

这些属性,特别是类型,是节点知道它们正在讨论通过主题传输的相同信息的方式。

如果你想知道rqt_graph中的所有这些主题在哪里,你可以取消选中 Hide: 下的所有框。

取消隐藏选项

不过,现在暂时保留那些选项选中以避免混淆。

3.4 提取话题信息:ros2 topic echo

要查看发布到某个主题的数据,请使用:

命令格式

ros2 topic echo <topic_name>

因为我们知道/teleop_turtle通过/turtle1/cmd_vel主题向/turtlesim发布数据,所以让我们使用echo来内省 (introspect) 该主题:

ros2 topic echo /turtle1/cmd_vel

起初,此命令不会返回任何数据。那是因为它正在等待/teleop_turtle发布某些内容。

返回到运行turtle_teleop_key的终端,并使用箭头键移动乌龟。同时观察运行echo的终端,你会看到每次移动都会发布位置数据:

linear:
x: 2.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---

现在返回到rqt_graph并取消选中Debug框。

取消选中 Debug 框

/_ros2cli_26646是我们刚刚运行的echo命令创建的节点(数字可能不同)。现在你可以看到发布者正在通过cmd_vel主题发布数据,并且有两个订阅者订阅了它。

3.5 审计话题:ros2 topic info

主题不必仅限于一对一的通信;它们可以是一对多、多对一或多多对多。

另一种查看方法是运行:

ros2 topic info /turtle1/cmd_vel

上述命令的输出大致如下:

Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscription count: 2

3.5.1 ros2 topic info --verbose

要获取有关主题的更多详细信息,可以使用--verbose(或-v)标志:

ros2 topic info /turtle1/cmd_vel --verbose

这将返回其他详细信息,包括:

  • 发布者和订阅者的节点名称和命名空间
  • 主题类型
  • QoS 配置文件
Type: geometry_msgs/msg/Twist

Publisher count: 1

Node name: teleop_turtle
Node namespace: /
Topic type: geometry_msgs/msg/Twist
Topic type hash: RIHS01_9c45bf16fe0983d80e3cfe750d6835843d265a9a6c46bd2e609fcddde6fb8d2a
Endpoint type: PUBLISHER
GID: 24.ba.3e.e7.c1.51.bb.46.21.41.de.36.1b.14.73.5e
QoS profile:
Reliability: RELIABLE
History (Depth): KEEP_LAST (7)
Durability: VOLATILE
Lifespan: Infinite
Deadline: Infinite
Liveliness: AUTOMATIC
Liveliness lease duration: Infinite

Subscription count: 2

Node name: _ros2cli_300492
Node namespace: /
Topic type: geometry_msgs/msg/Twist
Topic type hash: RIHS01_9c45bf16fe0983d80e3cfe750d6835843d265a9a6c46bd2e609fcddde6fb8d2a
Endpoint type: SUBSCRIPTION
GID: cc.4d.98.79.29.91.fe.25.8a.0a.c9.03.db.1a.ec.81
QoS profile:
Reliability: RELIABLE
History (Depth): KEEP_LAST (5)
Durability: VOLATILE
Lifespan: Infinite
Deadline: Infinite
Liveliness: AUTOMATIC
Liveliness lease duration: Infinite

Node name: turtlesim
Node namespace: /
Topic type: geometry_msgs/msg/Twist
Topic type hash: RIHS01_9c45bf16fe0983d80e3cfe750d6835843d265a9a6c46bd2e609fcddde6fb8d2a
Endpoint type: SUBSCRIPTION
GID: 9c.33.59.38.b2.f2.42.47.69.1b.7f.0e.5e.1d.86.f5
QoS profile:
Reliability: RELIABLE
History (Depth): KEEP_LAST (7)
Durability: VOLATILE
Lifespan: Infinite
Deadline: Infinite
Liveliness: AUTOMATIC
Liveliness lease duration: Infinite

3.6 查询接口:ros2 interface show

节点通过主题发送数据使用消息。发布者和订阅者必须发送和接收相同类型的消息才能进行通信。

我们之前在运行ros2 topic list -t后看到的主题类型让我们知道每个主题使用的消息类型是什么。回想一下,cmd_vel主题的类型是:

geometry_msgs/msg/Twist

这意味着在geometry_msgs包中有一个名为Twistmsg

命令格式

ros2 interface show <msg_type>

现在我们可以在这个类型上运行如下命令来了解其详细信息。具体来说,就是消息期望的数据结构。

ros2 interface show geometry_msgs/msg/Twist

这将返回:

# This expresses velocity in free space broken into its linear and angular parts.
Vector3 linear
float64 x
float64 y
float64 z
Vector3 angular
float64 x
float64 y
float64 z

这告诉我们/turtlesim节点期望一个包含两个向量linearangular的消息,每个向量有三个元素。如果你回想起我们用echo命令看到的/teleop_turtle传递给/turtlesim的数据,它的结构是相同的:

linear:
x: 2.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---

3.7 发布话题:ros2 topic pub

现在你有了消息结构,你可以直接从命令行使用以下格式的命令向主题发布数据:

命令格式

ros2 topic pub <topic_name> <msg_type> '<args>'

'<args>'参数是你将传递给主题的实际数据,采用你在前一部分发现的结构。

使用pub命令主要有四种方法,如下所示。然而,c.d.中描述的自动补全功能在 Windows 中不受支持。


a. 发布字典字符串

为了向主题发布数据,你需要以 YAML 字符串的形式传递数据。

ros2 topic pub /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}}"

但是,如果只是更改线性或角速度,则不需要指定整个消息,只需指定要更改的值即可。

例如,如果你想将线性速度更改为 2.0 并将角速度保持在 1.8,可以执行以下操作:

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.8}}"

b. 发布空消息

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist

这将以 1 Hz 的频率发布消息类型的默认值。在这种情况下,这相当于以下命令:

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}" --rate 1

c. 使用自动补全

你可以通过以下方式触发终端的自动补全功能:

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist <TAB>

如上述命令,在按下<TAB>键之后,将弹出如下所是的候选命令的菜单:

--keep-alive
--max-wait-time-secs
--node-name
--once
--print
--qos-depth
--qos-durability
--qos-history
--qos-liveliness
--qos-liveliness-lease-duration-seconds
--qos-profile
--qos-reliability
--rate
--spin-time
--stdin
--times
--use-sim-time
--wait-matching-subscriptions
--yaml-file
-1
-n
-p
-r
-s
-t
-w
\'linear:\^J\ \ x:\ 0.0\^J\ \ y:\ 0.0\^J\ \ z:\ 0.0\^Jangular:\^J\ \ x:\ 0.0\^J\ \ y:\ 0.0\^J\ \ z:\ 0.0\^J\'

所有选项都可以通过按tab键在输入选项的前几个字符后自动补全。

最终的自动补全字符串将如下所示:

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist 'linear:
x: 0.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
'

这个字符串是可编辑的,你可以根据需要更改消息类型的值。

d. 使用原始自动补全字符串

如上所述,geometry_msgs/msg/Twist的自动补全字符串如下所示:

\'linear:\^J\ \ x:\ 0.0\^J\ \ y:\ 0.0\^J\ \ z:\ 0.0\^Jangular:\^J\ \ x:\ 0.0\^J\ \ y:\ 0.0\^J\ \ z:\ 0.0\^J\'

这可以直接用作命令行中 yaml 字符串的替代品。

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist \'linear:\^J\ \ x:\ 0.0\^J\ \ y:\ 0.0\^J\ \ z:\ 0.0\^Jangular:\^J\ \ x:\ 0.0\^J\ \ y:\ 0.0\^J\ \ z:\ 0.0\^J\'

乌龟(以及通常它旨在模拟的真实机器人)需要连续操作的稳定命令流。因此,为了让乌龟移动并保持移动,你可以使用以下字典字符串:

ros2 topic pub /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选项。

ros2 topic pub --once -w 2 /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是一个可选参数,表示“发布一条消息然后退出”。

-w 2是一个可选参数,表示“等待两个匹配的订阅”。这是必需的,因为我们既有turtlesim又有主题回显订阅。

你将在终端中看到以下输出:

Waiting for at least 2 matching subscription(s)...
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))

并且你会看到你的乌龟像这样移动:

发布一次

你可以刷新rqt_graph以图形化地查看发生了什么。你会看到ros2 topic pub ...节点(/_ros2cli_30358)正在通过/turtle1/cmd_vel主题发布,这被ros2 topic echo ...节点(/_ros2cli_26646)和/turtlesim节点接收。

rqt_graph 更新

最后,你可以在pose主题上运行echo并重新检查rqt_graph

ros2 topic echo /turtle1/pose

rqt_graph 更新

你可以看到/turtlesim节点也在向pose主题发布,新的echo节点已订阅。

在发布带有时间戳的消息时,pub有两种方法自动填写当前时间。对于具有std_msgs/msg/Header的消息,可以将header字段设置为auto以填写stamp字段。

ros2 topic pub /pose geometry_msgs/msg/PoseStamped '{header: "auto", pose: {position: {x: 1.0, y: 2.0, z: 3.0}}}'

如果消息没有使用完整的头部,但只是有一个类型为builtin_interfaces/msg/Time的字段,可以将其设置为值now

ros2 topic pub /reference sensor_msgs/msg/TimeReference '{header: "auto", time_ref: "now", source: "dumy"}'

3.8 查找话题:ros2 topic find

要列出给定类型的所有可用主题,请使用:

ros2 topic find <topic_type>

回想一下,cmd_vel主题的类型是:

geometry_msgs/msg/Twist

使用find命令输出给定消息类型时的可用主题:

ros2 topic find geometry_msgs/msg/Twist
/turtle1/cmd_vel

3.9 清理运行现场

此时,你将有许多节点在运行。别忘了通过在每个终端中输入Ctrl+C来停止它们。

3.10 小结

节点通过主题发布信息,允许任意数量的其他节点订阅并访问该信息。在本教程中,你使用rqt_graph和命令行工具检查了多个节点在主题上的连接。你现在应该对数据如何在 ROS 2 系统中移动有了很好的了解。

04. 下一步

接下来,你将学习 ROS 图中的另一种通信类型,教程为理解 ROS2 服务/参数/动作三种通信机制