Files
mujoco_linkerbot/tools/o30_right_calibration/README_v2.md
T

98 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# O30 右手:五张真机照片与零位联合校准(第二版)
2026-09-21。原来的四组 SDK 指令不变:照片 1~4 分别对应拇指对食指、中指、无名指、小指。照片 5 的实测零位指令为:
```text
[0, 0, 255, 195, 100, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```
在项目根目录执行原命令即可,启动时直接使用上述零位:
```bash
./hands/O30/scripts/run_o30_right_mujoco_plan.sh
```
默认 URDF 已切换到模型目录中的 `linkerhand_o30_right_photo_calibrated.urdf`。仍然订阅 `/cb_right_hand_control_cmd`,消息类型和 20 路顺序不变。零位写入各关节的 `origin` 旋转,行程写入关节上限;SDK 映射从本次实际生成的 MJCF 读取,不重复叠加零位偏移。
## 输入与方法
- 四组捏合原始指令:`samples.json`。
- 五张照片的可见关节位置与零位数组:`photo_landmarks.json`。
- 照片没有可读的本地原文件,本轮从聊天中显示的 540×720 图片人工估计了关节中心和可见指尖位置。标注的像素不确定性为 5~15 像素;捏合时被遮挡的指尖端点不参与图像拟合。
- 对五张照片分别拟合相机位置、方向,并估计一个共享焦距,避免把拍摄视角变化当成关节误差。没有相机标定、畸变参数或实测三维点。
- 同时优化一套共享的 20 个零位偏移、20 个行程比例,以及有限指腹区域内的接触点。所有动作使用同一 URDF 和同一 SDK 映射。
- 目标包括照片关节投影、实测零位下的伸直姿态弱先验、四组指腹相对接触、手指与手掌的穿透限制,以及对原模型的小改动正则。零位照片并不等于测得每个关节恰为 0°,因此先验保留了角度余量。
- 使用多起点、有边界的非线性优化,在 MuJoCo 中反复计算误差。最后三轮局部搜索共 9,088 次目标评估;这是自动试错标定,没有训练强化学习策略。
- 连杆长度、关节轴和 STL 几何未变。新模型使用银灰色外壳和灰色指腹,便于和照片比较。
## 结果与限制
对相同人工标注,上一版和新版都分别拟合相机后进行比较。五张照片的综合关节投影 RMS 从 **11.63 px 降到 8.02 px**,约降低 31%。这是这些标注上的拟合误差,不是真机精度或独立测试结果。
各张照片的 RMS:
- 食指:9.91 → 9.07 px。
- 中指:11.78 → 9.06 px。
- 无名指:6.17 → 7.07 px;联合零位和其他姿态约束后,这一张有小幅回退。
- 小指:17.87 → 8.30 px。
- 零位:9.46 → 6.52 px。
实际启动脚本生成的 MuJoCo 模型中,四组指腹碰撞网格有符号距离分别为 −0.054、−0.042、+0.024、−0.025 mm(正为间隙,负为穿透)。拟合指腹法向误差均小于 1°,这五组姿态的最大网格穿透小于 0.06 mm,零位没有检测到穿透。**这些是仿真内部的接触指标,不是真机达到亚毫米精度的证明。**
保留的行程比例边界为 0.5~1.5。拇指根部 roll 和小指 PIP 的行程拟合触及边界,说明这些参数仍比较敏感。额外尝试 0.35~1.8 的范围后,图像 RMS 只从 8.02 降至 7.86 px,约 0.17 px 的改善小于人工标注误差,而且小指 PIP 仍触及新边界,因此保留较保守的版本。
单视角照片不能唯一确定所有关节的真实零位和完整机械行程。食指 DIP 在已有动作里始终为 0,行程没有得到观测支持,保留原值。仍需更多视角、关节端点角度或额外动作验证未见姿态与全行程;本次没有做真机操作或 PD 动力学标定。
## 查看和复现
第二版对比图:`reports/o30_right_photo_calibration/photo_fit_comparison.png`。上排为上一版只拟合接触的模型,下排为照片与零位联合拟合;每列使用相同相机和中性材质。最后一列是第五张照片的零位。
报告目录还包含五张单独姿态图和 `*_landmarks.png`:青色圈是人工照片标注,红点是模型投影,黄色线表示偏差。这些是模拟图上的标注诊断,不是原始照片叠图。参数、相机与逐点误差保存在模型目录的 `o30_right_photo_calibration.json`,当前生成模型的验证结果在报告目录的 `validation.json`。
独立预览零位或某组捏合,不发送 ROS 控制指令:
```bash
venv/bin/python tools/o30_right_calibration/fit_photos.py --preview zero
venv/bin/python tools/o30_right_calibration/fit_photos.py --preview pinky
```
也可将 `pinky` 替换为 `index`、`middle`、`ring`。
只生成模型并验证/渲染:
```bash
O30_RIGHT_PREPARE_ONLY=1 ./hands/O30/scripts/run_o30_right_mujoco_plan.sh
OPENBLAS_NUM_THREADS=1 venv/bin/python tools/o30_right_calibration/fit_photos.py --check --render
```
重新优化第二版,再生成模型:
```bash
OPENBLAS_NUM_THREADS=1 venv/bin/python tools/o30_right_calibration/fit_photos.py --fit --starts 3 --max-nfev 250
O30_RIGHT_PREPARE_ONLY=1 ./hands/O30/scripts/run_o30_right_mujoco_plan.sh
venv/bin/python tools/o30_right_calibration/fit_photos.py --check --render
```
当前版本请使用 `fit_photos.py`。旧的 `calibrate.py` 是第一版接触拟合的实现和公共函数,不包含五张照片的约束。
运行消息回归测试:
```bash
source /opt/ros/jazzy/setup.bash
PYTHONPATH="$PWD/venv/lib/python3.12/site-packages:$PYTHONPATH" python3 tools/o30_right_calibration/test_calibration.py
```
已验证实测零位初始化、四组真实 `JointState` 类型消息经过桥接回调后到达正确姿态、模型切换后的 SDK 行程同步、无效模型限位拒绝。另检查了四组捏合、实测零位、全 0、全 255 和 30 组随机输入,共 37 组;导出后所有连杆位置与优化模型的最大差异约为 `3.9e-10 m`。随机输入仅验证导出与映射一致,不代表其与真机一致或运动过程无碰撞。
## 备份
原始模型仍保留为 `linkerhand_o30_right_stock.urdf` 和 `linker_hand_o30_right_stock.xml`。上一版保留为 `linkerhand_o30_right_pinch_calibrated_v1.urdf`、`o30_right_pinch_calibration_v1.json`;上一版说明见 `README_v1.md`。
临时使用上一版模型:
```bash
O30_RIGHT_URDF="$PWD/src/linkerhand-sim/linker_hand_mujoco_ros2/linker_hand_mujoco_ros2/urdf/O30/linker_hand_o30_right/linkerhand_o30_right_pinch_calibrated_v1.urdf" ./hands/O30/scripts/run_o30_right_mujoco_plan.sh
```
之后正常运行原启动命令,就会再次生成并使用第二版照片校准模型。