3. ROS2服务通信实现

任务目标

本案例将创建一个ROS2服务通信的最小可运行示例:一个服务端节点提供两个整数相加的服务,一个客户端节点发起请求并接收响应。同时演示服务不可用时客户端的超时处理机制。

环境准备

需要已安装ROS2(Humble或更高版本),并完成环境source。本案例使用Python实现,无需额外依赖包。

实现代码

创建文件 add_two_ints_server.py:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class AddTwoIntsServer(Node):
    def __init__(self):
        super().__init__('add_two_ints_server')
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_callback)
        self.get_logger().info('服务端已启动,等待请求...')

    def add_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 = AddTwoIntsServer()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

创建文件 add_two_ints_client.py:

#!/usr/bin/env python3
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().warn('服务不可用,等待中...')
        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, timeout_sec=5.0)
        if future.done() and future.result() is not None:
            return future.result().sum
        else:
            raise TimeoutError('请求超时:服务端未在5秒内响应')

def main(args=None):
    rclpy.init(args=args)
    node = AddTwoIntsClient()
    if len(sys.argv) != 3:
        node.get_logger().error('用法: python3 add_two_ints_client.py <a> <b>')
        rclpy.shutdown()
        return
    try:
        a, b = int(sys.argv[1]), int(sys.argv[2])
        result = node.send_request(a, b)
        node.get_logger().info(f'调用结果: {a} + {b} = {result}')
    except TimeoutError as e:
        node.get_logger().error(str(e))
    except Exception as e:
        node.get_logger().error(f'发生异常: {e}')
    finally:
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

运行与验证

步骤1:打开终端,source ROS2环境后运行服务端:

source /opt/ros/humble/setup.bash
python3 add_two_ints_server.py

步骤2:另开终端,运行客户端发起请求:

source /opt/ros/humble/setup.bash
python3 add_two_ints_client.py 3 5

预期输出:客户端终端显示 调用结果: 3 + 5 = 8,服务端终端显示收到请求的日志。

异常验证:先不启动服务端,直接运行客户端。客户端会持续打印“服务不可用,等待中...”,此时启动服务端,客户端自动连接成功并完成请求。若服务端在请求发出后5秒内无响应(可先启动客户端再立即关闭服务端模拟),客户端会打印超时错误。

通过标准:正常场景下客户端能正确打印两数之和;异常场景下客户端能识别服务不可用并等待,或在超时后给出明确错误提示,不崩溃退出。