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

本文涉及的产品
资源编排,不限时长
简介: ROS入门笔记(十一):编写与测试简单的Service和Client (Python)

01 导读


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


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


开发的功能包都放在catkin_ws这样一个工作空间里;

新建的功能包取名为service_example,实现两个整数求和为例,client端节点向server端节点发送a、b的请求,server端节点返回响应sum=a+b给client端节点;

通信网络结构如图所示:


aHR0cHM6Ly9naXRlZS5jb20vSVQtY3V0ZS9QaWNiZWQvcmF3L21hc3Rlci9pbWcvaW1hZ2UtMjAyMDA0MjIyMDMyNDU4MzgucG5n.png

服务编程流程


创建服务器

创建客户端

添加编译选项

运行可执行程序


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

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


aHR0cHM6Ly9naXRlZS5jb20vSVQtY3V0ZS9QaWNiZWQvcmF3L21hc3Rlci9pbWcvaW1hZ2UtMjAyMDA0MjMwMDM3NDQ0NzMucG5n.png


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创建VPC和VSwitch
本场景主要介绍如何利用阿里云资源编排服务,定义资源编排模板,实现自动化创建阿里云专有网络和交换机。
阿里云资源编排ROS使用教程
资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。编排模板同时也是一种标准化的资源和应用交付方式,并且可以随时编辑修改,使基础设施即代码(Infrastructure as Code)成为可能。 产品详情:https://www.aliyun.com/product/ros/
目录
相关文章
|
1月前
|
Ubuntu 机器人 Linux
|
30天前
|
测试技术 持续交付 开发者
探索自动化测试的无限可能:从入门到精通
在软件开发领域,确保产品质量是至关重要的。自动化测试作为一种高效、可靠的测试方法,正逐渐成为行业标准。本文将带你深入了解自动化测试的世界,从基础概念到实践技巧,帮助你掌握这一强大的工具。无论你是初学者还是有经验的开发者,都能从中获得宝贵的知识和启发。
|
1月前
|
Java 测试技术 开发者
初学者入门:掌握单元测试的基础与实践
【10月更文挑战第14天】单元测试是一种软件测试方法,它验证软件中的最小可测试单元——通常是单独的函数或类——是否按预期工作。单元测试的目标是确保每个模块在其自身范围内正确无误地运行。这些测试应该独立于其他模块,并且应该能够反复执行而不受外部环境的影响。
52 2
|
5天前
|
存储 传感器 编解码
ROS机器视觉入门:从基础到人脸识别与目标检测
【11月更文挑战第9天】从本文开始,我们将开始学习ROS机器视觉处理,刚开始先学习一部分外围的知识,为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。
103 56
|
12天前
|
Java 测试技术 持续交付
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
本文重点讲解如何搭建App自动化测试框架的思路,而非完整源码。主要内容包括实现目的、框架设计、环境依赖和框架的主要组成部分。适用于初学者,旨在帮助其快速掌握App自动化测试的基本技能。文中详细介绍了从需求分析到技术栈选择,再到具体模块的封装与实现,包括登录、截图、日志、测试报告和邮件服务等。同时提供了运行效果的展示,便于理解和实践。
48 4
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
|
7天前
|
Java 测试技术 Android开发
探索自动化测试的奥秘:从入门到精通
【10月更文挑战第37天】本文将带你进入自动化测试的世界,从基础知识到实战案例,逐步揭示自动化测试的神秘面纱。我们将一起探讨如何利用代码来简化测试过程,提高效率,并确保软件质量。无论你是初学者还是有经验的开发者,这篇文章都能为你提供有价值的见解和技巧。让我们一起踏上这段探索之旅吧!
|
13天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
15天前
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
41 3
|
13天前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
30 1
|
29天前
|
传感器 机器人 数据处理
ROS 编程入门的介绍
【10月更文挑战第13天】ROS(Robot Operating System)是一种开源的机器人软件框架,广泛用于机器人开发中。通过使用 ROS,开发者可以轻松创建和管理机器人应用程序。在本节中,我们将介绍如何创建一个 ROS 功能包并实现一些基本功能。