Sim-to-real 部署

部署桥在真机 Wuji Hand 上运行导出的 ONNX 策略。视觉模块通过 MVS SDK 直接读取相机,追踪一个锚定在手腕 AprilTag 世界坐标系上的 ArUco 标定 cube,把位姿通过 ZMQ 发布出去。play_real 进程订阅位姿、跑 ONNX 推理,把动作命令闭环下发到手部驱动。

本页假设装置已搭建并标定。若未完成,先看硬件搭建

部署无需训练。从 Releases 下载预训练的 policy.onnxpolicy_config.json,把 policy.onnx 路径作为 --ckpt 传入。演示就是这个 release 策略跑出来的。

管线

+-----------------+       +------------------+       +-------------------+
| Camera + tags   | -MVS->| cube observer    | -ZMQ->| play_real         |
| (aruco+apriltag)|       | (cube_world_     |       | (policy + control |
|                 |       |  observer.py)    |       |  + viewer)        |
+-----------------+       +------------------+       +-------------------+
                                                              |
                                                              v
                                                       +--------------+
                                                       | WujiHandDriver
                                                       | (real hardware)
                                                       +--------------+

RealHandEnv 继承 mjlab 的 ManagerBasedRlEnv,因此与训练相同的 observation 和 action manager 原封不动地生效,没有并行流水线。在 env 的 step() 内,动作下发到手部驱动,观测来自关节状态(经驱动)与 cube 位姿(经 observer 的 ZMQ)的组合。

ONNX 策略通过一个 loader 加载,它读取 sidecar JSON 中导出时捕获的控制模式参数(action_scaleema_alphawarmup_time_scontrol_modehistory_lenctrl_dt)。这让部署推理与产出该 ONNX 的仿真策略完全一致。

运行闭环

完成硬件设置后,三个命令各自在独立终端按顺序运行。home 是一次性复位。visionplay-real 都会持续运行,不能共用一个终端。

# 终端 1 —— 一次性复位,随后退出
pixi run -e deploy home
# 终端 2 —— cube observer,持续运行(OpenCV 预览)
pixi run -e deploy vision
# 终端 3 —— 闭环控制 + mirror viewer,持续运行
pixi run -e deploy play-real --ckpt <path-to.onnx>

位姿估计调优

硬件固定后,observer.yaml 提供四个旋钮,在噪声与延迟之间权衡。

参数默认效果
rotation_filter.process_noise0.5越高越灵敏,噪声越大
rotation_filter.measurement_noise0.1越低越信任 PnP
position_filter.alpha0.8[0, 1] 范围的低通,1.0 表示不滤波
pnp.reproj_threshold6.0 px超过该阈值的拟合被丢弃,cube 进入 lost

observer.yaml 内嵌两套预设:

  • Agile(快速响应,噪声更大):process_noise: 0.5measurement_noise: 0.1alpha: 0.8
  • Smooth(稳定,响应更慢):process_noise: 0.01measurement_noise: 2.0alpha: 0.2

随包默认是 agile 预设,也是训练策略部署时使用的配置。

按现象调优:

  • Cube 静止时抖动——切换到 smooth 预设。
  • 快速翻转时位姿滞后——切换到 agile 预设。
  • Cube 反复跌入 lost——把 pnp.reproj_threshold 提高到约 8.0 px,并重新检查相机内参标定。如果轴向看起来错了,修 cube_tags.json 的 face rotations 或重贴对应面的 tag。

端到端冒烟测试

按顺序走完以下五个检查点。若任何一步失败,先跳回对应设置章节再继续。

步骤 1 — 让手回零

pixi run -e deploy home

预期:3 秒平滑斜坡,20 个关节都落入 home 位置 ±2° 内,打印 "home reached"。手指抖动或硬卡停时,先停止控制并断开执行器电源、确认关节已去力,再拔插 USB 线重试。

步骤 2 — 启动 cube observer

pixi run -e deploy vision

预期:OpenCV 预览出现,手腕标签保持在视野内时黄色 "World Sampling: N/100" 进度条填满,累积 100 个样本平均后标签翻为绿色 "WORLD FIXED",cube 静止时轴向叠加图稳定。

步骤 3 — 验证 ZMQ 位姿流

另开一个终端(保持 vision 持续运行),确认 cube 位姿正在端口 5555 上发布:

pixi run -e deploy python - <<'EOF'
import json, zmq
sock = zmq.Context().socket(zmq.SUB)
sock.connect("tcp://localhost:5555")
sock.subscribe(b"")
sock.setsockopt(zmq.RCVTIMEO, 5000)  # 5 秒收不到就报错,避免无限阻塞
try:
    for _ in range(3):
        msg = json.loads(sock.recv_string())
        p = msg["cube1"]["position"]
        print(f"frame={msg['frame']:5d}  pos=({p['x']:+.3f},{p['y']:+.3f},{p['z']:+.3f})")
except zmq.Again:
    print("5 秒内没收到位姿 —— vision 是否在运行并向端口 5555 发布?")
EOF

你应当看到 3 个新的 frame 编号和稳定的位置数值。

步骤 4 — cube 位姿可视化检查

保持 vision 仍在运行:

pixi run -e deploy python deploy/reorient/tools/calib_check.py

这会打开一个 MuJoCo passive viewer 渲染数字孪生,手部 mirror 实时 encoder 读数,cube 显示在 observer 估计的位姿上。挪动物理 cube,观察渲染 cube 是否跟随。相比 ZMQ 检查,这一步还能查出:

  • 轴向错配——让物理 cube 绕某个面轴旋转,渲染 cube 应绕同一个轴。镜像或 90° 偏差意味着 cube_tags.json 的 face rotations 不对,或某个 tag 贴反了。
  • 位置偏差——把 cube 放在手掌中心,渲染 cube 应落在 palm geom 上。> 2 cm 偏差通常意味着手部安装或相机内参有问题。

步骤 5 — 运行闭环策略

pixi run -e deploy play-real --ckpt <path-to.onnx>

预期:ONNX 策略加载并打印 sidecar JSON,手部回零,一个 passive MuJoCo mirror viewer 打开(显示真实关节、观测到的 cube,以及上方的半透明目标 cube),手部把 cube 朝目标姿态调整,各次试验结果实时打印。

排错

现象可能原因解决方法
相机打不开MVS SDK 未安装或 MVS_PYTHON_PATH 未设置重做「Hikvision MVS SDK」一节,再跑一遍导入冒烟测试
手腕 AprilTag 一直检测不到光照、标签 family、ID 或尺寸错确认 AprilTag36h11、ID 0、48 mm,加强光照
World Sampling 进度条一直不满手腕标签太小或模糊调位置使标签 ≥ 80 px 宽,重新对焦
Cube observer 频繁掉 cube重投影误差门触发重做相机内参标定,用步骤 4 校验 cube_tags.json 面映射
策略第一步就发散tag 朝向错配cube_tags.json 的 face rotations 或重贴对应 tag
Rollout 时手抖动ctrl_dt 策略侧与硬件侧不匹配检查 ONNX sidecar 的 ctrl_dt,降低硬件低通截止频率

想深入了解策略背后的任务设计,见架构