3. ROS2服务通信实现

任务目标

在ROS2中创建自定义服务类型(AddTwoInts.srv),实现一个服务端节点接收两个整数请求并返回求和结果,同时实现一个客户端节点发送请求并接收响应,完整掌握ROS2服务通信的同步请求-响应模式。

环境准备

本案例基于ROS2 Humble版本,需要预先安装ros-humble-desktop。创建工作空间并编译自定义服务接口包:

mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake tutorial_interfaces
mkdir -p tutorial_interfaces/srv

自定义服务类型

在tutorial_interfaces/srv/AddTwoInts.srv中定义请求与响应结构:

int64 a
int64 b
---
int64 sum

编辑tutorial_interfaces/CMakeLists.txt,添加服务生成规则:

rosidl_generate_interfaces(${PROJECT_NAME}
  "srv/AddTwoInts.srv"
)

编译并source环境:

cd ~/ros2_ws && colcon build --packages-select tutorial_interfaces
source install/setup.bash

服务端节点实现

创建service_server.py,注册服务并处理请求:

import rclpy
from rclpy.node import Node
from tutorial_interfaces.srv import AddTwoInts

class ServiceServer(Node):
    def __init__(self):
        super().__init__('service_server')
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.callback)

    def callback(self, request, response):
        response.sum = request.a + request.b
        self.get_logger().info(f'收到请求: {request.a} + {request.b} = {response.sum}')
        return response

def main(args=None):
    rclpy.init(args=args)
    node = ServiceServer()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

客户端节点实现

创建service_client.py,发送请求并等待响应:

import sys
import rclpy
from rclpy.node import Node
from tutorial_interfaces.srv import AddTwoInts

class ServiceClient(Node):
    def __init__(self):
        super().__init__('service_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('等待服务端上线...')
        self.req = AddTwoInts.Request()

    def send_request(self, a, b):
        self.req.a = a
        self.req.b = b
        future = self.cli.call_async(self.req)
        rclpy.spin_until_future_complete(self, future)
        return future.result()

def main(args=None):
    rclpy.init(args=args)
    client = ServiceClient()
    a, b = int(sys.argv[1]), int(sys.argv[2])
    response = client.send_request(a, b)
    client.get_logger().info(f'服务端返回: {a} + {b} = {response.sum}')
    client.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

运行与验证

将两个Python文件放入~/ros2_ws/src/tutorial_pkg/(需先创建包并配置setup.py入口点),编译后分别运行:

# 终端1 - 启动服务端
ros2 run tutorial_pkg service_server

# 终端2 - 启动客户端(传入两个整数)
ros2 run tutorial_pkg service_client 3 5

验证判定标准:

  1. 服务端终端输出收到请求: 3 + 5 = 8;
  2. 客户端终端输出服务端返回: 3 + 5 = 8;
  3. 另开终端执行ros2 service list能看到/add_two_ints服务,执行ros2 service type /add_two_ints返回tutorial_interfaces/srv/AddTwoInts。

以上三条同时满足即表示服务通信闭环成功。若客户端先于服务端启动,客户端会每1秒重试连接直到服务端就绪,无需重启客户端。

客户端节点 service_client.py 服务端节点 service_server.py /add_two_ints 请求: a=3, b=5 响应: sum=8 通信流程:客户端通过call_async发送请求 → 服务端回调处理 → 返回响应 同步等待:客户端使用spin_until_future_complete阻塞直到收到响应