ROS2 Interface 开发No.1 运动状态机

ROS2 接口开发

更新于:2026年8月17日

1.1 运动状态切换通过两个 ROS2 话题完成:

话题名称消息类型方向说明
/motion/motion_stateMotionState.msg运动管理服务 → 客户端读取当前运动状态
/motion/set_motion_stateMotionStateRequest.msg客户端 → 运动管理服务发送运动状态切换请求

MotionState 消息中包含当前运动状态名称和 available_transition_motions 列表,后者列出了当前可直接切换到的目标状态。开发者发送 MotionStateRequest 消息来请求状态切换。

1.2 状态定义与列表

运动状态机是机器人所有控制接口的前置条件。大多数运动控制接口只有在机器人处于正确运动状态时才会响应,因此开发者首先需要理解状态机的定义和切换方法。

下表列出了所有可用运动状态及其含义,并标注了各机型的支持情况:

状态名称说明PM01T800
idle空闲,全身关节下使能
passive阻力模式
pd_standPD 控制器站立
rl_amp机械步态
rl_basic自然行走步态
rl_terrain地形步态
lower_body_balance下肢平衡,上肢低阻尼步态(响应上肢关节控制接口)
joint_bridge关节透传模式(响应全身关节控制接口)
pd_sitground机器人坐着起身
rl_recover_prone从地上趴着起来
rl_floor_sitting站立坐到地上
walk_server行走控制服务端
rl_mimic_supine_to_stance仰卧 → 站立
rl_mimic_prone_to_stance俯卧 → 站立
rl_mimic_stance_to_supine站立 → 仰卧
rl_mimic_sitdown_to_stance坐姿 → 站立
rl_mimic_stance_to_sitdown站立 → 坐下

1.3 切换接口

通信接口:运动状态切换通过两个 ROS2 话题完成。

  • 状态反馈话题:/motion/motion_state,消息类型:interface_protocol/msg/MotionState
  • 切换请求话题:/motion/set_motion_state,消息类型:interface_protocol/msg/MotionStateRequest

后续小节再详细说明消息字段含义。

MotionState.msg 字段定义(来自 GitHub):

PLAIN
string current_motion_task
string[] available_transition_motions
字段类型说明
current_motion_taskstring当前运动状态名称
available_transition_motionsstring[]当前可直接切换到的目标状态列表

MotionStateRequest.msg 字段定义:

PLAIN
string target_motion_name
字段类型说明
target_motion_namestring目标运动状态名称

1.4 状态转换规则

  • 切换前必须确保目标状态在 available_transition_motions 列表中,否则切换请求会被忽略
  • 只需要发送一条 MotionStateRequest 消息,机器人就会开始切换
  • 状态切换有 3 秒超时限制,超时后切换失败
  • 某些状态之间无法直接切换,需要经过中间状态(例如从 idle 到 rl_terrain 可能需要先经过 pd_stand)。状态转换的具体限制可参看产品手册。可用的转换目标不是固定的,而是由机器人运行时通过 available_transition_motions 字段动态返回——开发者应在代码中先读取该字段,确认目标状态在列表中后再发送切换请求
  • QoS 配置不匹配会导致消息接收失败,务必确认订阅和发布的 QoS 一致

1.5 示例:完整切换流程

文件名switch_to_terrain_walking_gait_example.py

本示例展示了从默认站立状态切换到目标运动状态(如下肢平衡模式)的完整流程,包括状态监听、白名单检查、切换请求和结果验证。示例以 lower_body_balance 为例,该状态在 PM01 与 T800 系列上均受支持。

运行命令

代码示例位于 engineai_ros2_workspace/src/interface_example/scripts 目录下,切换到对应目录后再执行上述命令。

Bash
# 以下肢平衡模式为例(PM01/T800 均支持)
python3 switch_to_terrain_walking_gait_example.py --target-motion lower_body_balance

# 或使用简写
python3 switch_to_terrain_walking_gait_example.py -m lower_body_balance

程序运行流程

  1. 初始化节点并订阅 /motion/motion_state
  2. 等待接收当前运动状态信息
  3. 检查目标状态是否在 available_transition_motions 列表中
  4. 发布状态切换请求到 /motion/set_motion_state
  5. 监控切换进度,等待切换完成或超时
  6. 完成后自动退出

最小示例(仅供逻辑参考)(基于 GitHub 脚本 switch_to_terrain_walking_gait_example.py 精简;同目录下另有 switch_to_target_motion_example.py,二者仅目标步态不同、逻辑一致。完整超时/退出/错误处理逻辑请见 GitHub 完整版本),核心逻辑是订阅状态 → 检查白名单 → 发布切换请求:

Python
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy
from interface_protocol.msg import MotionState, MotionStateRequest

class MotionStateSwitcher(Node):
    def __init__(self, target_motion: str):
        super().__init__("motion_state_switcher")
        # 发布者:QoS 必须用 RELIABLE
        self._pub = self.create_publisher(
            MotionStateRequest, "/motion/set_motion_state",
            QoSProfile(depth=1, reliability=ReliabilityPolicy.RELIABLE,
                       durability=DurabilityPolicy.VOLATILE))
        # 订阅者:QoS 用 BEST_EFFORT
        self._sub = self.create_subscription(
            MotionState, "/motion/motion_state",
            self._on_state,
            QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT,
                       durability=DurabilityPolicy.VOLATILE))
        self._target = target_motion
        self._available = []
        self.create_timer(0.1, self._tick)

    def _on_state(self, msg: MotionState):
        self._available = msg.available_transition_motions

    def _tick(self):
        if self._target in self._available:
            req = MotionStateRequest()
            req.target_motion_name = self._target
            self._pub.publish(req)
            self.get_logger().info(f"Switching to {self._target}")

rclpy.init()
node = MotionStateSwitcher("lower_body_balance")
rclpy.spin(node)

注意:完整脚本还包含超时处理、切换成功检测和完整退出逻辑,更健壮,建议实际使用时参考 GitHub 完整版本。

1.6 注意事项

  • 确保运动控制器节点已启动,否则状态消息无法接收
  • 状态切换需要一定时间,请耐心等待,不要重复发送请求
  • 如果超时,请检查目标状态名称是否正确(注意大小写)
  • 使用 Ctrl+C 可以随时中断程序
  • 切换成功后,对应的运动控制接口才会生效(如 joint_bridge 模式下关节命令接口才可用)

📎 本章涉及的开源仓库源码文件(点击文件名跳转 GitHub):MotionState.msg · MotionStateRequest.msg · switch_to_target_motion_example.py · switch_to_terrain_walking_gait_example.py