ROS实操入门系列(四)

1、service通讯讲解

2、通过实际需求理解Service


Service通讯
需求
Server端实现
调试Server
Client端实现
Service命令行工具


https://www.lanqiao.cn/courses/2947,提供准备好的云主机ros环境,进行实操,课程包括了 Topic 通讯, Service 通讯,ROS 自定义消息,URDF可视化,TF坐标转换等技术要点。每个技术点都会结合例子先把原理讲解清楚,为了达到学以致用的目的,我们会再进行知识拓展,针对每个技术点实现对应的生动有趣的需求,保证学完后会有很大的收获。


Service通讯
ROS提供了节点与节点间通讯的另外一种方式:service通讯。
Service通讯分为client端和server端。
client端负责发送请求(Request)给server端。
server端负责接收client端发送的请求数据。
server端收到数据后,根据请求数据和当前的业务需求,产生数据,将数据(Response)返回给client 端。

Service通讯的特点
(1)同步数据访问
(2)具有响应反馈机制
(3)一个server多个client
(4)注重业务逻辑处理

Service通讯的关键点
(1)service的地址名称
(2)client端访问server端的数据格式
(3)server端响应client端的数据格式

需求
构建一个service通讯。需求是一个client端,一个server端。
server端为client端提供服务。
服务的内容是:帮助client端计算加法求和。

Server端实现
创建节点
rospy.init_node(nodeName)

创建server

rospy.Service(name, service_class, handler)

第一个参数serviceName为服务名称,为一个uri地址
第二个参数是服务需要的数据类型。
第三个参数为服务请求的回调

处理请求的逻辑

def callback(request):
    if not isinstance(request, AddTwoIntsRequest):
        return
    # 获取请求数据
    a = request.a
    b = request.b
    # 返回响应结果
    response = AddTwoIntsResponse()
    response.sum = a + b
    return response
    
回调函数的参数是请求过来的数据
返回值是响应的数据

完整代码

#!/usr/bin/env python
# coding:utf-8
import rospy
from rospy_tutorials.srv import AddTwoInts, AddTwoIntsRequest, AddTwoIntsResponse

def callback(request):
    if not isinstance(request, AddTwoIntsRequest):
        return
    # 获取请求数据
    a = request.a
    b = request.b
    # 返回响应结果
    response = AddTwoIntsResponse()
    response.sum = a + b
    return response

if __name__ == '__main__':
    # 创建节点
    nodeName = "my_server_node"
    rospy.init_node(nodeName)
    # 创建Service Server
    serviceName = "my_service"
    rospy.Service(serviceName, AddTwoInts, callback)
    # 阻塞线程
    rospy.spin()

调试Server
调试server端主要是查看server端是否能接收到请求,并根据请求数据处理相应的业务逻辑,然后返回处理好的结果。在这里,我们只需要模拟client端发送请求就可以了。ROS提供了命令行工具和图形化工具供我们调试开发。
rosservice命令行调试
通过rosservice list命令可以帮助我们查询出当前运行的所有service:
    rosservice list

通过查询的服务名称,来调用此服务
rosservice call /my_service "a:1 b:3"

rosservice call负责调用service。第一个参数是要调用的service的名称,后面的参数是调用时需要传入的参数。

Client端实现
创建节点

rospy.init_node(nodeName)

调用Service

# 等待服务器连接
rospy.wait_for_service(serviceName)
# 创建服务调用代理
client = rospy.ServiceProxy(name, service_class)
# 调用服务
result = client.call(4, 9)


完整代码

#!/usr/bin/env python
# coding:utf-8

import rospy
from rospy_tutorials.srv import AddTwoInts, AddTwoIntsRequest, AddTwoIntsResponse

if __name__ == '__main__':
    # 创建节点
    nodeName = "my_client_node"
    rospy.init_node(nodeName)

    # 创建Service Client
    serviceName = "my_service"
    client = rospy.ServiceProxy(serviceName, AddTwoInts)

    # 等待服务开启
    rospy.wait_for_service(serviceName)

    # 创建请求数据
    request = AddTwoIntsRequest()
    request.a = 4
    request.b = 5
    # 调用服务并且获得响应结果
    response = client.call(request)

    if isinstance(response, AddTwoIntsResponse):
        rospy.loginfo("响应结果: %d" % response.sum)

    # 阻塞线程
    rospy.spin() 

调试Client
通过刚才的server来调试client

Service命令行工具
查询所有的Service

rosservice list

查询service详情

rosservice info 服务地址

查询service传输的数据类型

rosservice type 服务地址

模拟client端调用服务

rosservcie call 服务地址 请求数据

查询service请求参数

rosservice args 服务地址

https://www.lanqiao.cn/courses/2947,提供准备好的云主机ros环境,进行实操,课程包括了 Topic 通讯, Service 通讯,ROS 自定义消息,URDF可视化,TF坐标转换等技术要点。每个技术点都会结合例子先把原理讲解清楚,为了达到学以致用的目的,我们会再进行知识拓展,针对每个技术点实现对应的生动有趣的需求,保证学完后会有很大的收获。