赞
踩
学习目标:用Python创建并运行简单的服务的客户端和服务端节点。
当节点通过服务进行通讯的时候,发送数据请求的一方我们称之为客户端,接收数据然后相应的一端我们称之为服务器端。请求和响应的数据结构有一个.srv
文件决定。
本例程当中我们做一个加法运算,一个节点发送一个将两个整数相加的请求,另外一个节点对请求进行相应。
知道如何创建工作空间和功能包
为教程新建一个包
cd ~/dev_ws/src
ros2 pkg create --build-type ament_python py_srvcli --dependencies rclpy example_interfaces
由于我们使用了--dependencies
选项,我们就不在需要添加依赖选项。我们只需要填写功能包的描述,维护者的姓名和联系方式,许可这些内容
<description>Python client server tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
更新setup.py
和package.xml
保持一致
maintainer='Your Name',
maintainer_email='you@email.com',
description='Python client server tutorial',
license='Apache License 2.0',
进入dev_ws/src/py_srvcli/src
文件夹,创建service_member_function.py
文件,粘贴下面的内容后保存。
from example_interfaces.srv import AddTwoInts import rclpy from rclpy.node import Node class MinimalService(Node): def __init__(self): super().__init__('minimal_service') self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback) def add_two_ints_callback(self, request, response): response.sum = request.a + request.b self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b)) return response def main(args=None): rclpy.init(args=args) minimal_service = MinimalService() rclpy.spin(minimal_service) rclpy.shutdown() if __name__ == '__main__': main()
第一行加载了服务的消息类型,然后加载了ROS2的Python客户端和节点的类
from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node
接下来定义了一个类过后,在构造函数里面初始化了节点的名字,和服务的名称、类型和回调函数
def __init__(self):
super().__init__('minimal_service')
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
回调函数将接收到的两个数字相加后返回相应,同时往控制台打印消息。
def add_two_ints_callback(self, request, response):
response.sum = request.a + request.b
self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
return response
最后,主函数主类初始化ROS2 Python客户端,创建服务节点,等待处理回调。
打开setup.py
然后在console_scripts
下一行括号之内添加程序入口:
'service = py_srvcli.service_member_function:main',
进入dev_ws/src/py_srvcli/src
文件夹,创建client_member_function.py
文件,粘贴下面的内容后保存。
import sys from example_interfaces.srv import AddTwoInts import rclpy from rclpy.node import Node class MinimalClientAsync(Node): def __init__(self): super().__init__('minimal_client_async') self.cli = self.create_client(AddTwoInts, 'add_two_ints') while not self.cli.wait_for_service(timeout_sec=1.0): self.get_logger().info('service not available, waiting again...') self.req = AddTwoInts.Request() def send_request(self): self.req.a = int(sys.argv[1]) self.req.b = int(sys.argv[2]) self.future = self.cli.call_async(self.req) def main(args=None): rclpy.init(args=args) minimal_client = MinimalClientAsync() minimal_client.send_request() while rclpy.ok(): rclpy.spin_once(minimal_client) if minimal_client.future.done(): try: response = minimal_client.future.result() except Exception as e: minimal_client.get_logger().info( 'Service call failed %r' % (e,)) else: minimal_client.get_logger().info( 'Result of add_two_ints: for %d + %d = %d' % (minimal_client.req.a, minimal_client.req.b, response.sum)) break minimal_client.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()
由于我们需要获得程序输入的参数,我们新加了一行import sys
和服务端类似,首先定义了一个类,然后在构造函数中创建了一个类型名称和服务端一样的节点。
然后white循环一直寻找服务端
之后是发送请求的函数和main函数的定义
在主函数中while循环检测等待服务的相应,同时进行了一个异常处理,如果响应正确打印消息。
打开setup.py
文件,和服务端一样我们添加客户端的程序入口
entry_points={
'console_scripts': [
'service = py_srvcli.service_member_function:main',
'client = py_srvcli.client_member_function:main',
],
},
进入工作空间根目录进行编译
cd ~/dev_ws
colcon build --packages-select py_srvcli
打开一个新的终端,我们运行service服务端
cd ~/dev_ws
source install/setup.bash
ros2 run py_srvcli service
再打开一个新的终端,我们运行client客户端
cd ~/dev_ws
source install/setup.bash
ros2 run cpp_srvcli client 2 3
客户端收到服务端的响应后退出,收到响应如下
[INFO] [minimal_client_async]: Result of add_two_ints: for 2 + 3 = 5
同时服务器端也打印出消息,显示收到客户端的请求
[INFO] [minimal_service]: Incoming request
a: 2 b: 3
现在Ctrl + C关掉两个节点。
操作流程和话题类似,对于Python记得添加程序的入口不然ros2 run
找不到可执行的文件。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。