编写一个简单的服务和客户端(Python)
目标: 使用Python创建和运行服务和客户端节点。
教程级别: 初学者
背景
当使用:doc:services <../Beginner-CLI-Tools/Understanding-ROS2-Services/Understanding-ROS2-Services>`的方式进行通信时,发送请求数据的节点称为客户端节点,而响应请求的节点则是服务节点。请求和响应的结构由`
.srv``文件确定。
这里使用的示例是一个简单的整数加法系统;一个节点请求两个整数的和,另一个节点返回结果。
任务
1 创建一个包
在一个新的终端中 源化你的 ROS 2 安装,这样 ros2
命令才能正常工作。
进入在 上一个教程 中创建的 ros2_ws
目录。
请记住,包应该在“src”目录中创建,而不是工作区的根目录。进入“ros2_ws/src”并创建一个新的包:
ros2 pkg create --build-type ament_python py_srvcli --dependencies rclpy example_interfaces
您的终端将返回一条消息,确认已创建名为``py_srvcli``的包及其所有必要的文件和文件夹。
``--dependencies``参数将自动向``package.xml``添加必要的依赖项。``example_interfaces``是包含 the .srv file 的包,您将需要使用它来构建请求和响应的结构:
int64 a
int64 b
---
int64 sum
前两行是请求的参数,在破折号以下是响应。
1.1 更新 package.xml
由于在包创建过程中使用了``--dependencies``选项,您无需手动将依赖项添加到``package.xml``文件中。
同样,确保将描述、维护者电子邮件和姓名以及许可证信息添加到 package.xml
中。
<description>Python client server tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
2 编写服务节点
在``ros2_ws/src/py_srvcli/py_srvcli``目录中创建一个名为``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():
rclpy.init()
minimal_service = MinimalService()
rclpy.spin(minimal_service)
rclpy.shutdown()
if __name__ == '__main__':
main()
2.1 检查代码
第一个 import
语句从 example_interfaces
包中导入了 AddTwoInts
服务类型。接下来的 import
语句导入了 ROS 2 Python 客户端库,具体导入了 Node
类。
from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node
MinimalService
类的构造函数使用名称 minimal_service
初始化节点。然后,它创建一个服务并定义了类型、名称和回调函数。
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
最后,主类初始化了 ROS 2 Python 客户端库,实例化 MinimalService
类以创建服务节点,并旋转节点以处理回调函数。
3.编写客户端节点
在``ros2_ws/src/py_srvcli/py_srvcli``目录中创建一个名为``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, a, b):
self.req.a = a
self.req.b = b
self.future = self.cli.call_async(self.req)
rclpy.spin_until_future_complete(self, self.future)
return self.future.result()
def main():
rclpy.init()
minimal_client = MinimalClientAsync()
response = minimal_client.send_request(int(sys.argv[1]), int(sys.argv[2]))
minimal_client.get_logger().info(
'Result of add_two_ints: for %d + %d = %d' %
(int(sys.argv[1]), int(sys.argv[2]), response.sum))
minimal_client.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
3.1 检查代码
客户端唯一不同的``import``语句是``import sys``。客户端节点代码使用`sys.argv <https://docs.python.org/3/library/sys.html#sys.argv>`__ 来获取请求的命令行输入参数访问权限。
构造函数定义创建一个与服务节点相同类型和名称的客户端。客户端和服务必须具有匹配的类型和名称才能进行通信。
构造函数中的``while``循环每秒检查是否有与客户端类型和名称匹配的服务可用。
构造函数下方是请求定义,然后是``main``函数。
客户端的``main``函数中唯一重要的区别是``while``循环。循环检查``future``以查看服务是否有响应,只要系统正在运行。如果服务发送了响应,结果将写入日志消息中。
3.2 添加一个入口点
像服务节点一样,您还必须添加一个入口点才能运行客户端节点。
您的``setup.py``文件的``entry_points``字段应该如下所示:
entry_points={
'console_scripts': [
'service = py_srvcli.service_member_function:main',
'client = py_srvcli.client_member_function:main',
],
},
4 构建和运行
在构建之前,最好在工作空间的根目录(ros2_ws
)中运行``rosdep``来检查是否缺少依赖项:
rosdep install -i --from-path src --rosdistro humble -y
rosdep 只能在 Linux 上运行,所以您可以跳过下一步。
rosdep 只能在 Linux 上运行,所以您可以跳过下一步。
返回到您的工作空间的根目录 ros2_ws
,并构建您的新包:
colcon build --packages-select py_srvcli
打开一个新的终端,导航到 ros2_ws
,并加载设置文件:
source install/setup.bash
. install/setup.bash
call install/setup.bat
现在运行服务节点:
ros2 run py_srvcli service
节点将等待客户端的请求。
打开另一个终端,并再次从``ros2_ws``内部源化设置文件。启动客户端节点,然后输入由一个空格分隔的两个整数:
ros2 run py_srvcli client 2 3
例如,如果你选择了``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``以停止节点的运行。