服务通讯是ROS 2中节点通讯的另一种方式,与话题通讯不同,服务通讯具有反馈机制,即客户端发送请求后,服务器处理请求并返回结果。这在需要确认操作结果的场景中非常有用。以下是如何使用Python实现ROS 2节点之间的服务通讯的详细说明。
步骤概述
- 创建工作空间和包
- 编写服务端节点
- 编写客户端节点
- 配置和编译包
- 运行服务和客户端
1. 创建工作空间和包
首先,在你的工作目录中创建一个ROS 2工作空间:
# 复制代码
mkdir -p ~/ros2_ws/src cd ~/ros2_ws colcon build
然后,在工作空间中创建一个新的ROS 2包:
复制代码
cd ~/ros2_ws/src ros2 pkg create --build-type ament_python my_service_package
2. 编写服务端节点
在my_service_package
目录下,创建一个新的Python脚本,例如service_node.py
:
# my_service_package/my_service_package/service_node.py
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts
class AddTwoIntsService(Node):
def __init__(self):
super().__init__('add_two_ints_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(f'Incoming request: a={request.a}, b={request.b}, sum={response.sum}')
return response
def main(args=None):
rclpy.init(args=args)
service = AddTwoIntsService()
rclpy.spin(service)
service.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
3. 编写客户端节点
在my_service_package
目录下,创建另一个Python脚本,例如client_node.py
:
# my_service_package/my_service_package/client_node.py
import sys
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts
class AddTwoIntsClient(Node):
def __init__(self):
super().__init__('add_two_ints_client')
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)
rclpy.spin_until_future_complete(self, self.future)
return self.future.result()
def main(args=None):
rclpy.init(args=args)
client = AddTwoIntsClient()
response = client.send_request()
client.get_logger().info(f'Result of add_two_ints: {response.sum}')
client.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
4. 配置和编译包
更新setup.py
文件,添加入口点以便于启动节点:
from setuptools import setup
package_name = 'my_service_package'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='Your Name',
maintainer_email='yourname@example.com',
description='Examples of ROS 2 service communication',
license='Apache License 2.0',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'service_node = my_service_package.service_node:main',
'client_node = my_service_package.client_node:main',
],
},
)
确保package.xml
中包含以下依赖项:
<exec_depend>rclpy</exec_depend>
<exec_depend>example_interfaces</exec_depend>
在工作空间的根目录下编译包:
cd ~/ros2_ws colcon build
5. 运行服务和客户端
编译完成后,运行服务节点:
source ~/ros2_ws/install/setup.bash
ros2 run my_service_package service_node
在另一个终端中,运行客户端节点:
source ~/ros2_ws/install/setup.bash
ros2 run my_service_package client_node 5 3
这里,client_node
脚本会发送两个整数(5和3)到服务端,服务端将返回它们的和,并在客户端打印结果。
总结
通过以上步骤,你可以使用Python成功实现ROS 2中的服务通讯。服务端节点负责处理请求并返回结果,而客户端节点发送请求并接收结果。这种通讯方式适用于需要确认操作结果的场景,例如生成对象、计算任务等。