理解 ROS 2 服务
目标: 使用命令行工具学习 ROS 2 中的服务。
教程级别: 初级
预计用时: 10 分钟
服务(service)是 ROS 图中节点间通信的另一种方式。话题(topic)基于发布者-订阅者模型,而服务基于调用-响应模型。话题允许节点订阅数据流并持续获取更新,而服务仅在被客户端明确调用时才返回数据。


本教程中提到的一些概念,如节点和话题,已在之前的教程中介绍。
你需要安装 turtlesim 包。
和之前一样,请记得在每个新打开的终端中 source ROS 2。
启动两个 turtlesim 节点:/turtlesim 和 /teleop_turtle。
打开一个新终端并运行:
$ ros2 run turtlesim turtlesim_node打开另一个终端并运行:
$ ros2 run turtlesim turtle_teleop_key2 ros2 service list
Section titled “2 ros2 service list”在新终端中运行 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 中几乎所有节点都内置了这些用于管理 parameter 的基础设施服务。关于 parameter 的更多内容将在下一个教程中介绍,本教程暂不讨论 parameter 相关服务。
现在,让我们关注 turtlesim 特有的服务:/clear、/kill、/reset、/spawn、/turtle1/set_pen、/turtle1/teleport_absolute 和 /turtle1/teleport_relative。你可能还记得在 turtlesim、ros2 和 rqt 的教程中,曾通过 rqt 与其中一些服务交互过。
3 ros2 service type
Section titled “3 ros2 service type”服务有类型,用于描述请求和响应数据的结构。服务类型的定义方式与话题类型类似,区别在于服务类型包含两部分:一个请求消息和一个响应消息。
要查看某个服务的类型,使用以下命令:
$ ros2 service type <service_name>让我们看看 turtlesim 的 /clear 服务。在新终端中输入命令:
$ ros2 service type /clearstd_srvs/srv/EmptyEmpty 类型表示该服务调用在发送请求时不携带数据,在接收响应时也不返回数据。
3.1 ros2 service list -t
Section titled “3.1 ros2 service list -t”要同时查看所有活跃服务的类型,可以在 list 命令后附加 --show-types 选项(简写为 -t):
$ ros2 service list -t/clear [std_srvs/srv/Empty]/kill [turtlesim_msgs/srv/Kill]/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]...4 ros2 service info
Section titled “4 ros2 service info”要查看特定服务的信息,使用以下命令:
$ ros2 service info <service_name>这将返回服务的类型,以及服务客户端和服务端的数量。
例如,你可以查看 /clear 服务的客户端和服务端数量:
$ ros2 service info /clearType: std_srvs/srv/EmptyClients count: 0Services count: 14.1 ros2 service info —verbose
Section titled “4.1 ros2 service info —verbose”要获取服务的更详细信息,可以在 info 命令后附加 --verbose(或 -v)选项:
$ ros2 service info --verbose <service_name>例如,你可以获取 /clear 服务的详细信息:
$ ros2 service info --verbose /clear这将返回额外的信息,包括服务端所在节点的名称和命名空间,以及底层中间件(RMW)的实现细节。值得注意的是:基于 DDS 的 RMW 实现(connextdds、cyclone、fastrtps)的 Endpoint count 为 2,因为 DDS 会为每个服务端创建两个 endpoint(一个用于请求,一个用于响应)。
Type: std_srvs/srv/Empty Clients count: 0 Services count: 1 Node name: turtlesim Node namespace: / Service type: std_srvs/srv/Empty Service type hash: RIHS01_5888399dedec5ccc85ea6451949fd2c9f97bfdf963f9a588821639fcd31b5d19 Endpoint type: SERVER Endpoint count: 2 GIDs: - Request Reader : 01.0f.93.f0.07.92.53.47.00.00.00.00.00.00.13.04 - Response Writer : 01.0f.93.f0.07.92.53.47.00.00.00.00.00.00.14.03 QoS profiles: - Request Reader : Reliability: RELIABLE History (Depth): KEEP_LAST (10) Durability: VOLATILE Lifespan: Infinite Deadline: Infinite Liveliness: AUTOMATIC Liveliness lease duration: Infinite - Response Writer : Reliability: RELIABLE History (Depth): KEEP_LAST (10) Durability: VOLATILE Lifespan: Infinite Deadline: Infinite Liveliness: AUTOMATIC Liveliness lease duration: Infinite而对于像 rmw_zenoh_cpp 这样非 DDS 的 RMW 实现,Endpoint count 为 1,因为它使用单个 endpoint 同时处理请求和响应。
Type: std_srvs/srv/Empty Clients count: 0 Services count: 1 Node name: turtlesim Node namespace: / Service type: std_srvs/srv/Empty Service type hash: RIHS01_5888399dedec5ccc85ea6451949fd2c9f97bfdf963f9a588821639fcd31b5d19 Endpoint type: SERVER Endpoint count: 1 GID: 59.b0.ea.78.57.3c.52.b4.c6.e9.af.44.22.3d.7c.f5 QoS profile: Reliability: RELIABLE History (Depth): KEEP_LAST (10) Durability: VOLATILE Lifespan: Infinite Deadline: Infinite Liveliness: AUTOMATIC Liveliness lease duration: Infinite如果你想了解更多关于不同 RMW 实现的内容,请参考 关于不同中间件厂商 的概念文档。
5 ros2 service find
Section titled “5 ros2 service find”如果你想查找特定类型的所有服务,可以使用以下命令:
$ ros2 service find <type_name>例如,你可以这样查找所有 Empty 类型的服务:
$ ros2 service find std_srvs/srv/Empty/clear/reset6 ros2 interface show
Section titled “6 ros2 interface show”你可以从命令行调用服务,但首先需要了解输入参数的结构。
$ ros2 interface show <type_name>在 /clear 服务的类型 Empty 上试试:
$ ros2 interface show std_srvs/srv/Empty------ 用于分隔请求结构(上方)和响应结构(下方)。不过,正如你之前了解到的,Empty 类型既不发送也不接收任何数据,所以它的结构自然是空白的。
让我们查看一个请求和响应都携带数据的服务,比如 /spawn。从 ros2 service list -t 的结果中,我们知道 /spawn 的类型是 turtlesim_msgs/srv/Spawn。
要查看 /spawn 服务的请求和响应参数,运行命令:
$ ros2 interface show turtlesim_msgs/srv/Spawnfloat32 xfloat32 yfloat32 thetastring name # Optional. A unique name will be created and returned if this is empty---string name--- 上方的内容告诉我们调用 /spawn 所需的参数。x、y 和 theta 确定生成乌龟的 2D 位姿,name 则是可选的。
--- 下方的信息虽在本例中并非必须了解,但可以帮助你理解服务响应的数据类型。
7 ros2 service call
Section titled “7 ros2 service call”现在你已经了解了什么是服务类型、如何查找服务类型,以及如何查看该类型参数的结构,接下来可以使用以下命令来调用服务:
$ ros2 service call <service_name> <service_type> <arguments><arguments> 部分是可选的。例如,你知道 Empty 类型的服务不需要任何参数:
$ ros2 service call /clear std_srvs/srv/Empty这条命令将清除 turtlesim 窗口中乌龟已经绘制的所有线条。

现在让我们通过调用 /spawn 并传入参数来生成一只新乌龟。从命令行调用服务时,<arguments> 需要使用 YAML 语法。
输入命令:
$ ros2 service call /spawn turtlesim_msgs/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: ''}"requester: making request: turtlesim_msgs.srv.Spawn_Request(x=2.0, y=2.0, theta=0.2, name='')
response:turtlesim_msgs.srv.Spawn_Response(name='turtle2')你将看到命令以结构化方式显示请求内容,随后输出服务响应。
你的 turtlesim 窗口将立即更新,显示新生成的乌龟:

8 ros2 service echo
Section titled “8 ros2 service echo”要查看服务客户端与服务端之间的数据通信,可以使用以下命令对服务执行 echo:
$ ros2 service echo <service_name | service_type> <arguments>ros2 service echo 依赖于服务客户端和服务端的服务内省(introspection)功能,该功能默认禁用。要启用它,需要在创建服务客户端或服务端之后调用 configure_introspection。
启动 introspection_client 和 introspection_service 服务内省演示:
$ ros2 launch demo_nodes_cpp introspect_services_launch.py打开另一个终端,运行以下命令为 introspection_client 和 introspection_service 启用服务内省:
$ ros2 param set /introspection_service service_configure_introspection contents$ ros2 param set /introspection_client client_configure_introspection contents现在我们可以通过 ros2 service echo 查看 introspection_client 和 introspection_service 之间的服务通信。
$ ros2 service echo --flow-style /add_two_ints info: event_type: REQUEST_SENT stamp: sec: 1709408301 nanosec: 423227292 client_gid: [1, 15, 0, 18, 250, 205, 12, 100, 0, 0, 0, 0, 0, 0, 21, 3] sequence_number: 618 request: [{a: 2, b: 3}] response: [] --- info: event_type: REQUEST_RECEIVED stamp: sec: 1709408301 nanosec: 423601471 client_gid: [1, 15, 0, 18, 250, 205, 12, 100, 0, 0, 0, 0, 0, 0, 20, 4] sequence_number: 618 request: [{a: 2, b: 3}] response: [] --- info: event_type: RESPONSE_SENT stamp: sec: 1709408301 nanosec: 423900744 client_gid: [1, 15, 0, 18, 250, 205, 12, 100, 0, 0, 0, 0, 0, 0, 20, 4] sequence_number: 618 request: [] response: [{sum: 5}] --- info: event_type: RESPONSE_RECEIVED stamp: sec: 1709408301 nanosec: 424153133 client_gid: [1, 15, 0, 18, 250, 205, 12, 100, 0, 0, 0, 0, 0, 0, 21, 3] sequence_number: 618 request: [] response: [{sum: 5}] ---节点可以通过服务在 ROS 2 中通信。话题是一种单向通信模式,一个节点发布消息供一个或多个订阅者接收;而服务采用请求/响应模式:客户端向提供服务的节点发出请求,该节点处理请求并返回响应。
通常,服务不适合用于连续调用;话题甚至动作(action)更适合这种场景。
在本教程中,你使用了命令行工具来识别、内省和调用服务。
在下一个教程中,你将学习如何配置节点设置。
查看 这个教程;它是一个使用 Robotis 机械臂的 ROS 服务的出色实际应用。