7.7 KiB
RM75 CANFD UDP 主动反馈设计
真机验证修正:右臂高跟随首轮测试触发掉使能。离线复现发现静止目标存在
23.582°空空间漂移,第一周期约3315°/s²。当前实现已移除 manipulability 自运动、增加软件关节加速度限幅和故障 Grip 锁存,并将三份 YAML 恢复为follow: false安全基线;高跟随须在基线验证后单独测试。
目标
按睿尔曼 MovejCANFD 示例,将真机关节反馈从同一 TCP 控制连接上的
rm_get_joint_degree() 周期轮询,替换为控制器 UDP 主动状态推送。
控制命令继续通过现有单个 RoboticArm(RM_TRIPLE_MODE_E) 句柄发送,不新增
RealMan 连接,不修改 Placo QP、工作空间/圆柱限位、速度限制、指令超时或安全
停止条件。
根因与证据
低跟随模式下,125 Hz CANFD 发送与绝对周期 TCP 反馈轮询能够同时工作:
feedback_interval mean=10.041–10.389 ms;feedback_age mean=5.730–6.138 ms;- 控制周期最大值不超过
8.979 ms。
启用高跟随后,即使 canfd_trajectory_mode=2,控制发送仍正常:
period max=9.275 ms;send max=0.235 ms。
但同步反馈退化为:
feedback_read mean=11.278 ms、max=80.320 ms;feedback_age max=117.502 ms。
反馈年龄逼近现有 command_timeout_sec=0.12 s,触发“关节反馈缺失或过期”
安全停止,造成 Grip 按住期间控制反复退出和重新锁定。增大超时只会允许 QP
继续使用更旧的关节状态,不解决 TCP 反馈阻塞。
睿尔曼 MovejCANFD 示例使用三线程模式、rm_set_realtime_push() 和
rm_realtime_arm_state_call_back(),通过 UDP 回调获取关节状态,而不是在
CANFD 透传期间同步轮询关节角。
数据流
PICO -> ROS 125 Hz 控制回调 -> Placo QP -> TCP rm_movej_canfd
RM75 控制器 -> UDP 5 ms 主动推送 -> SDK 第三线程回调
-> JointStateSnapshot 缓存 -> ROS 125 Hz 控制回调
TCP 仍承担 CANFD、慢停、安全配置和末端工具命令。UDP 只承担状态反馈,两条 传输路径共用同一个机械臂句柄。
SDK 连接与反馈生命周期
RealManAdapter.connect() 保持三线程模式和单次 rm_create_robot_arm():
- 创建并检查机械臂句柄。
- 下发已有安全参数和可选初始位姿。
- 创建并保存
rm_realtime_arm_state_callback_ptr,避免 Python 回调被垃圾 回收。 - 使用
rm_realtime_push_config_t配置 5 ms UDP 主动上报。 - 注册
rm_realtime_arm_state_call_back()。 - 等待第一帧有效 UDP 反馈,最长 2 秒。
若配置接口返回非零,或 2 秒内没有有效反馈,连接初始化失败并删除已创建的 机械臂句柄;不静默回退到 TCP 轮询。
连接成功后不再创建反馈线程,也不再调用 rm_get_joint_degree()。
close() 先停止接受回调更新,再执行现有慢停和句柄删除。控制器的 UDP 配置
由下一次启动重新覆盖,不额外增加关闭阶段配置命令。
UDP 回调与缓存
回调只执行有界、非阻塞工作:
- 检查回调对象、
errCode和来源机械臂 IP。 - 读取 7 个
joint_position,检查数量、数值类型及 NaN/Inf。 - 将厂商反馈的角度转换为弧度。
- 使用
time.monotonic()记录接收时刻,并计算与上一帧的更新间隔。 - 在现有
_joint_state_lock下替换JointStateSnapshot。 - 第一帧有效数据唤醒连接初始化等待。
无效 UDP 帧不覆盖上一帧缓存。若后续持续丢包,现有 120 ms 新鲜度检查自然 触发安全停止。
UDP 回调不执行 QP、ROS 发布、停止命令或其他 SDK 调用,避免阻塞 SDK 接收 线程。
参数与三份 YAML
新增真机参数:
realtime_push_host_ip:机械臂可直接访问的上位机地址;realtime_push_port:单臂 UDP 接收端口;realtime_push_cycle_ms:主动上报周期,默认并配置为5。
本次现场配置:
| 配置 | 节点 | host | port |
|---|---|---|---|
right_arm_rm75.yaml |
右臂 | 192.168.192.148 |
8090 |
left_arm_rm75.yaml |
左臂 | 192.168.192.148 |
8089 |
dual_arm_rm75.yaml |
左臂 | 192.168.192.148 |
8089 |
dual_arm_rm75.yaml |
右臂 | 192.168.192.148 |
8090 |
左右臂端口必须不同。更换上位机或网络后,只需同步修改 YAML 中的
realtime_push_host_ip。
Mock 模式不导入厂商 SDK,也不要求 UDP 参数有效。
YAML 与 launch 参数所有权
此前 arm_debug.launch.py 会用 launch 默认值覆盖 YAML 中的机械臂参数,
导致 YAML 无法单独控制 follow 等行为。
用户选择由 YAML 作为机械臂行为和硬件参数的唯一默认来源。
以下参数只由 left_arm_rm75.yaml、right_arm_rm75.yaml 和
dual_arm_rm75.yaml 管理,launch 不再声明或覆盖:
robot_ip、robot_port;avoid_singularity;control_rate_hz;follow、canfd_trajectory_mode、canfd_radio;configure_safety_limits;move_to_initial_pose_on_connect;enable_tool_control、enable_trigger_gripper_control;trigger_close_threshold;configure_peripheral_on_connect;- 本设计新增的 UDP 主动反馈参数。
三份 YAML 补齐工具控制参数;删除其中不再生效的 use_mock,避免出现两个
配置来源。
arm_debug.launch.py 只保留:
arm=left|right|both,选择启动拓扑;use_mock=true|false,作为显式安全运行模式,默认仍为true;- PICO 输入节点的
udp_host、udp_port、udp_timer_hz; - launch 根据安装路径和左右臂生成的
robot_urdf_path、peripheral_config_file、peripheral_arm和tool_command_topic。
launcher_ui.py 和 README 中的启动命令同步删除机械臂 IP、初始化移动等已
移交 YAML 的 launch 参数,只保留 arm、use_mock 和 PICO 输入覆盖。
控制模式保持分阶段范围:
- 三份 YAML 均使用
follow: false、canfd_trajectory_mode: 2完成安全基线; - 基线验证通过前不启用高跟随或模式 0,不提高
max_linear_speed。
Timing 日志
保留:
period;total;qp;send;feedback_age;feedback_interval。
feedback_read 表示同步 SDK 查询耗时;UDP 架构不存在该查询,因此该字段
不再产生样本,现有条件日志逻辑会自动省略它,不新增同义统计项。
测试
使用 FakeArm 和伪造 SDK 模块覆盖:
- 连接时使用正确 host、port、5 ms 周期配置 UDP 并注册回调;
- 第一帧有效回调转换 7 个关节角为弧度并解除启动等待;
- 连续回调正确记录
feedback_interval; - 错误码、来源 IP、长度或 NaN/Inf 无效帧不覆盖缓存;
- UDP 配置失败或首帧超时会清理句柄并抛出明确异常;
- 真机适配器不再启动轮询线程或调用
rm_get_joint_degree(); - Mock 模式无需厂商 SDK。
- launch 不再覆盖 YAML 的机械臂行为和硬件参数;
use_mock仍由 launch 默认设为true;launcher_ui.py不再传递已经删除的 launch 参数。
随后运行:
cd /home/robot/WS_xr
source /opt/ros/humble/setup.bash
python3 -m pytest -q src/xr_rm_teleop/test
python3 -m pytest -q src/xr_rm_teleop/test/test_orientation_control.py
colcon build --symlink-install --executor sequential
Codex 不连接真机。用户在右臂小范围测试中确认:
- 启动日志显示收到 UDP 首帧;
- 按住 Grip 不再出现反馈过期或 SDK
-2; - 连续四个 timing 窗口
period max < 10 ms、total max < 8 ms; feedback_interval mean接近 5 ms;feedback_age mean < 5 ms,且最大值不触发 120 ms 安全停止。