理解服务
目标: 使用命令行工具学习 ROS 2 中的服务
教程等级: 初级
预计时长: 10 分钟
背景
服务是 ROS 图中节点之间的另一种通信方式。 服务基于请求-响应模型,而不是话题的发布-订阅模型。 话题允许节点订阅数据流并持续获取更新,而服务只在特定时刻被调用时提供数据。
前提条件
本教程中提到的一些概念,比如 节点 和 topic,在之前的教程中有介绍。
你需要安装 turtlesim package。
如往常一样,不要忘记在 每次打开新终端时 source ROS 2。
任务
1 Setup
启动两个 turtlesim 节点, /turtlesim
和 /teleop_turtle
。
打开一个新终端并运行:
ros2 run turtlesim turtlesim_node
打开另一个终端并运行:
ros2 run turtlesim turtle_teleop_key
2 ros2 service list
在新终端中运行 ros2 service list
命令,返回当前系统中所有运行中服务的列表:
/clear
/kill
/reset
/spawn
/teleop_turtle/describe_parameters
/teleop_turtle/get_parameter_types
/teleop_turtle/get_parameters
/teleop_turtle/list_parameters
/teleop_turtle/set_parameters
/teleop_turtle/set_parameters_atomically
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically
你会发现两个节点都有相同的六个服务,服务名称中都包含 parameters
。
这是因为 ROS 2 中的几乎每个节点都有这些基础服务,参数是基于这些服务构建的。
在下一个教程中会有更多关于参数的内容。
在本教程中,将忽略有关参数服务的讨论。
现在,让我们专注于 turtlesim 特定的服务, /clear
、 /kill
、 /reset
、 /spawn
、 /turtle1/set_pen
、 /turtle1/teleport_absolute
和 /turtle1/teleport_relative
。
你可能还记得在 Use turtlesim, ros2, and rqt 教程中使用 rqt 与这些服务交互。
3 ros2 service type
服务用类型来描述服务的请求和响应数据的结构。 服务类型的定义方式与 topic 类型类似,只是服务类型有两部分:一个用于请求的消息,另一个用于响应的消息。
要查找服务的类型,使用命令:
ros2 service type <service_name>
让我们看看 turtlesim 的 /clear
服务。
在新终端中输入命令:
ros2 service type /clear
这会返回:
std_srvs/srv/Empty
Empty
类型意味着服务调用在请求时不发送数据,在接收响应时也不接收数据。
3.1 ros2 service list -t
要同时查看所有活跃(active)服务的类型,可以在 list
命令后添加 --show-types
选项,简写为 -t
:
ros2 service list -t
这会返回:
/clear [std_srvs/srv/Empty]
/kill [turtlesim/srv/Kill]
/reset [std_srvs/srv/Empty]
/spawn [turtlesim/srv/Spawn]
...
/turtle1/set_pen [turtlesim/srv/SetPen]
/turtle1/teleport_absolute [turtlesim/srv/TeleportAbsolute]
/turtle1/teleport_relative [turtlesim/srv/TeleportRelative]
...
4 ros2 service find
如果你想找到所有特定类型的服务,可以使用命令:
ros2 service find <type_name>
例如,你可以这样找到所有 Empty
类型的服务:
ros2 service find std_srvs/srv/Empty
这会返回:
/clear
/reset
5 ros2 interface show
你可以从命令行请求服务,但首先需要了解输入参数的结构。
ros2 interface show <type_name>
尝试对 /clear
服务的类型 Empty
使用 interface show
命令:
ros2 interface show std_srvs/srv/Empty
这会返回:
---
---
分隔了请求结构(上面)和响应结构(下面)。
但是,正如你之前了解到的,Empty
类型不发送或接收任何数据。
所以,这里它的结构是空的。
让我们看一个会交换数据的服务类型,比如 /spawn
。
从 ros2 service list -t
的结果中,我们知道 /spawn
的类型是 turtlesim/srv/Spawn
。
要查看 /spawn
服务的请求和响应参数,运行命令:
ros2 interface show turtlesim/srv/Spawn
这会返回:
float32 x
float32 y
float32 theta
string name # Optional. A unique name will be created and returned if this is empty
---
string name
---
行上面的信息告诉我们调用 /spawn
需要的参数。
其中 x
、 y
和 theta
确定了生成的小乌龟的 2D 姿态,name
显然是可选的(optional)。
---
行下面的信息不是你在这种情况下需要知道的,但它可以帮助你了解调用返回的响应的数据类型。
6 ros2 service call
现在你知道了服务类型是什么,如何找到服务的类型,以及如何找到该类型的参数结构,你可以使用以下命令请求服务:
ros2 service call <service_name> <service_type> <arguments>
<arguments>
部分是可选的。
例如,你知道 Empty
类型的服务没有任何参数:
ros2 service call /clear std_srvs/srv/Empty
这会清除小乌龟窗口中的所有已经画出来的线条。
现在我们调用 /spawn
服务生成一个新的小乌龟。
在命令行调用中, <arguments>
部分需要使用 YAML 语法。
输入命令:
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: ''}"
你会得到这种 method-style 的输出,显示请求了什么和响应了什么:
requester: making request: turtlesim.srv.Spawn_Request(x=2.0, y=2.0, theta=0.2, name='')
response:
turtlesim.srv.Spawn_Response(name='turtle2')
你的 turtlesim 窗口会立即更新,显示新生成的小乌龟:
总结
ROS 2 中的节点可以使用服务进行通信。 与 topic 不同,服务是一种请求-响应模式,其中客户端向提供服务的节点发出请求,服务处理请求并生成响应。
通常不建议使用服务进行连续调用,topic 或者 action 更适合。
在本教程中,你使用命令行工具识别、检查(introspect)和调用服务。
下一步
在下一个教程中, 理解参数,你将学习如何配置节点设置。
相关内容
这个教程 是一个用 ROS 2 服务控制 Robotis 机械臂的的优秀实际应用。