zoukankan      html  css  js  c++  java
  • ROS入门笔记(十一):编写与测试简单的Service和Client (Python)

    ROS入门笔记(十一):编写与测试简单的Service和Client (Python)

    [TOC]

    01 导读

    C++代码必须通过编译生成可执行文件;

    python代码是可执行文件,不需要编译;

    • 开发的功能包都放在catkin_ws这样一个工作空间里;
    • 新建的功能包取名为service_example,实现两个整数求和为例,client端节点向server端节点发送a、b的请求,server端节点返回响应sum=a+b给client端节点;
    • 通信网络结构如图所示:

    服务编程流程

    • 创建服务器
    • 创建客户端
    • 添加编译选项
    • 运行可执行程序

    02 功能包的创建

    在catkin_ws/src/目录下新建功能包service_example,并在创建时显式的指明依赖rospy和std_msgs,依赖std_msgs将作为基本数据类型用于定义我们的服务类型。打开命令行终端,输入命令:

    $ cd ~/catkin_ws/src
    
    #创建功能包topic_example时,显式的指明依赖rospy和std_msgs,
    #依赖会被默认写到功能包的CMakeLists.txt和package.xml中
    $ catkin_create_pkg service_example rospy std_msgs
    

    03 在功能包中创建自定义服务类型

    • 服务(srv): 一个srv文件描述一项服务。它包含两个部分:请求和响应。

    • 服务类型的定义文件都是以*.srv为扩展名,srv文件则存放在功能包的srv目录下。

    • 服务通信过程中服务的数据类型需要用户自己定义,与消息不同,节点并不提供标准服务类型。

    3.1 定义srv文件

    srv文件分为请求和响应两部分,由'---'分隔。

    在功能包service_example目录下新建srv目录,然后在service_example/srv/目录中创建AddTwoInts.srv文件

    int64 a
    int64 b
    ---
    int64 sum
    

    其中 ab 是请求, 而sum 是响应。

    3.2 在package.xml中添加功能包依赖

    srv文件被转换成为C++,Python和其他语言的源代码:

    查看package.xml, 确保它包含一下两条语句:

    <build_depend>message_generation</build_depend>
    <exec_depend>message_runtime</exec_depend>
    

    如果没有,添加进去。 注意,在构建的时候,我们只需要"message_generation"。然而,在运行的时候,我们只需要"message_runtime"。

    3.3 在CMakeLists.txt添加编译选项

    第一步,增加message_generation

    打开功能包中的CMakeLists.txt文件,利用find_packag函数,增加对message_generation的依赖,这样就可以生成消息了。 你可以直接在COMPONENTS的列表里增加message_generation,就像这样:

    find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation
      )
    

    有时候你会发现,即使你没有调用find_package,你也可以编译通过。这是因为catkin把你所有的功能包都整合在一起,因此,如果其他的功能包调用了find_package,你的功能包的依赖就会是同样的配置。但是,在你单独编译时,忘记调用find_package会很容易出错。

    第二步,删掉#,去除对下边语句的注释:

    找到如下代码块:

    # add_service_files(
    #   FILES
    #   Service1.srv
    #   Service2.srv
    # )
    

    用你自己定义的srv文件名(AddTwoInts.srv)替换掉那些Service*.srv文件,修改好后的代码如下:

    add_service_files(
      FILES
      AddTwoInts.srv
    )
    

    第三步,msg和srv都需要的步骤

    CMakeLists.txt中找到如下部分:

    # generate_messages(
    #   DEPENDENCIES
    # #  std_msgs  # Or other packages containing msgs
    # )
    

    去掉注释并附加上所有你消息文件所依赖的那些含有.msg文件的功能包(这个例子是依赖std_msgs,不要添加roscpp,rospy),结果如下:

    generate_messages(
      DEPENDENCIES
      std_msgs
    )
    

    原因:generate_messages的作用是自动创建我们自定义的消息类型 .msg与服务类型 .srv相对应的 .h,由于我们定义的服务类型使用了std_msgs中的int64基本类型,所以必须向generate_messages指明该依赖。

    第四步,由于增加了新的消息,所以我们需要重新编译我们的功能包:

    目的:查看配置是否有问题

    $ cd ~/catkin_ws
    $ catkin_make -DCATKIN_WHITELIST_PACKAGES="service_example" 
    

    所有在msg路径下的.msg文件都将转换为ROS所支持语言的源代码。生成的C++头文件将会放置在~/catkin_ws/devel/include/service_example/。 Python脚本语言会在 ~/catkin_ws/devel/lib/python2.7/dist-packages/service_example/msg 目录下创建。

    04 查看自定义的服务消息

    通过<功能包名/服务类型名>找到该服务,打开命令行终端,输入命令:

    $ source ~/catkin_ws/devel/setup.bash
    
    $ rossrv show service_example/AddTwoInts
    

    05 功能包的源代码编写

    功能包中需要编写两个独立可执行的节点,一个节点用来作为client端发起请求,另一个节点用来作为server端响应请求,所以需要在新建的功能包service_example/scripts目录下新建两个文件server.py和client.py,并将下面的代码分别填入。

    5.1 编写Service节点(server.py)

    将创建一个简单的service节点("server"),该节点将接收到两个整形数字,并返回它们的和。

    如何实现一个服务器

    • 初始化ROS节点;
    • 创建Server实例;
    • 循环等待服务请求,进入回调函数;
    • 在回调函数中完成服务功能的处理,并反馈应答数据。

    在service_example包中创建scripts / server.py文件:

    #!/usr/bin/env python
    
    from service_example.srv import AddTwoInts,AddTwoIntsResponse
    import rospy
    
    def handle_add_two_ints(req):
        print "Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))
     
     #因为我们已经将服务的类型声明为AddTwoInts,所以它会为您生成AddTwoIntsRequest对象(可以自由传递)
        return AddTwoIntsResponse(req.a + req.b)    # AddTwoIntsResponse由服务生成的返回函数
    
    def add_two_ints_server():
        rospy.init_node('add_two_ints_server')  # 声明节点为add_two_ints_server
       
        #定义服务器节点名称,服务类型,处理函数
    	#处理函数调用实例化的AddTwoIntsRequest接收请求和返回实例化的AddTwoIntsResponse
        s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
        print "Ready to add two ints."
        rospy.spin()   # 就像订阅者示例一样,rospy.spin()使代码不会退出,直到服务关闭;
    
    if __name__ == "__main__":
        add_two_ints_server()
    

    在~/catkin_ws/src/service_example下,让节点可执行:

    $ chmod +x scripts/server.py
    

    5.2 编写Client节点(client.py)

    如何实现一个客户端

    • 初始化ROS节点;
    • 创建一个Client实例;
    • 发布服务请求数据;
    • 等待Server处理之后的应答结果。

    在service_example包中创建scripts / client.py文件,并在其中粘贴以下內容:

    #!/usr/bin/env python
    
    """ 
    导入sys模块,sys.argv的功能是在外部向程序的内部传递参数。sys.argv(number),number=0的时候是脚本的名称
    """
    import sys
    import rospy
    from service_example.srv import *
    
    def add_two_ints_client(x, y):
        # 等待接入服务节点
        # 第二句是调用wait_for_service,阻塞直到名为“add_two_ints”的服务可用。
        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 
        #如果调用失败,可能会抛出rospy.ServiceException
        except rospy.ServiceException, 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))
    

    在~/catkin_ws/src/service_example节点可执行:

    $ chmod +x scripts/client.py
    

    代码解析:

    我们可以像普通函数一样使用这个句柄并调用它:

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

    因为我们已经将服务的类型声明为AddTwoInts,所以它会为你生成AddTwoIntsRequest对象(可以自由传递)。返回值是AddTwoIntsResponse对象。如果调用失败,可能会抛出rospy.ServiceException,因此你应该设置适当的try/except块。

    06 功能包的编译

    我们使用CMake作为构建系统,是的,即使是Python节点也必须使用它。这是为了确保创建消息和服务时自动生成Python代码。

    $ cd ~/catkin_ws
    $ catkin_make -DCATKIN_WHITELIST_PACKAGES="service_example"    
    

    07 测试service和client

    7.1 运行Service

    第一步,打开一个命令行终端:

    $ roscore
    

    第二步,打开第二个命令行终端:

    # 用rosrun <package_name> <node_name>启动功能包中的发布节点。
    $ source ~/catkin_ws/devel/setup.bash    # 激活catkin_ws工作空间(必须有,必不可少) 
    $ rosrun service_example server.py       # (python版本)
    

    你将看到如下的输出信息:

    Ready to add two ints.              # Server节点启动后的日志信息
    

    7.2 运行Client

    现在,运行Client并附带一些参数:

    打开第三个命令行客户端:

    $ source ~/catkin_ws/devel/setup.bash     # 激活catkin_ws工作空间(必须有,必不可少) 
    $ rosrun service_example client.py 1 3    # (Python)      
    

    你将会看到如下的输出信息:

    # Client启动后发布服务请求,并成功接收到反馈结果
    Requesting 1+3
    1 + 3 = 4
     
    # Server接收到服务调用后完成加法求解,并将结果反馈给Client              
    Returning [1 + 3 = 4]         
    

    现在,你已经成功地运行了你的第一个Service和Client程序。

    微信公众号:喵哥解说 公众号介绍:主要研究机器学习、计算机视觉、深度学习、ROS等相关内容,分享学习过程中的学习笔记和心得!期待您的关注,欢迎一起学习交流进步!同时还有1200G的Python视频和书籍资料等你领取!!!

  • 相关阅读:
    Pytorch安装
    使用Inception-v3进行图像分类
    Tensorflow模型保存与载入
    LSTM用于MNIST手写数字图片分类
    卷积神经网络应用于MNIST数据集分类
    手工设计神经MNIST使分类精度达到98%以上
    关于优化器的选择
    手动设计神经网络进行MNIST分类
    Matplotlib学习
    Apiview使用方法
  • 原文地址:https://www.cnblogs.com/IT-cute/p/12989993.html
Copyright © 2011-2022 走看看