ROS2 Interface 开发No.2 关节命令与全身控制

ROS2 接口开发

更新于:2026年8月17日

1.1 接口概述

关节命令与全身控制接口是机器人运动控制的最底层接口,通过 /hardware/joint_command 话题直接发送关节级控制指令(位置、速度、力矩),并通过 /hardware/joint_state 话题读取关节状态反馈。该接口是 PD 控制器站立、RL 策略部署等高级控制实现的基础。

协议说明中的「关节命令/状态接口」和「全身关节控制接口」使用同一组话题和消息,前者侧重消息字段定义,后者侧重参数和力矩公式,此处合并阐述。

1.2 消息字段

通信接口

话题名称消息类型方向说明
/hardware/joint_commandJointCommand.msg客户端 → 关节控制器发送关节控制消息
/hardware/joint_stateJointState.msg关节控制器 → 客户端读取关节状态反馈

JointCommand 消息包含以下参数:

参数说明
position关节目标位置 [rad],按模型关节顺序排列
velocity关节目标速度,按模型关节顺序排列
feed_forward_torque前馈力矩 [N·m]
torque暂不支持
stiffness刚度 kp [N·m/rad]
damping阻尼 kd [N·m·s/rad]
parallel_parser_type并联关节解析器类型:0 = CLASSIC_PARSER(经典解析器),1 = RL_PARSER(强化学习解析器)

JointState.msg 字段定义(完整定义见 GitHub 消息目录):

PLAIN
std_msgs/Header header
float64[] position
float64[] velocity
float64[] torque
字段类型说明
positionfloat64[]当前关节位置(弧度)
velocityfloat64[]当前关节速度(rad/s)
torquefloat64[]当前关节力矩(N·m)

关节总力矩由以下公式计算:

PLAIN
tau = kp * (q_cmd - q) + kd * (qd_cmd - qd) + feed_forward_torque

其中 position 对应公式中的 q_cmd(目标位置),stiffness 对应 kp,damping 对应 kd;q 和 qd 为当前关节位置和速度,从 /hardware/joint_state 读取。所有数组长度必须与机器人总关节数 num_total_joints 一致。

1.3 控制频率与 QoS

项目要求
推荐控制频率100~500 Hz
QoS 策略Best Effort(以减少延迟)
数组长度所有数组必须等于机器人总关节数
关节索引从 0 开始
轨迹插值步数影响运动平滑度,步数越多越平滑

1.4 前置条件

必须先切换到 joint_bridge(关节透传)模式,关节命令接口才会响应。切换方式见第1章。

运动模式手柄按键
关节透传模式(joint_bridge)[BACK, A]

1.5 示例A:PD 控制器站立

文件名joint_bridge_example.py

本示例从 YAML 配置文件读取目标位置和控制参数,生成平滑的关节轨迹,并以 500 Hz 高频率发送控制命令,实现精确的关节位置控制。

运行命令

Bash
python3 src/interface_example/scripts/joint_bridge_example.py src/interface_example/config/pm01/pd_joint_test.yaml
python3 src/interface_example/scripts/joint_bridge_example.py src/interface_example/config/t800/pd_joint_test.yaml
python3 src/interface_example/scripts/joint_bridge_example.py src/interface_example/config/t800pro/pd_joint_test.yaml

配置文件格式(YAML,示例文件见 GitHub 配置目录):

PM01(24 自由度)

YAML
target_position:
  - [-0.280673, -0.00314991, -0.0736041, 0.413063, -0.141991, -0.00686322]
  - [-0.280673, 0.00314922, 0.0736043, 0.413063, -0.141991, 0.00686394]
  - [0]
  - [0, 0.054, 0, -0.128, 0]
  - [0, -0.054, 0, -0.128, 0]
  - [0]
kp:
  - [200, 200, 380, 450, 400, 200]
  - [200, 200, 380, 450, 400, 200]
  - [200]
  - [250, 250, 250, 250, 250]
  - [250, 250, 250, 250, 250]
  - [100]
kd:
  - [5, 5, 5, 5, 2, 2]
  - [5, 5, 5, 5, 2, 2]
  - [1]
  - [1, 1, 1, 1, 1]
  - [1, 1, 1, 1, 1]
  - [1]

# Total steps
num_steps:
  - [1500, 1500, 1500, 1500, 1500, 1500]
  - [1500,  1500, 1500, 1500, 1500, 1500]
  - [1500]
  - [1500, 1500, 1500, 1500, 1500]
  - [1500, 1500, 1500, 1500, 1500]
  - [1500]

T800 开发版(25 自由度)

YAML
target_position:
  - [-0.280673, -0.00314991, -0.0736041, 0.413063, -0.141991, -0.00686322]
  - [-0.280673, 0.00314922, 0.0736043, 0.413063, -0.141991, 0.00686394]
  - [0]
  - [0, 0.054, 0, -0.128, 0]
  - [0, -0.054, 0, -0.128, 0]
  - [0, 0]
kp:
  - [200, 200, 380, 450, 400, 200]
  - [200, 200, 380, 450, 400, 200]
  - [200]
  - [250, 250, 250, 250, 250]
  - [250, 250, 250, 250, 250]
  - [100, 100]
kd:
  - [5, 5, 5, 5, 2, 2]
  - [5, 5, 5, 5, 2, 2]
  - [1]
  - [1, 1, 1, 1, 1]
  - [1, 1, 1, 1, 1]
  - [1, 1]

# Total steps
num_steps:
  - [1500, 1500, 1500, 1500, 1500, 1500]
  - [1500,  1500, 1500, 1500, 1500, 1500]
  - [1500]
  - [1500, 1500, 1500, 1500, 1500]
  - [1500, 1500, 1500, 1500, 1500]
  - [1500, 1500]

T800 Pro(43 自由度,含灵巧手)

YAML
target_position:
  - [0, 0, 0, 0, 0, 0] # left leg
  - [0, 0, 0, 0, 0, 0] # right leg
  - [0] # waist
  - [0, 0, 0, 0, 1.57, 0, 0] # left arm
  - [-1.2, 0.0, 1.437, -1.23, -1.84487, -1.3, -1.8287] # left hand
  - [0, 0, 0, 0, -1.57, 0, 0] # right arm
  - [1.2, 0.0, 1.437, 1.23, 1.84487, 1.3, 1.8287] # right hand
  - [0, 0] # head

kp:
  - [1080, 480, 880, 1000, 800, 100]
  - [1080, 480, 880, 1000, 800, 100]
  - [200]
  - [120, 120, 120, 120, 120, 30, 30]
  - [20, 20, 20, 20, 20, 20, 20]
  - [120, 120, 120, 120, 120, 30, 30]
  - [20, 20, 20, 20, 20, 20, 20]
  - [100, 100]

kd:
  - [25, 25, 25, 25, 2, 2]
  - [25, 25, 25, 25, 2, 2]
  - [1]
  - [1.8, 1.5, 1.5, 1.8, 1.2, 0.8, 0.8]
  - [0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]
  - [1.8, 1.5, 1.5, 1.8, 1.2, 0.8, 0.8]
  - [0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]
  - [1, 1]

# Total steps
num_steps:
  - [1500, 1500, 1500, 1500, 1500, 1500]
  - [1500,  1500, 1500, 1500, 1500, 1500]
  - [1500]
  - [1500, 1500, 1500, 1500, 1500, 1500, 1500]
  - [1500, 1500, 1500, 1500, 1500, 1500, 1500]
  - [1500, 1500, 1500, 1500, 1500, 1500, 1500]
  - [1500, 1500, 1500, 1500, 1500, 1500, 1500]
  - [1500, 1500]

三个机型的关节分组数量不同(PM01/T800 为 6 组,T800 Pro 为 8 组,含左右灵巧手各 7 个关节),请按所用机型选择对应配置文件。

线性插值算法:对于每个关节,按以下公式生成平滑轨迹:

PLAIN
步长 = (目标位置 - 当前位置) / (步数 - 1)
第 i 步位置 = 当前位置 + 步长 × i

这保证了从起始位置到目标位置的平滑线性过渡。

1.6 示例B:RL 策略部署

启动文件rl_basic_example.launch.py(位于 GitHub 示例目录

本示例展示了如何部署一个强化学习全身控制策略。与 PD 控制器站立不同,RL 策略的关节命令不是来自 YAML 配置文件,而是由策略网络根据多传感器观测实时计算。

通信接口

话题名称消息类型方向
/hardware/joint_commandJointCommand.msg客户端 → 关节控制器
/hardware/joint_stateJointState.msg关节控制器 → 客户端
/hardware/gamepad_keysGamepadKeys.msg传感器 → 客户端
/hardware/imu_infoImuInfo.msg传感器 → 客户端

运行命令

Bash
ros2 launch interface_example rl_basic_example.launch.py

操作流程

  1. 机器人进入 PD 站立模式(pd_stand),站立在平坦空旷的地方,注意安装吊架保护
  2. 对周围 3 米进行人员清场
  3. 进入关节桥接模式(joint_bridge
  4. 命令行运行 launch 文件
  5. 实验结束后回到 PD 站立或 Passive 模式

1.7 示例C:灵巧手虚握拳

文件名:t800pro/loose_fist_example.py

本示例展示了使用T800Pro机器人的三指灵巧手,完成虚握拳的动作,以及从虚握拳动作回到伸直状态。可支持单独的左手、右手控制和双手同时控制。

运行命令:

Bash
# 双手伸直
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --pose extend
# 双手虚握拳
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --pose loose_fist
# 双手先虚握拳,保持,再伸直
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --pose both

# 双手先虚握拳,保持,再伸直,动作执行时间3.5s,保持时间2.5s,频率500hz
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --pose both --exec-time 3.0 --hold-time 2.5 --rate 500.0

# 单独左手伸直
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --hand left --pose extend
# 单独左手虚握拳
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --hand left --pose loose_fist

# 单独右手伸直
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --hand right --pose extend
# 单独右手虚握拳
python3 src/interface_example/scripts/t800pro/loose_fist_example.py --hand right --pose loose_fist

操作流程

  1. 机器人进入 PD 站立模式(pd_stand),站立在平坦空旷的地方,注意安装吊架保护
  2. 对周围 3 米进行人员清场
  3. 进入关节桥接模式(joint_bridge
  4. 命令行执行脚本,建议测试过程中吊起机器人,谨防摔倒损坏零部件

1.8 两种实现路径对比

对比维度PD 控制器站立RL 策略部署
控制目标保持固定目标关节位置部署强化学习策略,实现全身运动
核心算法线性插值 + PD 位置伺服强化学习策略网络
命令来源YAML 配置文件策略网络根据观测实时计算
所需输入仅需关节状态反馈关节状态 + 手柄 + IMU
控制频率500 Hz策略推理帧率决定(≤500 Hz)
安全要求目标位置在安全范围内平坦空旷、吊架保护、3 米清场
适用场景静态姿态保持、桥接测试动态全身运动、RL 策略验证

两者的共同点:都需要进入 joint_bridge 模式,都通过 /hardware/joint_command 发布命令,都需要确保硬件接口节点已启动。

1.9 注意事项

  • 必须进入 joint_bridge 模式后才能发送关节命令,进入前不要运行示例程序
  • 控制频率必须足够高以保证控制稳定性,推荐 100~500 Hz
  • 所有数组长度必须等于机器人总关节数
  • kp(stiffness)和 kd(damping)参数需要根据关节特性调整,过高的刚度可能导致系统震荡
  • 目标位置必须在关节的安全运动范围内
  • 500 Hz 高频控制对系统性能有一定要求
  • 使用 Ctrl+C 可以安全退出,建议等待运动完成
  • RL 策略部署实验结束后,应回到 PD 站立或 Passive 模式

📎 本章涉及的开源仓库源码文件(点击文件名跳转 GitHub):GamepadKeys.msg · ImuInfo.msg

No.2 关节命令与全身控制 | 众擎开源平台