文章只是个人学习过程中学习笔记,主要参考ROS教程1。
服务(Services):是节点之间通讯的另一种方式。服务允许节点发送一个请求(request)并获得一个响应(response)。

服务通信 是也是ROS通信中最常用的一种基于 请求和响应 模型的通信方式。用于临时性、非周期性、有一定逻辑处理的数据传输场景。
服务通信 通过允许请求-响应通信来实现更紧密的耦合。服务客户端向服务服务器发送请求消息并等待响应(客户端将阻塞,直到收到响应)。服务器将使用请求中的数据构造响应消息并将其发送回客户端。每个服务都有一个类型,它决定了请求和响应消息的结构。服务也有在一个网络中唯一的名称。
ROS Node想通过service方式来传递消息: 首先Server节点和Client节点都要到ROS Master(节点管理器)中进行注册节点名称、服务(Sevice)名称、消息类型、URI地址和端口;然后, ROS Master会根据注册表中的信息匹配Server和 Client,并向Client发送 Server 的 TCP 地址信息;其次,Client 根据Server的信息,使用TCP与Server 建立连接,并请求发送消息;最后, Server 接收、解析请求的数据,并产生响应结果返回给 Client。

1.客户端请求被处理时,需要保证服务器已经启动;
2.服务端和客户端都可以存在多个;
rosservice 2 可以很容易地通过服务附加到ROS客户端/服务器框架上。
| 命令 | 功能 |
|---|---|
rosservice argc | 输出服务的参数 |
rosservice call | 用给定的参数调用服务 |
rosservice find | 按服务的类型查找服务 |
rosservice info | 输出服务的信息 |
rosservice list | 输出活跃的服务 |
rosservice type | 输出服务的类型 |
rosservice uri | 输出服务的ROSRPC uri |
Tips:使用
rosservice帮助选项获取更详细的用法。-h
通过ROS内置的乌龟模拟器(turtlesim)来进行服务通信的实操,在乌龟模拟器的指定位置孵化一个小乌龟。
实现的步骤如下:
步骤1:在新终端中启动roscore
roscore
步骤2:在新终端中启动乌龟模拟器节点turtlesim_node
rosrun turtlesim turtlesim_node
步骤3:通过调试工具rqt_service_caller和编程的方式在乌龟模拟器的指定位置孵化一个小乌龟。
通过rqt_service_caller工具模拟服务请求:
rqt_service_caller工具rosrun rqt_service_caller rqt_service_caller
/spawn,在Request中配置孵化位置、角度、乌龟名字请求参数,然后点击右上角call 发送请求,如果乌龟模拟器响应成功,会在Response中显示结果,并在乌龟模拟器turtlesim中孵化出一个小乌龟。
在beginner_tutorials软件包的src目录下创建服务客户端源文件:
roscd beginner_tutorials
cd src
touch turtle_spawn_client.cpp
#include "ros/ros.h"
#include "turtlesim/Spawn.h"
int main(int argc, char **argv)
{
setlocale(LC_ALL,"");
/* 初始化ROS节点 */
ros::init(argc,argv,"turtle_spawn_client");
/* 为这个节点创建句柄 */
ros::NodeHandle nh;
/* 创建service client 指定服务类型为turtlesim::Spawn */
ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn");
/* 等待服务器启动 */
ros::service::waitForService("/spawn");
/* 实例化服务数据类型,并给成员request赋值 */
turtlesim::Spawn spawn;
spawn.request.x = 2;
spawn.request.y = 8;
spawn.request.theta = 1.8;
spawn.request.name = "new_turtle1";
/* 服务调用 */
if(client.call(spawn))
{
ROS_INFO("小乌龟[%s]已孵化", spawn.response.name.c_str());
}
else
{
ROS_INFO("小乌龟孵化失败!");
}
return 0;
}
只需将这几行添加到CMakeLists.txt文件的底部:
add_executable(turtle_spawn_client src/turtle_spawn_client.cpp)
target_link_libraries(turtle_spawn_client ${catkin_LIBRARIES})
add_dependencies(turtle_spawn_client ${PROJECT_NAME}_gencpp)
在你的工作空间下执行catkin_make编译,将turtle_spawn_client.cpp编译成可执行文件turtle_spawn_client。编译后,在终端中执行过程如下所示。

在beginner_tutorials软件包的scripts目录下创建服务客户端源文件:
roscd beginner_tutorials
cd scripts
touch turtle_client.py
chmod +x turtle_client.py
#!/usr/bin/env python
# encoding: utf-8
import rospy
from turtlesim.srv import Spawn,SpawnRequest
def turtle_spawn_client():
# 初始化ROS节点
rospy.init_node("turtle_spawn_client")
# 创建sevice client
spawn_client = rospy.ServiceProxy('/spawn',Spawn)
# 等待服务开启
spawn_client.wait_for_service()
# 创建请求数据
spawn_req = SpawnRequest()
spawn_req.x = 8.0
spawn_req.y = 8.0
spawn_req.theta = 0.8
spawn_req.name = "new_turtle2"
try:
# 调用服务并获取相应结果
spawn_res = spawn_client.call(spawn_req)
rospy.loginfo("小乌龟[%s]龟已孵化", spawn_res.name)
except rospy.ServiceException as e:
rospy.loginfo("小乌龟孵化失败!")
if __name__ == '__main__':
turtle_spawn_client()
只需catkin_install_python中添加 scripts/turtle_spawn_client.py即可:
# 安装python可执行脚本
catkin_install_python(PROGRAMS
scripts/turtle_spawn_client.py
...
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
其实这个例子很简单,不需要编译,直接执行python文件就行。但是我们还是养成习惯吧,每次创建和修改代码后,就catkin_make编译一下,即使是Python节点也必须使用它。这是为了确保能为创建的消息和服务自动生成Python代码。

ROS提供了一些命令行工具帮助我们查看Service的信息。通过小乌龟模拟器(turtlesim)来实操服务命令。
rosservice list 输出活跃(当前正在运行)服务的信息。

list命令显示有两个与rosout节点有关的服务:/rosout/get_loggers和/rosout/set_logger_level。其余的都是turtlesim节点提供了9个服务。
rosservice argc[service] 输出服务的所有参数。

rosservice type [service] 输出服务的类型。

rosservice call [service] 按服务的类型查找服务。

rosservice uri 输出服务的ROSRPC uri。

rosservice info [service] 输出服务的信息。

rosservice call [service] [args] 用给定的参数调用服务。
# 调用服务 /spawn ,给定参数:位置(8.0,2.0)、角度为1.8、名字为new_turtle3,然后孵化小乌龟。
rosservice call /spawn 8.0 2.0 1.8 "new_turtle3"

ROS.otg. ROS教程[EB/OL]. 2020-12-22[2022-7-5].
http://wiki.ros.org/cn/ROS/Tutorials. ↩︎
ROS.otg. rosservice[EB/OL]. 2020-12-22[2022-7-5].
https://wiki.ros.org/rosservice. ↩︎