1. 服务通信是什么
在ROS中,服务通信机制是一种点对点的通信方式,用于节点之间的请求和响应。它允许一个节点(服务请求方)向另一个节点(服务提供方)发送请求,并等待响应。
服务通信机制在ROS中使用以下两个概念:
服务(Service):服务是一种在ROS中定义的一对相关消息类型,包括请求消息和响应消息。请求消息用于向服务提供方发送请求,而响应消息用于服务提供方返回响应给请求方。
服务节点(Service Node):服务节点是一个ROS节点,它提供了一个或多个服务。服务节点注册自己提供的服务,并等待来自其他节点的请求。一旦接收到请求,服务节点执行相应的操作,并将响应发送回请求方。
下面是服务通信的基本流程:
-
服务定义
首先,需要在ROS中定义一个服务,包括请求消息和响应消息的格式。这可以使用ROS的消息描述语言(如.srv文件)来完成。 -
服务节点注册
服务提供方节点将自己注册为一个服务节点,并指定所提供的服务类型。 -
请求发送
服务请求方节点创建一个请求消息实例,并将其发送到服务提供方节点。 -
请求处理
服务提供方节点接收到请求消息后,执行相应的操作,可能包括计算、处理数据等。 -
响应发送
服务提供方节点生成一个响应消息,并将其发送回请求方节点。 -
响应接收
请求方节点接收到响应消息后,可以根据需要进行后续处理。
下面以打车的案例简单描述ROS中服务通信机制的场景:
(1)Master(管理者):Master是滴滴打车平台的中央控制器,负责协调和管理打车服务请求。在这个案例中,滴滴打车的后台系统可以充当Master的角色。它接收乘客的打车请求,处理请求并将其分派给合适的司机。
(2)Server(司机):Server指的是滴滴打车平台上的司机角色。他们是提供车辆和打车服务的实际执行者。当Master将乘客的打车请求分派给司机时,司机将接收到请求并决定是否接受该请求。
(3)Client(乘客):Client是需要使用滴滴打车服务的乘客。在这个案例中,乘客作为Client,他们使用滴滴打车应用程序来请求打车服务。乘客通过应用程序选择目的地、车型等选项,并发起打车请求。
上图参考了赵虚左老师的课程
2. 服务通信有什么用
以下是一些常见的ROS服务通信应用举例:
(1)传感器数据请求:在一个机器人系统中,可以使用服务通信来请求特定传感器(如摄像头、激光雷达)的数据。例如,一个节点可以向摄像头节点发送请求,要求获取当前的图像数据。
(2)控制指令发送:通过服务通信,可以向执行器节点发送控制指令,控制机器人的运动或执行特定任务。例如,一个导航节点可以向底盘控制节点发送请求,要求机器人移动到特定位置。
(3)参数配置和调整:服务通信可用于动态地配置和调整节点的参数。例如,在机器人系统中,可以使用服务通信来请求更改底盘控制节点的运动速度或其他参数,以适应不同的任务需求。
(4)数据处理和计算:通过服务通信,可以请求进行特定的数据处理或计算操作。例如,一个节点可以向图像处理节点发送请求,要求对图像进行特定的算法处理,如目标识别或图像滤波。
(5)任务协作和分布式计算:在多机器人系统中,可以使用服务通信来实现任务的协作和分布式计算。不同机器人节点可以通过服务通信交换任务信息、共享计算结果,并相互协作完成复杂的任务。
3.编写服务通信(客户端-服务端)的python案例
(1)任务要求
实现简单的整数加法运算。客户端提交两个数据至服务端,服务端相应之后将求和结果发送至客户端。
(2)流程
① 编写服务消息文件srv文件。(注意:与话题通信的不同,为了实现服务通信,需要定义服务消息类型,服务消息文件(.srv)描述了请求和响应的消息格式。服务服务器根据服务消息文件生成服务接口,服务客户端使用该接口与服务服务器进行通信。因此在编写客户端和服务端的python程序之前,我们需要先编写好服务消息文件。)
② 编写客户端和服务端的python程序。
(3)编程实现流程
① 创建功能包(默认继续在之前ROS学习笔记(二)上新建功能包server_client,然后新建一个scripts文件夹,用来编写python的服务通信程序,再新建一个srv文件,新建好之后如下图。
② 定义srv文件
- 按照固定格式创建srv文件
在srv文件夹下新建文件AddTwoInts.srv。也就是我们的服务消息srv文件)
编辑文件的内容如下。
# AddTwoInts.srv
int64 a
int64 b
---
int64 sum
- 编辑配置文件
1)在package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
2)在CMakeLists.txt编辑 srv 相关配置
第一处:
message_generation
第二处:要改成你srv文件名
AddTwoInts.srv
第三处:
generate_messages(
DEPENDENCIES
std_msgs
)
- 编译之后生成中间文件(编译 crtl + shift +b)
这样就完成服务消息srv的创建了。接下来来时编写服务通信的程序
(4)编写服务端和客户端的程序
① 我们在创建好的script文件内,继续创建add_two_ints_server.py和add_two_ints_client.py的Python文件。
- 服务端实现:
#!/usr/bin/env python
#coding:utf-8
#上面的coding:utf-8是放置程序有中文报错的
import rospy
from server_client.srv import AddTwoInts, AddTwoIntsResponse
def handle_add_two_ints(req):
result = req.a + req.b
rospy.loginfo("Received request: %d + %d = %d", req.a, req.b, result)
return AddTwoIntsResponse(result)
def add_two_ints_server():
rospy.init_node('add_two_ints_server')
rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
rospy.loginfo("Ready to add two ints.")
rospy.spin()
if __name__ == '__main__':
add_two_ints_server()
- 客户端实现:
#!/usr/bin/env python
#coding:utf-8
import rospy
from server_client.srv import AddTwoInts, AddTwoIntsRequest
import sys
def add_two_ints_client(x, y):
rospy.wait_for_service('add_two_ints')
try:
add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
req = AddTwoIntsRequest()
req.a = x
req.b = y
resp = add_two_ints(req)
return resp.sum
except rospy.ServiceException as e:
rospy.logerr("Service call failed: %s", str(e))
if __name__ == '__main__':
rospy.init_node('add_two_ints_client')
x = int(sys.argv[1])
y = int(sys.argv[2])
result = add_two_ints_client(x, y)
rospy.loginfo("%d + %d = %d", x, y, result)
② 打开python可执行权限,然后编辑配置文件CMakeLists.txt