🤖 roboto_origin_03 Wiki
首页 / 部署 / ROS2 服务接口调用

inference_node 在启动时会注册 10 个 std_srvs::srv::Trigger 类型的服务,全部挂载在根命名空间下,服务名分别为 /init_motors/deinit_motors/start_inference/stop_inference/reset_joints/set_zeros/clear_errors/refresh_joints/read_joints/read_imu。这些接口将底层 RobotInterface 的硬件操作与推理生命周期管理暴露为标准的 ROS2 服务,开发者既可以通过命令行快速调试,也可以在自己的节点中以编程方式异步调用。

Sources: inference_node.hpp

服务接口架构

下面的架构图展示了 inference_node 作为服务提供方与外部调用者之间的交互关系。所有服务均通过 ROS2 内部机制分发,调用方无需关心底层 CAN/串口细节。

graph LR
    A[CLI / 外部节点] -->|ros2 service call| B(inference_node)
    B --> C[/init_motors]
    B --> D[/deinit_motors]
    B --> E[/start_inference]
    B --> F[/stop_inference]
    B --> G[/reset_joints]
    B --> H[/set_zeros]
    B --> I[/clear_errors]
    B --> J[/refresh_joints]
    B --> K[/read_joints]
    B --> L[/read_imu]

Sources: inference_node.hpp

服务列表与前置条件

各服务的功能简述与前置条件如下表所示。由于接口统一使用 std_srvs::srv::Trigger,请求体为空,调用方只需关注服务名称与返回状态。

服务名 功能说明 前置条件 典型成功返回
/init_motors 初始化所有电机并进入可控状态 电机未初始化 Motors initialized successfully
/deinit_motors 关闭电机驱动并释放资源 电机已初始化 Motors deinitialized successfully
/start_inference 启动策略推理循环 推理未运行 Inference started
/stop_inference 暂停策略推理循环 推理正在运行 Inference stopped
/reset_joints 将所有关节复位到默认角度 推理已停止、电机已初始化 Joints reset successfully
/set_zeros 将当前姿态写入电机零点 推理已停止、电机已初始化 Zeros set successfully
/clear_errors 清除电机错误状态 RobotInterface 已创建 Errors cleared successfully
/refresh_joints 刷新关节状态(重新使能或同步) 电机已初始化 Motors refresh successfully
/read_joints 立即读取并发布关节状态到 /joint_states 电机已初始化 Joints read successfully
/read_imu 立即读取并发布 IMU 数据到 /imu RobotInterface 已创建 IMU read successfully

Sources: ros_interface.cpp

调用方式对比

ROS2 服务支持命令行与编程两种调用方式。命令行适合单次调试,而编程客户端适合集成到自动化流程。下表对比了两种方式的适用场景。

调用方式 适用场景 关键命令 / API
CLI 单次调试、快速验证 ros2 service call /service_name std_srvs/srv/Trigger
Python 客户端 自定义节点、定时任务 rclpy 异步客户端 call_async

Sources: README_CN.md

命令行调用示例

通过 ROS2 命令行工具调用服务是最直接的调试手段。所有服务均采用相同的标准格式,仅需替换服务名称即可。下面给出完整的服务调用示例与对应返回说明。

# 初始化电机
ros2 service call /init_motors std_srvs/srv/Trigger

# 开始推理
ros2 service call /start_inference std_srvs/srv/Trigger

# 停止推理
ros2 service call /stop_inference std_srvs/srv/Trigger

# 去初始化电机
ros2 service call /deinit_motors std_srvs/srv/Trigger

Sources: README_CN.md

Python 客户端示例

对于需要在自定义节点中集成服务调用的开发者,可使用 rclpy 编写异步客户端。以下示例展示了如何调用 /start_inference 并处理返回结果。由于 inference_node 中的服务类型均为 std_srvs::srv::Trigger,客户端代码可复用于任意服务,只需修改话题名。

import rclpy
from rclpy.node import Node
from std_srvs.srv import Trigger

class ServiceCaller(Node):
    def __init__(self):
        super().__init__('service_caller')
        self.client = self.create_client(Trigger, 'start_inference')
        while not self.client.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('等待服务上线...')
        self.req = Trigger.Request()

    def send_request(self):
        self.future = self.client.call_async(self.req)
        rclpy.spin_until_future_complete(self, self.future)
        response = self.future.result()
        if response.success:
            self.get_logger().info(f'调用成功: {response.message}')
        else:
            self.get_logger().warn(f'调用失败: {response.message}')

def main():
    rclpy.init()
    node = ServiceCaller()
    node.send_request()
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

Sources: inference_node.hpp

典型操作流程

实际运行机器人时,服务调用需要遵循特定的时序,以避免状态冲突。必须先初始化电机才能启动推理,而复位关节或标定零点则要求在推理停止后进行。

启动并运行推理

启动并运行推理的标准流程如下:

flowchart TD
    A[启动 inference_node] --> B[调用 /init_motors]
    B -->|success: true| C[调用 /reset_joints]
    C -->|success: true| D[调用 /start_inference]
    D -->|success: true| E[机器人进入推理控制模式]
    B -->|success: false| F[检查硬件连接与错误日志]
    C -->|success: false| F

Sources: ros_interface.cpp

安全下电

安全下电或暂停调试时,建议先停止推理再去初始化电机,防止突然掉电导致关节失控。

flowchart TD
    A[调用 /stop_inference] -->|success: true| B[调用 /deinit_motors]
    B -->|success: true| C[电机下电完成]
    A -->|success: false| D[推理已处于停止状态]

Sources: ros_interface.cpp

零点标定

零点标定是一个对时序要求严格的操作。服务层面的完整流程为:初始化电机、复位关节到默认角度、将机器人手动摆放到目标零位、调用 /set_zeros 写入零点、最后去初始化电机。详细的机械操作说明与阻尼模式控制请参考 电机零点标定

flowchart TD
    A[调用 /init_motors] --> B[调用 /reset_joints]
    B --> C[人工摆放机器人至目标零位]
    C --> D[调用 /set_zeros]
    D -->|success: true| E[调用 /deinit_motors]
    D -->|success: false| F[检查推理是否已停止]

Sources: ros_interface.cpp

返回值与异常排查

当服务返回 success: false 时,message 字段会给出明确的拒绝原因。下表汇总了常见错误及其含义,便于快速定位问题。

错误提示 触发服务 原因与修复
Inference is running, cannot reset joints. /reset_joints, /set_zeros 推理循环正在运行,需先调用 /stop_inference
Motors are not initialized... /reset_joints, /set_zeros, /refresh_joints, /read_joints, /deinit_motors 电机尚未初始化,需先调用 /init_motors
Motors are already initialized... /init_motors 电机已处于使能状态,无需重复初始化
Inference is already running! /start_inference 推理已在运行,重复调用无效
Inference is already stopped! /stop_inference 推理已停止,重复调用无效
Robot interface is not initialized... /clear_errors, /read_imu RobotInterface 实例未就绪,检查节点启动日志

Sources: ros_interface.cpp

注意事项与边界条件

所有服务回调均在 inference_node 的主执行器线程中同步处理,因此单个服务的耗时操作(如电机初始化)会短暂阻塞同一节点的其他回调。开发者在设计外部调用逻辑时,应避免高频并发请求,并始终检查返回值的 success 标志。此外,/set_zeros 会直接将当前关节位置写入电机零偏寄存器,调用前务必确认机器人已稳定处于目标姿态,否则会导致后续控制基准错误。

Sources: ros_interface.cpp, inference_node.hpp

延伸阅读与下一步

完成服务接口的学习后,建议结合 启动机器人与推理节点 中的启动脚本实际运行节点,因为所有服务都依赖于 inference_node 的正常启动。节点通过 inference.launch.py 加载配置并注册服务;若希望使用手柄完成相同操作,请参考 手柄控制说明。如需了解底层硬件抽象,可阅读 RobotInterface 硬件抽象层;若希望通过 Python 直接绑定硬件而非走 ROS2 服务,请查看 Python SDK 快速上手