Skip to main content

概述

本篇实践介绍如何通过引导姿势完成手部模型标定,生成适合操作者手型的 URDF。应用场景包括适配不同操作者的手型和建立个人手部追踪模型。 对应的 Python 示例为 5.calibration.py,C 示例为 4_user_calibration.c。 标定的适用场景、产物存储与版本要求见标定与配置,本页说明集成流程和运行时行为。
本文在实机上由真人佩戴完成了前四个捏合姿势,第五个姿势 four_finger_bend_90 超时中止,因此没有拿到最终的 URDF 产物。用户门、六姿势清单与各自的约束阈值、反馈结构、状态机、两条超时错误码、skip_constraints 的实际行为全部为实测结果,标定成功后的结果结构按接口契约说明。

前置条件

硬件

标定只读传感器、只写 SDK 侧模型文件,不写固件。

软件

前序步骤

切到具名 SDK 用户。 默认用户不能标定,见下一节。用 --dry-run 先确认:
实测输出:
--dry-run 不连设备也不标定,就为确认用户。

数据流

默认用户不能标定

在默认用户下 --dry-run,示例会在报错之前先给出引导:
真跑的话,SDK 抛出带错误码的异常:
记住 0x4108,它专指这一种情况。

六个引导姿势

step_total 实测为 6,顺序固定: 真人佩戴实测跑到 step 4/6,前四个捏合姿势全部通过。 每个姿势之间要真的把手动过去,状态机靠检测运动来切步,见下文 waiting_movement。

判据分两类

前四个捏合姿势只看一个指标:拇指与对应手指的指尖距离,上限 0.05 m。做起来直观,捏上就过。 后两个姿势换成四根手指朝向的三轴角约束,roll、pitch、yaw 都要落进区间: 约束作用在四指上(不含拇指),所以拇指位置不受此约束。 第五步是整个流程的实际难点。 真人实测在这一步耗尽了 120 秒,收到的提示统计:rotate to decrease roll 43 次、rotate to increase yaw 36 次、rotate to decrease yaw 15 次。 decrease roll 的意思是 roll 要更负,也就是手指要弯得更深。凭感觉弯到四五十度远远不够,区间中心在 −90° 附近,得弯到指根到指尖接近直角。握紧成拳又会让 yaw 跑偏,四指要并排、各自弯曲,不要攥。 flat_open 的区间宽得多,自然摊平就能过。
源码里定义了 8 个姿势,另两个是 thumb_to_index_dip 与 index_to_thumb_emf。默认流程实测只走其中 6 个,step_total 恒为 6。

反馈结构实测

on_feedback 回调收到的是一个 dict。实测第一步的完整内容:
字段分三组: metrics 里每条都自带 label、unit、当前 value、允许上限 max、超出量 error 和一句人话 hint。直接拿去渲染 UI,不用自己写文案。

两条判据是独立的

这一点从实测数据看得很清楚。手套静置在桌上、无人佩戴时: 稳不等于对。 两条都满足才会进入采集。

状态机实测

跳过约束检查跑一轮,捕获到的状态转移:
真人佩戴跑同一条流程,四个捏合姿势依次走完 waiting_movement → waiting_stable → collecting → done,与上面的转移序列一致。 流程里的几个时间常量: waiting_movement 是卡住不动的手套过不去的那一关。上一步 done 之后,状态机检测到真实运动后,才认为下一个姿势开始。静置手套永远停在这里,直到超时。

两条超时是分开的

单步的 120 秒是固定的,timeout_s 调的是整体上限。实测把 timeout_s 设成 25 秒时,先撞上的是整体超时,抛 WujiException。设成 200 秒时,先撞上的是 pinch_middle 的单步 120 秒,抛带 0x4101 的 WujiException。 两种超时均抛出 WujiException,通过错误消息区分整体超时与单步超时。

skip_constraints 的影响

这个选项名字看着无害,实测下来它把姿势正确性检查整个关掉了。 静置在桌上、无人佩戴的手套,在 skip_constraints=True 下顺利通过了第一个姿势的全部三个阶段。 采集到的是一份完全错误的「拇指碰食指」数据。 因为 variance_ok 只管稳不稳,静置最稳。约束一关,就没有任何东西能判断这个姿势是不是真的摆对了。 所以:
  • 调试流程、验证接入、跑自动化冒烟测试时可以用
  • 生成真正要用的手模时绝对不要用,它会安静地产出一份垃圾模型,而且不报任何错

集成步骤

完整示例:Python 手部模型标定 和 C 手部模型标定。 以下为接入片段。Python 导入与 manager 初始化、C 初始化与连接错误分支、回调定义均沿用 Python 示例 和 C 示例。C 每次调用应检查返回状态,失败时按 Python 示例 和 C 示例 释放已有资源并退出。

1. 确认具名用户

标定使用当前 SDK 用户。默认用户会被拒绝,先切换到具名用户。

2. 连接并启动标定

连接目标序列号后,选择可取消的异步 API。正式标定保持 skip_constraints=False,为 Ctrl+C 注册取消处理。

3. 读取结果并释放资源

将上一步的 Python 标定调用包在 try/finally 中,取消或异常时也断开设备。C 辅助函数先释放标定会话,成功后读取并释放结果,所有退出分支都清理设备。

运行与输出

--mode terminal(默认)会给一屏姿势提示,--mode api 只打印回调和结果流。 实测无人佩戴、跳过约束时的状态流:
以上为实机运行结果,设备是右手 Wuji Glove,当前为具名 SDK 用户。手套静置无人佩戴,所以流程停在第二个姿势的运动检测上。 标定成功时返回 handedness 与 calibrated_urdf 路径,模型落到 ~/.wuji/sdk/models/ 下。实测标定超时退出后该目录没有新增文件,未完成的标定不会留下半成品。

注意事项

阻塞式与异步式的取消语义差别写在文档字符串里:
要让用户能随时中断,用 await glove.calibrate(...),别用 calibrate_blocking。

扩展用法

标定之前确认是哪个用户

产物按 SDK 用户进行管理,选错用户会覆盖对应用户的模型,而且不会报错。标定脚本开头打一行:

换手套不用重标

模型按用户加手别存,不绑定序列号。同一用户换一只同侧手套,加载的还是这份模型。换到另一只手则要重标。

把角度数值显示出来,别只显示 hints

hints 只有方向(rotate to decrease roll),没有量。真人实测卡在第五步 120 秒,就是因为不知道还差多少。把 metrics 里的当前值和允许区间一起渲染出来,调整一次就能到位:
做标定向导时这是最值得花的一点力气。

把 hints 直接给用户看

metrics 里的 hint 是现成的人话(比如 move the two fingertips closer),label 和 unit 也齐了。做 UI 时照着渲染就行,别自己另写一套判断逻辑。

标定完验证效果

拿标定前录的一段数据,用离线管线分别跑默认手模和新手模,逐帧比关节角,就能量化标定带来的变化。方法见离线数据处理。

别用 skip_constraints 生成正式手模

再说一遍:静置的手套在这个选项下能通过姿势检查。它只适合调试流程。

相关内容