引言

       这个教程是和之前的有些联系的,基础以及重复的知识我就不做讲解啦,本身这个内容也不是太难,关于之前的话题通信以及怎么创建msg或者srv大家可以看之前的教程。

传送门:
ROS发布者(Publisher)和订阅者(Subscriber)的python编程实现(讲解超级详细)
创建ROS消息(msg)和服务(srv)

接下来让我们进入正题吧!

一、创建功能包

       我们在之前的工作空间创建一个service的功能包,用来存放这个教程的所有文件:

在这里插入图片描述
       让我们先整体看一下这个功能包的文件,主要有一个客户端和一个服务端程序,然后还有一个srv文件:

在这里插入图片描述
AddTwoInts.srv内容如下:

int64 A
int64 B
---
int64 Sum

二、编写服务端节点

       我们将创建简单的服务端节点add_two_ints_server,该节点将接收两个整数,并返回它们的和。
整体代码如下:

#!/usr/bin/env python

from __future__ import print_function
from service.srv import AddTwoInts,AddTwoIntsResponse #注意是功能包名.srv
import rospy

def handle_add_two_ints(req):
    print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b)))
    return AddTwoIntsResponse(req.a + req.b)

def add_two_ints_server():
    rospy.init_node('add_two_ints_server')
    s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
    print("Ready to add two ints.")
    rospy.spin()

if __name__ == "__main__":
    add_two_ints_server()

       我们使用rospy.init_node()声明我们的节点,然后再声明我们的服务:

 s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)

       这声明了一个名为add_two_ints的新服务,其服务类型为AddTwoInts。所有的请求(request)都传递给了handle_add_two_ints函数。handle_add_two_intsAddTwoIntsRequest的实例调用,返回AddTwoIntsResponse实例。就像订阅者中的例子一样,rospy.spin()可以防止程序在服务关闭之前退出。

如何实现一个服务端节点?
1.初始化ROS节点;
2.创建Server实例;
3.循环等待服务请求,进入回调函数;
4.在回调函数中完成服务功能的处理,并反馈应答数据。

二、编写客户端节点

整体代码如下:

#!/usr/bin/env python

from __future__ import print_function 

import sys
import rospy
from service.srv import * #注意是功能包名.srv

def add_two_ints_client(x, y):
    rospy.wait_for_service('add_two_ints')
    try:
        add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
        resp1 = add_two_ints(x, y)
        return resp1.sum
    except rospy.ServiceException as e:
        print("Service call failed: %s"%e)

def usage():
    return "%s [x y]"%sys.argv[0]

if __name__ == "__main__":
    if len(sys.argv) == 3:
        x = int(sys.argv[1])
        y = int(sys.argv[2])
    else:
        print(usage())
        sys.exit(1)
    print("Requesting %s+%s"%(x, y))
    print("%s + %s = %s"%(x, y, add_two_ints_client(x, y)))

       对于客户端来说不需要调用init_node()。我们首先调用:

rospy.wait_for_service('add_two_ints')

       这是一种很方便的方法,可以让在add_two_ints服务可用之前一直阻塞。

add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)

       这里我们为服务的调用创建了一个句柄(handle)。

 resp1 = add_two_ints(x, y)
 return resp1.sum

       然后我们可以使用这个句柄,就像普通的函数一样调用它。

       因为我们已经将服务的类型声明为AddTwoInts,它会为你生成AddTwoIntsRequest对象。如果调用失败,rospy.ServiceException将会抛出,所以应该编写一个合适的try/except部分(异常处理)。

如何实现一个客户端节点?
1.初始化ROS节点;
2.创建一个Client实例;
3.发布服务请求数据;
4.等待Server处理之后的应答结果。

三、编译

       我们需要在package.xml添加如下内容:

在这里插入图片描述

CMakeLists.txt整体如下:
在这里插入图片描述
       然后进行编译。
       这些内容之前都有讲解,这里就不一一赘述啦。

四、运行结果

在这里插入图片描述

五、服务通信机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、话题与服务区别

在这里插入图片描述

本文内容参考:
ROS官方wiki:http://wiki.ros.org
古月——ROS入门21讲
《ROS机器人开发实践》

如有错误或者不足之处,欢迎大家留言指正!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐