标定
Wuji Glove 用 EMF 解算手部关节角度时,需要先做一次 IK 标定,生成与穿戴者手型匹配的 URDF 模型。SDK 提供 Python 标定 API、运行时手型切换、用户自定义 URDF 覆盖,并按 SDK 用户与设备序列号隔离标定文件。
何时需要标定
- 首次使用一台手套
- 更换穿戴者
- 上层应用需要切换 Wuji Hand / Wuji Hand 2 模型
设备序列号已包含左右手信息,左手套和右手套各自独立标定,互不影响。启用 SDK 用户隔离时,每位用户独立持有自己的标定 URDF,见 SDK 用户管理。
标定流程
标定要求穿戴者按提示完成一组规定动作,SDK 采集 EMF 数据并解算出适配的 URDF。
标定开始 SDK 自动把 EMF 降频因数临时强制为 1,采集结束恢复原值(含错误与取消路径)。预先调用 glove.emf_poses_rate_divider().set(N>1) 不会让标定时间被放大。详见 输出率调节。
同步阻塞调用
适合脚本与命令行工具:
from wuji_sdk import SdkManager, Handedness
manager = SdkManager.instance()
glove = manager.connect(handedness=Handedness.Left, device_name="glove")
result = glove.calibrate_blocking(timeout_s=900.0)
print("device_sn:", result["device_sn"])
print("active hand profile:", result["active_hand_profile"])
print("generated profiles:", result["generated_hand_profiles"])
print("URDFs:", result["calibrated_urdfs"])
print("poses collected:", result["poses_collected"])
print("sdk user:", result["sdk_user"]["display_name"])calibrate_blocking() 在标定结束或超时前不返回,Ctrl+C 延迟到方法返回后才响应。
异步调用
asyncio 程序使用异步 API,支持标准 cancellation:
result = await glove.calibrate(timeout_s=900.0)参数
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
skip_constraints | bool | False | 跳过稳定性和约束检查(仅调试用) |
timeout_s | float | 900.0 | 整体超时(秒),必须为有限正数 |
hand_profile | WujiHandProfile 或 str 或 None | None | 指定要生成的手型 profile(见下) |
on_feedback | Callable 或 None | None | 实时反馈回调 |
实时反馈
通过 on_feedback 回调获取标定过程中的状态:
def on_feedback(fb):
if fb.get("state") == "collecting":
progress = fb.get("progress", 0.0)
step = fb.get("step_index", 0)
total = fb.get("step_total", 0)
print(f"step {step}/{total}: {progress*100:.0f}%")
for hint in fb.get("hints", []):
print(f"hint: {hint}")
result = glove.calibrate_blocking(on_feedback=on_feedback)fb 字典包含当前姿势序号、状态、进度、采集帧数、姿势偏差诊断指标 (metrics) 与提示文本 (hints) 等字段。
回调内抛出的异常会被 SDK 记录到日志,不会中断标定。
手型选择
Wuji Glove 支持两代手型的实时 IK 模型:
| 手型 | 字符串值 | 枚举 |
|---|---|---|
| Wuji Hand | "wujihand" | WujiHandProfile.WUJI_HAND |
| Wuji Hand 2 | "wujihand2" | WujiHandProfile.WUJI_HAND_2 |
标定时指定手型
from wuji_sdk import WujiHandProfile
result = glove.calibrate_blocking(
hand_profile=WujiHandProfile.WUJI_HAND_2,
)
# result["generated_hand_profiles"] == ["wujihand2"]
# result["calibrated_urdfs"] == {"wujihand2": "/path/to/...urdf"}不指定 hand_profile 时,SDK 用同一批采集数据同时生成两代 URDF,写入:
calibration.hand_model_paths.wujihandcalibration.hand_model_paths.wujihand2
实时 IK 默认使用 "wujihand",运行时可直接切换。
运行时切换手型
calibration.hand_profile 参数通过 SET 在线切换实时 IK 模型:
# 切到 Wuji Hand 2
glove.set("calibration.hand_profile", "wujihand2")
# 切回 Wuji Hand
glove.set("calibration.hand_profile", "wujihand")切换在下一帧生效。未设置 calibration.hand_profile 时默认为 "wujihand"。
自定义 URDF 覆盖
calibration.hand_model_path 可指定用户提供的 URDF 文件,优先级最高:
glove.set("calibration.hand_model_path", "/path/to/custom_hand.urdf")清空该值后,SDK 按 calibration.hand_profile 回退到标定生成的 URDF。
URDF 查找顺序
实时 IK、tf_static、offline_pipeline 加载手部 URDF 的优先级:
- 用户自定义路径:
calibration.hand_model_path指向 SDK 托管目录之外的文件 - 当前 profile 的标定 URDF:
calibration.hand_model_paths.<profile>(wujihand或wujihand2) - legacy 兼容路径:旧版本写入的
calibration.hand_model_paths.hand_1/hand_2或calibration.hand_model_path - 内置默认 URDF:按左右手返回 SDK 自带模型
找不到目标 profile 的标定 URDF 时,SDK 会静默回退到内置默认模型并打印一条 warn 日志。手部追踪不会中断,但解算精度会下降。生产环境应根据日志确认 IK 在用预期的 URDF。
返回字段
calibrate() / calibrate_blocking() 返回的标定汇总:
| 字段 | 类型 | 说明 |
|---|---|---|
device_sn | str | 设备序列号(已编码左右手) |
hand_profile | str 或 None | 调用时传入的 profile,未传则为 None |
active_hand_profile | str 或 None | 实时 IK 标定后将使用的 profile |
generated_hand_profiles | list[str] | 本次实际生成的所有 profile(["wujihand"] 或 ["wujihand","wujihand2"]) |
calibrated_urdfs | dict[str, str] | profile → URDF 文件路径 |
calibrated_urdf | str 或 None | 单 profile 标定时为该路径,多 profile 时为 None |
poses_collected | int | 采集到的姿势数 |
frames_per_pose | dict[str, int] | 姿势名 → 该姿势采集帧数 |
sdk_user | dict | 标定当时的 SDK 用户信息(user_id / display_name / description / is_default) |
标定结果路径
标定 URDF 按 <sn>_hand_<profile>_<calibration_id>.urdf 命名。落盘根目录按 SDK 用户区分:
| SDK 用户 | URDF 目录 | 参数表 |
|---|---|---|
| 默认用户 | ~/.wuji/sdk/models/ | ~/.wuji/sdk/params/<sn>.toml |
| 具名用户 | ~/.wuji/sdk/users/<user_id>/models/ | ~/.wuji/sdk/users/<user_id>/params/<sn>.toml |
唯一性由 (user_id, device_sn, hand_profile) 三元组保证。切换 SDK 用户时,已连接设备会自动重新加载该用户名下对应的 URDF,无需重连。
错误处理
| 场景 | 行为 |
|---|---|
hand_profile 传入非 "wujihand" / "wujihand2" 的字符串或枚举 | 立即抛 ValueError / WujiException,标定不会启动 |
timeout_s 非有限正数 | 立即抛 ValueError |
| 标定超时 | 抛 TimeoutError,本轮采集结果不持久化 |
| 标定中途切换 SDK 用户 | 抛 WujiException(错误信息含 SDK user changed during calibration),本轮采集结果丢弃,旧 URDF 不动 |
| URDF 写入失败 | 抛 WujiException,自动回滚本轮新文件,旧 URDF 与 hand_model_paths 参数保持原值 |
| 标定算法收敛失败 | 抛 WujiException,错误信息标注失败的 hand_profile,旧 URDF 不动 |
所有失败路径都保留上一次成功的标定结果,失败的本轮不会污染已有 URDF,可直接重试。
资源路径速查
| 资源路径 | 访问 | 说明 |
|---|---|---|
calibration.hand_profile | GET / SET | 实时 IK 当前使用的手型("wujihand" / "wujihand2") |
calibration.hand_model_paths.wujihand | GET / SET | Wuji Hand 标定 URDF 路径,由 SDK 写入 |
calibration.hand_model_paths.wujihand2 | GET / SET | Wuji Hand 2 标定 URDF 路径,由 SDK 写入 |
calibration.hand_model_path | GET / SET | 用户自定义 URDF 覆盖(优先级最高) |