ros2 pkg create --build-type ament_python py_srv_cli --dependencies rclpy example_interfaces
此处在新建功能包时为其添加了依赖 rclpy和example_interfaces
example_interfaces是ros2的数据类型接口,里面有用于ROS2教学的一些样例数据类型,比如example_interfaces/srv/AddTwoInts就是本示例要使用的数据类型
from example_interfaces.srv import AddTwoInts # 导入需要使用的srv数据类型
import rclpy
from rclpy.node import Node
class MinimalService(Node):
def __init__(self):
super().__init__('minimal_service')
# 创建server
# 数据类型,服务名称,回调函数
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 requestna: %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()
3.添加依赖
在功能包目录下打开package.xml,修改以下内容[可选,不影响使用]
例子:
Examples of minimal publisher/subscriber using rclpy Herman Ye Apache License 2.0
继续添加内容[必须]
当功能包里的代码被执行时,这些语句声明了功能包的依赖
因为在创建功能包时已经添加了依赖,因此此处无需重复添加
4.添加入口点rclpy example_interfaces
打开setup.py,添加入口点
maintainer='Herman Ye', maintainer_email='hermanye233@icloud.com', description='Examples of minimal publisher/subscriber using rclpy', license='Apache License 2.0',
在entry_points下的这个位置添加以下命令
'service = py_srv_cli.service_member_function:main',
最终效果:
entry_points={
'console_scripts': [
'service = py_srv_cli.service_member_function:main',
],
},
二、客户端 Client
1.新建客户端 Client
在和服务端相同的目录下新建client_member_function.py
源码如下:
import sys #客户端节点代码使用sys.argv来访问命令行输入的请求命令的参数,这是客户端的特别之处
from example_interfaces.srv import AddTwoInts # 数据类型导入
import rclpy
from rclpy.node import Node # 节点必备的类
class MinimalClientAsync(Node):
def __init__(self):
super().__init__('minimal_client_async') # 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() #request部分定义
def send_request(self): # 发送函数
self.req.a = int(sys.argv[1]) # 命令行输入的数1
self.req.b = int(sys.argv[2]) # 命令行输入的数2 sys.argv[x]获取了命令行输入的参数
self.future = self.cli.call_async(self.req) #future包含反馈的response
def main(args=None):
rclpy.init(args=args) #初始化rclpy
minimal_client = MinimalClientAsync() # 客户端
minimal_client.send_request() # 客户端发送请求
while rclpy.ok(): # 当ros准备就绪时
rclpy.spin_once(minimal_client) # 循环客户端
if minimal_client.future.done(): # 当future完成时,代表服务端已经完成了服务并且反馈response了result
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()
call_async()
也可以使用call_async()来执行异步呼叫服务,作用和上文中的send_request类似但更简单,上文的send_request有输入参数,因此独立成发送函数
call_async(request) Make a service request and asyncronously get the result. Parameters request (~SrvTypeRequest) – The service request. Return type Future Returns A future that completes when the request does. Raises TypeError if the type of the passed request isn’t an instance of the Request type of the provided service when the client was constructed.
要获取更多信息请查阅rclpy文档
2.添加入口点打开setup.py,添加入口点
在entry_points下的这个位置添加以下命令
'client = py_srv_cli.client_member_function:main',
最终效果:
entry_points={
'console_scripts': [
'service = py_srv_cli.service_member_function:main',
'client = py_srv_cli.client_member_function:main',
],
},
三、测试 客户端-服务-服务端
1.编译
colcon build --packages-select py_srv_cli2.运行
先运行服务端
ros2 run py_srvcli service
随后运行客户端并键入参数
ros2 run py_srvcli client 2 3



