话题清单

章节

节点 / 包

包路径(工作区 src/ 下)

说明

§2

ti5_master_arm

ti5_controller/

主臂:外骨骼 → 关节/扳机/摇杆等话题

§3

ti5_follow_arm

ti5_controller/

从臂:跟随主臂 CAN 驱动

§4

ti5_aoyihand_node

ti5_aoyihand/

傲意灵巧手(单独 launch)

§5

dex1_gripper_node

dex1_gripper_ros2/

宇树 Dex1 夹爪(单独 launch)

§6

lanxin_chassis_controller_node

lanxin_chassis_controller/

蓝芯 VMR 底盘摇杆(单独 launch)

备注

说明:下文路径均相对于工作区根目录(如 ti5-remote_control/)。修改 YAML 后需重启对应 launchti5_controller 内 C++ 节点改参一般无需 colcon build,改 launch/Python 或新增包才需重新编译。


1. 命名约定

  • 主臂分话题前缀:/{master_device_id}/...,默认 MASTER_001(仓库配置示例常用 ti5_master_001)。

  • 从臂分话题前缀:/{slave_device_id}/...,默认 SLAVE_001(仓库配置示例常用 ti5_slave_001)。

  • 傲意灵巧手ti5_aoyihand_node,包 src/ti5_aoyihand/):控制输入(订阅)在主臂命名空间 /{master_device_id}/...末端状态(与 Dex1 相同话题名)发布在 /{device_id}/...master_device_id / device_id 须在 src/ti5_aoyihand/config/ti5_aoyihand_node.yaml(或启动时参数覆盖)与主臂 paired_device_id、从臂 device_id 自行对齐

  • 宇树 Dex1 夹爪dex1_gripper_node,包 src/dex1_gripper_ros2/)订阅主臂 trigger_cmd,状态话题发布在夹爪节点device_id 下(默认与从臂同为 ti5_slave_001),即用 /<SLAVE_ID>/..._gripper_states请单独 launch,与从臂 launch 独立。

  • 主臂、从臂(包 src/ti5_controller/)、灵巧手、Dex1、底盘等节点各自独立 launch,运行时通过话题与参数约定配合;底盘§6src/lanxin_chassis_controller/)。

  • 本文的 <MASTER_ID><SLAVE_ID> 为占位符。


2. 主臂节点(ti5_master_arm

包位置src/ti5_controller/
启动ros2 launch ti5_controller ti5_master.launch.py(launch 文件:src/ti5_controller/launch/ti5_master.launch.py
主要配置src/ti5_controller/config/):

文件

用途

ti5_master_config.yaml

主臂节点 ROS 参数(device_id、串口、按键映射、腿控等)

retargeting_T170C.yaml

外骨骼→机器人关节名与限位(须与从臂 retargeting_config_file 一致)

ti5_arm_solver_170c.yaml

臂/腿 solver 参数(须与从臂 arm_solver_config_file 一致)

2.1 发布话题

  • /<MASTER_ID>/right_arm_joint_cmd (sensor_msgs/msg/JointState)

    • name: 右臂关节名(优先来自 retargeting)

    • position: 右臂各关节目标角(弧度)

    • header.frame_id: master_arm

  • /<MASTER_ID>/left_arm_joint_cmd (sensor_msgs/msg/JointState)

    • 同上,左臂

  • /<MASTER_ID>/head_joint_cmd (sensor_msgs/msg/JointState)

    • name: 头部 R/P/Y 关节名

    • position: [roll, pitch, yaw](弧度)

    • header.frame_id: master_arm

  • /<MASTER_ID>/waist_joint_cmd (sensor_msgs/msg/JointState)

    • name: 腰部关节名(支持单轴或多轴)

    • position: 腰部目标角(弧度)

    • header.frame_id: master_arm

  • /<MASTER_ID>/leg_joint_cmd (sensor_msgs/msg/JointState)(仅 leg_teleop_enabledenable_leg_joint_cmd_pub=true

    • name: 腿部关节名(retargeting 的 leg

    • position: 腿电机目标角(弧度)

    • header.frame_id: master_arm

    • 当前为“遥操态按键腿控”输出:会话开始前先请求一次 leg_states 刷新,锁存当前末端姿态后仅改末端位置

  • /<MASTER_ID>/trigger_cmd (sensor_msgs/msg/JointState)

    • name: ["right_trigger","left_trigger"] [右扳机, 左扳机]

    • position: 范围约 [0,1]

    • header.frame_id: trigger_cmd

  • /<MASTER_ID>/thumb_side_cmd (sensor_msgs/msg/JointState)

    • name: ["right_thumb_side","left_thumb_side"]

    • position: 两侧拇指侧向量,范围约 [0,1]

    • header.frame_id: thumb_side_cmd

  • /<MASTER_ID>/rocker_cmd (sensor_msgs/msg/JointState)

    • name: ["left_joy_x","left_joy_y","right_joy_x","right_joy_y"]

    • position: 四轴摇杆值

    • header.frame_id: rocker_cmd

  • /<MASTER_ID>/control_cmd (sensor_msgs/msg/JointState)

    • name[0]:命令字符串(如 enter_remote_modearm_follow_pause_left);position 多为占位。

    • 主臂按档位/按键自动发布;从臂如何处理见 §3.1 控制命令

  • /<MASTER_ID>/bottom_cmd (sensor_msgs/msg/JointState)

    • 用途:按键记录(供录包/数据分析);驱动从臂,功能映射走 control_cmd

    • 发布时机:某键按住期间,按按键解析频率持续发布;松手即停止。BOTH_3F 下不发布。

    • 命名name[0] = {模式前缀}_{left|right}_{键名}position[0] 固定 0.0header.frame_id: bottom_cmd

    • 模式前缀BOTH_1F1F_(如 1F_left_blue);NONENone_(如 None_right_joystick)。

    • 记录的键(左右手对称,共 20 路;未按住则不发布该条):

      键名

      含义

      black / white / blue / red

      四色面键(白→X、黑→Y、红→A、蓝→B)

      joystick

      摇杆轴心按下)

      ext_start / ext_mode / ext_back

      拓展键(须 enable_extended_buttons: true 且协议有按下)

      ext_rear_up / ext_rear_down

      拓展后侧上/下

    • 不在本话题:扳机 → trigger_cmd;拇指侧向 → thumb_side_cmd;摇杆轴值 → rocker_cmd

2.2 订阅话题

  • /<SLAVE_ID>/leg_states (sensor_msgs/msg/JointState)(仅折腿遥操启用时)

    • 用于主臂折腿 IK 反馈输入

    • 优先按 name 对齐读取,回退按下标读取

    • 兼容 position.size()==4(标准)或 ==3(兼容路径)


3. 从臂节点(ti5_follow_arm

包位置src/ti5_controller/(与主臂同包,独立进程)
启动ros2 launch ti5_controller ti5_follow.launch.py(launch 文件:src/ti5_controller/launch/ti5_follow.launch.py
主要配置src/ti5_controller/config/):

文件

用途

ti5_follow_config.yaml

从臂 ROS 参数(device_idpaired_device_id、腰/头/腿使能、CAN 等)

retargeting_T170C.yaml

与主臂同一份(retargeting_config_file

ti5_arm_solver_170c.yaml

与主臂同一份(arm_solver_config_file

3.1 订阅话题

下述话题是否创建受 ti5_follow_config.yamlenable_*/include*OnCan() 影响。

  • 主从遥操输入(来自主臂):

    • /<MASTER_ID>/right_arm_joint_cmd (sensor_msgs/msg/JointState)

    • /<MASTER_ID>/left_arm_joint_cmd (sensor_msgs/msg/JointState)

    • (双臂话题从臂侧 QoS 为 KEEP_LAST depth=1,减轻暂停恢复后 DDS 堆积旧帧;主臂单侧恢复后会对该臂 pulse 瞬时多发一帧 并唤醒发布节拍,control_cmd 本身不再要求带 7 轴。)

    • /<MASTER_ID>/head_joint_cmd (sensor_msgs/msg/JointState)

    • /<MASTER_ID>/waist_joint_cmd (sensor_msgs/msg/JointState)

    • /<MASTER_ID>/leg_joint_cmd (sensor_msgs/msg/JointState)

  • 控制命令:

    • /<MASTER_ID>/control_cmd (sensor_msgs/msg/JointState)

    • 怎么读:看 name[0] 里的命令名;若带 :,冒号前是命令、后面是参数。position 多数情况只是占位,以命令名为准

    • 进出遥操模式(主臂按档位自动发,从臂据此切换工作模式):

      命令

      主臂何时发布

      从臂收到后

      enter_chassis_control

      一切换到 BOTH_1F(两手 1F)

      底盘节点启用摇杆;从臂不处理此命令

      enter_remote_mode

      BOTH_1F 保持满 1 秒且尚未在遥操态

      进入遥操跟随REMOTE_OPERATION):清跟随缓存、腰/头/臂开始跟主臂;首帧关节会做平滑衔接

      enter_default_mode

      ① 切到 BOTH_3F(两手 3F)立即发;② 在遥操态切到 NONE 且持续 ≥0.5s(须 none_state_exit_remote: true

      退出遥操回待机:清跟随缓存、恢复默认速度限制;若配置了退出回默认位姿则做规划

      典型流程:两手 1F 并保持 1s → enter_chassis_control(进 1F 即发)+ enter_remote_mode(满 1s 发)→ 从臂跟随;两手 3F → enter_default_mode → 从臂待机、主臂停发关节。

    • 从臂直接忽略(留给录包/LeRobot 等其它节点):

      • record_bag_start / record_bag_stop

      • toggle_recorddropquitmark_failure

    • 单侧臂暂停 / 恢复(默认绑在红键 A,BOTH_1F 且已在遥操态;按住 ≥200ms 后松开触发):

      命令

      主臂何时发布

      从臂做什么

      arm_follow_pause_left / _right

      该侧第一次按红键松开

      该侧停止向电机发跟随;仍收 *_arm_joint_cmd 并更新缓存

      reset_first_point_left / _right

      该侧再次按红键松开(恢复)

      解除暂停;对该侧再做一次首帧平滑衔接(从当前电机位置插到主臂目标),然后恢复跟随

      恢复顺序:主臂先解除该侧轨迹冻结并刷新关节话题 → 等待约 50ms → 发 reset_first_point_*position 一般为占位,目标角来自仍在发布的 *_arm_joint_cmd)。

    • 腿控与腰控(主臂腿 IK 会话):

      命令

      含义

      refresh_leg_states

      腿控开始前:请从臂立刻读腿位置并发布 leg_states

      leg_hold_disable

      开始腿控:解除腿部 hold,允许下发 leg_joint_cmd

      leg_hold_enable

      腿控结束:非共享腿轴进入 hold

      set_waist_teleop_paused

      1 暂停腰遥操 CAN;0 恢复(腿控期间避免腰/腿抢轴)

      set_leg_hold_disabled

      旧命令,仍兼容;请优先用 leg_hold_enable / leg_hold_disable

    • 其它adjust_speed_slow/fast(及 _left/_right 分侧版)、aoyihand_toggle_*_mode 等,见 src/ti5_controller/config/ti5_master_config.yaml 按键映射注释。

3.2 发布话题

  • /<SLAVE_ID>/right_arm_states (sensor_msgs/msg/JointState)

    • name: 右臂关节名

    • position: 右臂电机角(弧度)

    • header.frame_id: <SLAVE_ID>

  • /<SLAVE_ID>/left_arm_states (sensor_msgs/msg/JointState)

    • 同上,左臂

  • /<SLAVE_ID>/head_states (sensor_msgs/msg/JointState)

    • name: 头部 R/P/Y

    • position: [roll,pitch,yaw](弧度)

    • header.frame_id: <SLAVE_ID>

  • /<SLAVE_ID>/waist_states (sensor_msgs/msg/JointState)

    • name: 腰部关节名(长度可为 1 或更多)

    • position: 腰部电机角(弧度)

    • header.frame_id: <SLAVE_ID>

  • /<SLAVE_ID>/leg_states (sensor_msgs/msg/JointState)

    • name: 腿关节名(retargeting leg 顺序)

    • position: 腿电机角(弧度;与 CAN/0x44 约定一致)

    • velocity/effort: 当前填 0 占位

    • header.frame_id: <SLAVE_ID>


4. 灵巧手节点(ti5_aoyihand_node,傲意 ROHand)

包位置src/ti5_aoyihand/
启动ros2 launch ti5_aoyihand ti5_aoyihand.launch.py(launch 文件:src/ti5_aoyihand/launch/ti5_aoyihand.launch.py
主要配置src/ti5_aoyihand/config/ti5_aoyihand_node.yaml(串口、device_idmaster_device_id、控制模式等)
源码src/ti5_aoyihand/src/ti5_aoyihand_node.cpp

备注

说明:与主臂同一网段侧运行。订阅挂在 master_device_id(主臂)。夹爪形态状态挂在 device_id(与从臂一致),仅由本节点在串口上完成「控制帧 → 延时 → 查询帧」后发布;ti5_follow_arm 参与 Aoyi 指令下发或状态读取。

4.1 订阅话题

  • /<MASTER_ID>/trigger_cmd (sensor_msgs/msg/JointState)

    • 与主臂发布约定一致:nameright_trigger / left_trigger,或无名时 position[0]=右、position[1]=左,值约 [0,1]

    • 映射为各指弯曲标量(实现内缩放至 0~65000 下发串口);five_finger / three_finger / two_finger 模式下依次参与映射的指序号递减(拇指侧向由 thumb_side_cmd 单独驱动为第 6 路)

  • /<MASTER_ID>/thumb_side_cmd (sensor_msgs/msg/JointState)

    • nameright_thumb_side / left_thumb_side,或无名时 position[0]=右、position[1]=左

    • 映射到第 6 路(拇指侧向轴)

  • /<MASTER_ID>/control_cmd (sensor_msgs/msg/JointState)

    • 使用 name[0] 字符串;当收到 aoyihand_toggle_left_mode / aoyihand_toggle_right_mode 时,在防抖间隔后分别循环切换左/右手控制模式:five_fingerthree_fingertwo_finger → …

4.2 发布话题(与 Dex1 对齐,由本节点闭环产生)

每个控制周期内顺序为:对单侧下发 Set_Finger_PosAll → 等待 query_delay_ms(默认 3ms)→ 查询指位/力 → 按 state_publish_hz 分频发布。

  • /<SLAVE_ID>/right_gripper_states (sensor_msgs/msg/JointState)

  • /<SLAVE_ID>/left_gripper_states (sensor_msgs/msg/JointState)

<SLAVE_ID> = 参数 device_idsrc/ti5_aoyihand/config/ti5_aoyihand_node.yaml)。话题名与 §5 Dex1 相同,字段含义不同;Dex1 字段说明见 §5.2

4.3 可选:模式话题(主臂侧)

  • /<MASTER_ID>/aoyihand_mode (std_msgs/msg/String)(publish_mode_topic=true 时)

    • 启动及每次切换模式时发布

    • data 格式:left:<mode>right:<mode><mode>five_finger | three_finger | two_finger


5. 夹爪节点(dex1_gripper_node,宇树 Dex1-1)

包位置src/dex1_gripper_ros2/
启动ros2 launch dex1_gripper_ros2 dex1_gripper.launch.py(launch 文件:src/dex1_gripper_ros2/launch/dex1_gripper.launch.py
主要配置src/dex1_gripper_ros2/config/dex1_gripper.yamldevice_idmaster_device_id、开合角标定、力矩保护等)
源码src/dex1_gripper_ros2/src/dex1_gripper_node.cpp
标定/探测脚本(非 ROS 包内):串口can口权限配置/install_scripts/(如 calibrate_dex1_gripper.shdetect_dex1_gripper.sh

5.1 订阅话题

  • /<MASTER_ID>/trigger_cmd (sensor_msgs/msg/JointState)(subscribe_master_trigger=true 时)

    • 读取优先级:

      1. name 匹配 right_trigger/left_trigger

      2. 回退 position[0]=右、position[1]=左

    • 将触发量按 trigger_open/trigger_close 线性映射到夹爪目标角 q_open_rad~q_close_rad

5.2 发布话题:*_gripper_states

话题

话题

消息类型

出现条件

/<SLAVE_ID>/right_gripper_states

sensor_msgs/msg/JointState

探测到 预设 id=0 的 M4010 电机

/<SLAVE_ID>/left_gripper_states

sensor_msgs/msg/JointState

探测到 预设 id=1 的 M4010 电机

<SLAVE_ID> = 参数 device_id(默认 ti5_slave_001,见 dex1_gripper.yaml)。左右侧由节点预设的固定电机 id 区分:id=0 → 右id=1 → 左

备注

说明:与 §4 灵巧手话题名相同;同机勿并行 launch dex1_gripper_nodeti5_aoyihand_node

消息形态

  • 类型:sensor_msgs/msg/JointState(ROS2 标准关节状态)。

  • 每侧只描述 1 个夹爪关节:namepositionvelocityeffort 四个数组长度均为 1(无 name 与数组长度不一致的情况)。

  • 未填充的 JointState 可选字段(如空 header 以外的扩展)本节点不使用。

备注

字段说明:发布代码见 dex1_gripper_node.cppstate.q/dq/tau 为 Unitree SDK 电机侧反馈,再经减速比换算到 关节侧 写入话题。

字段

ROS 类型

数组下标

单位

取值 / 换算

含义

header.stamp

builtin_interfaces/Time

控制环内本电机 sendRecv 完成时刻

状态采样时间

header.frame_id

string

等于 device_id 字符串

非 TF 帧名,仅作设备标识

name[0]

string

0

right_gripperleft_gripper

与预设 id 对应(0=右,1=左)

position[0]

float64

0

rad

position[0] = state.q / gear_ratio

关节侧当前角。M4010 gear_ratio = 25。本机标定:q_close_rad=0(全闭)、q_open_rad=5.0(全开),数值越大夹爪越开

velocity[0]

float64

0

rad/s

velocity[0] = state.dq / gear_ratio

关节侧角速度(电机 dq 经减速比)

effort[0]

float64

0

与力矩保护同量纲

effort[0] = -state.tau × gear_ratio

电机反馈力矩链(tau 取反后乘减速比)。夹持越紧通常 绝对值越大;本机 effort_limit: 3.0,注释量级约 0~5

电机侧 ↔ 关节侧gear_ratio = 25

电机侧(SDK state.*

话题(关节侧)

位置

state.q(rad)

position[0] = state.q / 25

速度

state.dq(rad/s)

velocity[0] = state.dq / 25

力矩

state.tau

effort[0] = -state.tau × 25

控制下发时节点做相反换算:cmd.q = q_cmd × gear_ratio(目标角 q_cmdposition[0] 同量纲,均在关节侧 rad)。

与配置参数的对应

  • position[0] 应与 q_open_rad / q_close_rad 同标度:录包时全闭接近 0,全开接近 5(本机标定值,改 YAML 后以新标定为准)。

  • 主臂 trigger_cmdtrigger_open / trigger_close 映射的目标角也在该 rad 标度上;不是扳机的 [0,1] 无量纲值。

  • effort_limit_enable=true 时,节点用 r = |effort[0]| / effort_limit 做单调钳位、kp 软化、超限回退等(详见 dex1_gripper.yaml 注释);订阅方若做力控显示,应直接使用 effort[0],勿再乘减速比。

发布频率

  • 控制周期:control_period_us(默认 2000 µs → 500 Hz 控制环)。

  • 状态发布:state_publish_hz(默认 100 Hz),在控制环内分频;header.stamp该次发布对应的控制周期时刻,非独立慢速采样。

  • 仅扫描登记成功的电机会创建 publisher;未接线一侧无对应话题。


6. 底盘节点(lanxin_chassis_controller_node,蓝芯 VMR)

包位置src/lanxin_chassis_controller/
启动ros2 launch lanxin_chassis_controller lanxin_chassis_launch.py(launch 文件:src/lanxin_chassis_controller/launch/lanxin_chassis_launch.py
主要配置src/lanxin_chassis_controller/config/lanxin_chassis_config.yaml(VMR IP、速度缩放、话题前缀、master_device_id 等)
源码src/lanxin_chassis_controller/src/lanxin_chassis_controller_node.cpp

备注

说明:与主臂同网段即可;不随 ti5_follow.launch.py 启动。默认通过 完整话题名master_topic_prefix 订阅主臂侧 control_cmdrocker_cmd(配置里常为 /ti5_master_001/...)。

6.1 订阅话题

  • /<MASTER_ID>/control_cmd (sensor_msgs/msg/JointState)

    • name[0],并按 : 截断命令基名

    • enable_cmd(默认 enter_chassis_control)使能底盘摇杆

    • disable_cmds(默认 enter_default_mode)停用底盘摇杆控制

  • /<MASTER_ID>/rocker_cmd (sensor_msgs/msg/JointState)

    • 支持两种解析:

      1. name 匹配 left_joy_x/y, right_joy_x/y

      2. 回退按下标 [0..3]

    • 映射关系:

      • 左摇杆左右 -> 角速度 wz

      • 右摇杆前后 -> 线速度 vx

      • 右摇杆左右 -> 线速度 vy

6.2 发布话题

  • 无 ROS 话题发布。

  • 控制输出通过 VMR SDK 直接下发底盘速度(非 ROS 话题)。