7e4ef6f98b
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
479 lines
28 KiB
Markdown
479 lines
28 KiB
Markdown
# HandFlow 项目:手部动作重定向流程与踩坑记录
|
||
|
||
整理日期:2026-09-15。依据当前本地脚本、输出 README 与 JSON 验证报告整理;本次仅整理文档,没有重新执行重建、重定向或动力学优化。文中数值是保存的运行结果,不代表新一轮实验。
|
||
|
||
## 1. 当前实现与结论边界
|
||
|
||
本项目的机器人重定向流程,将视频重建的人手动作转换为机器人手的关节轨迹,再保留世界坐标下的腕部运动,并增加物体接触处理。
|
||
|
||
当前机器人分支实际消费的是 **Dyn-HaMR 的 MANO 重建结果**。仓库主 README 中 HandFlow FM 推理入口与这里新增的机器人脚本应区分;不能将这次全部输出描述为 HandFlow FM 模型直接生成的机器人动作。
|
||
|
||
| 阶段 | 已有结果 | 能支持的结论 | 尚不能支持的结论 |
|
||
|---|---|---|---|
|
||
| Dyn-HaMR 重建 | 1333 帧、两条手轨迹、相机参数与世界坐标参数 | 全长重建及渲染流程完成 | 已达到实测三维精度 |
|
||
| LEAP 基线 | 四指、固定腕部的 dex 重定向 | 人手关键点到机器人关节链路可运行 | 移动腕部或抓瓶成功 |
|
||
| L20 基础重定向 | 16 主动 + 5 被动关节,移动腕部 | 限位、联动与前向运动学一致性通过 | 真实硬件可直接执行 |
|
||
| 离线平滑 | 完整 1333 帧手部轨迹 | 保存指标显示连续性改善 | 实时滤波或无偏恢复真实运动 |
|
||
| 全长接触回放 | 44.43 秒完整视频 | 指定姿态下接触几何与连续性检查完成 | 44 秒动力学稳定抓取 |
|
||
| SPIDER | 2 秒片段优化及独立 CPU/GPU 回放 | GPU 上保持接触,明显优于原控制基线 | 通过保持门限、跨后端可靠抓取或硬件验证 |
|
||
|
||
**当前完整视频是运动学接触回放。SPIDER 只验证了两秒片段,保持门限未通过,独立 CPU 回放出现滑脱。**
|
||
|
||
## 2. 数据流、版本与关键文件
|
||
|
||
```text
|
||
2047635068.mp4
|
||
→ Dyn-HaMR / VIPE / 运动先验等上游处理
|
||
→ output/results_2047635068/world_results.npz
|
||
→ export_dynhamr_dex.py
|
||
→ output/dex_2047635068/human_joints.npz
|
||
├─ run_dex_leap.py → LEAP 固定腕部基线
|
||
└─ run_dex_l20.py → L20 JSON 非线性联动、移动腕部
|
||
→ jitter_audit/corrected/motion.npz
|
||
→ smooth_l20_offline.py
|
||
→ jitter_audit/temporal/motion.npz
|
||
├─ prepare_spider_l20.py → 线性联动、2 秒参考与场景
|
||
│ → run_spider_l20_contact.py → SPIDER 动力学结果
|
||
│ → 独立 GPU / CPU 控制回放
|
||
└─ build_l20_full_replay.py
|
||
→ 复用已准备的 SPIDER 场景及初始配准
|
||
→ 线性联动、全长接触配准
|
||
→ output/l20_full_replay/
|
||
```
|
||
|
||
这里存在真实的文件依赖:全长回放构建脚本读取 SPIDER **准备阶段**生成的场景和初始参考,不要求先跑完 SPIDER 优化。它没有把 SPIDER 的两秒优化结果扩展成整段物理结果。
|
||
|
||
| 用途 | 文件 |
|
||
|---|---|
|
||
| 导出人手关键点 | [export_dynhamr_dex.py](../scripts/export_dynhamr_dex.py) |
|
||
| L20 重定向入口 | [run_dex_l20.py](../scripts/run_dex_l20.py) |
|
||
| JSON 标定与非线性联动 | [l20_calibrated.py](../scripts/l20_calibrated.py) |
|
||
| URDF/MJCF 与关键点构建 | [l20_model_source.py](../scripts/l20_model_source.py) |
|
||
| dex 目标函数修复 | [l20_consistent_optimizer.py](../scripts/l20_consistent_optimizer.py) |
|
||
| 离线平滑 | [smooth_l20_offline.py](../scripts/smooth_l20_offline.py) |
|
||
| 抖动诊断 | [audit_l20_jitter.py](../scripts/audit_l20_jitter.py) |
|
||
| 全长接触回放构建 | [build_l20_full_replay.py](../scripts/build_l20_full_replay.py) |
|
||
| 全长独立验证 | [verify_l20_full_replay.py](../scripts/verify_l20_full_replay.py) |
|
||
| 交互回放与视频导出 | [play_l20_full.py](../scripts/play_l20_full.py) |
|
||
| SPIDER 任务准备 | [prepare_spider_l20.py](../scripts/prepare_spider_l20.py) |
|
||
| SPIDER 官方入口封装 | [run_spider_l20_contact.py](../scripts/run_spider_l20_contact.py) |
|
||
|
||
## 3. 第一步:从 MANO 参数得到 21 点与腕部轨迹
|
||
|
||
输入 `world_results.npz` 包含 `pose_body`、`betas`、`root_orient`、`trans`、`is_right` 等字段。导出脚本要求恰好有一条整段一致的右手轨迹,否则断言失败。
|
||
|
||
对选定轨迹,按批次使用 Dyn-HaMR 自带 MANO wrapper 计算:
|
||
|
||
1. 将手指姿态展开为每帧 45 维 axis-angle 参数,使用该轨迹的固定手形 `betas`。
|
||
2. 根旋转和整体平移设为零,运行 MANO 前向运动学。
|
||
3. 所有点减去腕点,得到局部 21 点 `joints`,形状为 `(T,21,3)`。
|
||
4. 使用重建的根旋转、平移再次运行 MANO,取第 0 点作为 `wrist_world`。
|
||
5. 保存根旋转、原始平移、源轨迹编号和源文件路径,便于追溯。
|
||
|
||
世界腕点需要前向计算,因为模型的腕点定义包含手形等影响;不能直接用 MANO `trans` 代替。沿用原 wrapper 也避免额外叠加手部均值造成姿态约定变化。
|
||
|
||
当前脚本把帧率写为 30,输入视频恰好也是 30 fps。换视频时必须修改这一约定以及所有下游时间轴。
|
||
|
||
来源:[上游结果说明](../output/results_2047635068/README.md)、[导出脚本](../scripts/export_dynhamr_dex.py)。
|
||
|
||
## 4. 第二步:对齐掌面,重新构造机器人目标
|
||
|
||
### 4.1 为什么需要重新构造目标
|
||
|
||
人手与 L20 的骨长、指根位置、自由度不同。直接复制人手位置会要求机器人伸到无法到达的位置;直接复制 MANO 角度也没有一一对应的机械含义。
|
||
|
||
当前做法是保留手指骨段方向,使用机器人自身骨长和指根位置。
|
||
|
||
### 4.2 掌面坐标系
|
||
|
||
令腕点为 `p[0]`,食指、中指、小指掌指关节点为 `p[5]`、`p[9]`、`p[17]`:
|
||
|
||
- `z = normalize(p[9] - p[0])`;
|
||
- 从 `p[5] - p[17]` 中去掉沿 z 的分量,归一化得到 y;
|
||
- `x = cross(y,z)`;
|
||
- 组成基底矩阵 `B = [x,y,z]`。
|
||
|
||
机器人中立姿态得到 `B_robot`,每帧人手得到 `B_human`,代码计算:
|
||
|
||
```python
|
||
align = B_human @ B_robot.T
|
||
aligned = (human_points - human_points[0]) @ align
|
||
```
|
||
|
||
上式关键点采用行向量表达;解释旋转时不要将其与列向量乘法顺序混用。
|
||
|
||
### 4.3 骨段方向映射
|
||
|
||
目标先复制机器人中立姿态。五条链是 `(1,2,3,4)`、`(5,6,7,8)`、`(9,10,11,12)`、`(13,14,15,16)`、`(17,18,19,20)`。链起点保持机器人中立位置,随后逐节构造:
|
||
|
||
\[
|
||
p_b^{target}=p_a^{target}+L_{ab}^{robot}
|
||
\frac{p_b^{aligned}-p_a^{aligned}}{\|p_b^{aligned}-p_a^{aligned}\|}.
|
||
\]
|
||
|
||
所以代码使用的是逐骨段长度适配,不是一个整体缩放系数。腕点与指根位置基本固定在机器人掌面局部空间,手指方向随视频改变。
|
||
|
||
机器人侧建立 `landmark_00` 至 `landmark_20`:关节标记主要来自关节原点,指尖来自末端 STL 端部表面的近似点。报告中的指尖拟合误差依赖这些标记定义。
|
||
|
||
## 5. 第三步:有限位逆运动学与联动
|
||
|
||
### 5.1 PositionOptimizer 的求解对象
|
||
|
||
基础 L20 使用 dex-retargeting 0.5.0 的 position 模式,SLSQP 优化 16 个主动角,通过前向运动学匹配 21 个目标点。核心目标是:
|
||
|
||
\[
|
||
\min_{q_t}\ \mathrm{SmoothL1}(FK(q_t)-P_t^{target})
|
||
+\lambda\|q_t-q_{t-1}\|^2,
|
||
\quad q_{min}\le q_t\le q_{max}.
|
||
\]
|
||
|
||
这里 SmoothL1 按位置分量聚合;不是只匹配五个指尖的欧氏距离。`normal_delta=0.002`,dex 内置低通通过 `low_pass_alpha=-1` 关闭,后续由脚本显式平滑。以上目标表达的是修复后的实现。
|
||
|
||
初始姿态来自 JSON 基准命令,主动角先裁剪到有效范围,再通过联动适配器展开。后续顺序逐帧求解,利用前一帧状态。
|
||
|
||
### 5.2 JSON 非线性联动版本
|
||
|
||
提供资产位于 `third_party/l20_assets/L20/RIGHT/`,使用 `linkerhand_g20_right.urdf` 与 `g20_right_G20.json`。
|
||
|
||
标定解释为:
|
||
|
||
\[
|
||
q_j(u)=angle\_rad_j[u]+urdf\_zero\_offset\_rad_j.
|
||
\]
|
||
|
||
具体实现:
|
||
|
||
1. 按 `motor_index` 排序 16 个主动关节。
|
||
2. 每个被动关节找到共享电机编号的主动关节。
|
||
3. 遍历 0–255 命令,排除会使同电机任一关节超过 URDF 限位的值。
|
||
4. 检查有效命令区间连续,并形成主动角上下限。
|
||
5. 从同命令下的主动角、被动角建立分段线性插值曲线。
|
||
6. 前向计算时按曲线展开被动角;反向 Jacobian 使用当前插值段斜率。
|
||
|
||
生成的 URDF 去除原线性 mimic,生成的 MJCF 去除对应 equality,避免原线性关系和 JSON 关系重复生效。原始资产保留不变。
|
||
|
||
### 5.3 量化命令
|
||
|
||
求解后按主动角寻找最近的合法命令值,生成 20 槽位 `command_u8`。11–14 槽位保持 baseline;20 槽位不等于 20 个独立电机。命令再解码成全部关节角,检查量化误差。
|
||
|
||
修正版本报告中的最大量化角误差约 0.00604 rad。该值只是当前 LUT 下的往返误差,不是硬件执行误差。JSON 中还存在复用小指曲线的字段,不能描述成每根手指均独立实测。
|
||
|
||
### 5.4 后续线性联动版本
|
||
|
||
完整接触回放与 SPIDER 按既有需求使用 URDF 线性关系:
|
||
|
||
\[
|
||
q_{passive}=a q_{active}+b.
|
||
\]
|
||
|
||
它们从平滑轨迹读取主动角,再按线性关系重算被动角,同时收紧主动角范围以满足被动角限位。**它们并非重新从人手目标完整执行一次线性版 dex 拟合,也没有继续使用 JSON 被动角。**
|
||
|
||
因此基础 JSON 轨迹的拟合指标和命令文件,不能直接作为最终线性回放的拟合精度与硬件命令。
|
||
|
||
## 6. 第四步:保留腕部运动
|
||
|
||
每帧机器人腕部世界旋转由 `root_orient` 对应旋转矩阵乘以 `align` 得到。腕部世界位置使用 MANO 计算的 `wrist_world`。
|
||
|
||
展示时以首帧腕部旋转的逆作为固定场景旋转,将首帧腕部移至 `(0,0,0.2)`。这一变换只固定一次,整段运动仍然保留。保存原始世界腕点、世界旋转、场景旋转和平移,便于追溯。
|
||
|
||
四元数保存顺序是 WXYZ;SciPy 的默认顺序是 XYZW,读写需要显式转换。相邻四元数若点积小于零,则翻转符号,避免等价四元数符号跳变。
|
||
|
||
基础回放使用 freejoint;SPIDER 和最终全长场景采用三个平移、三个旋转标量坐标。其 CSV/NPZ 布局与基础手部文件不同,不可按列号直接混读。
|
||
|
||
这里没有机械臂模型、机械臂 IK 或机械臂动力学,腕部运动不能直接转换成真实机械臂执行轨迹。
|
||
|
||
## 7. 第五步:抖动诊断与离线平滑
|
||
|
||
基础脚本先对主动角做 `sigma=1` 帧高斯平滑,再重算被动角;腕部最初直接沿用重建结果。
|
||
|
||
后续从修复版基础输出出发,再对主动角做 `sigma=2.5` 帧离线高斯平滑。被动角仍由主动角重新计算,不能独立滤波破坏联动。腕部位置同步平滑;旋转在相对首帧的旋转向量空间处理,脚本断言该片段旋转范数小于 π/2。
|
||
|
||
| 版本 | 最大关节帧间变化 | 关节二阶差分 RMS | 平均指尖拟合误差 |
|
||
|---|---:|---:|---:|
|
||
| 原基础 L20 | 4.139° | 0.12148° | 10.675 mm |
|
||
| 仅修复目标函数 | 2.418° | 0.11907° | 10.680 mm |
|
||
| 修复 + 离线平滑 | 1.529° | 0.03146° | 10.701 mm |
|
||
| 旧接触修正 | 54.375° | 1.67298° | 目标改变,不直接比较 |
|
||
|
||
平滑版本相对原基础关节二阶差分下降约 74.1%;腕部位置二阶差分分量 RMS 降至 0.114 mm,但腕点相对原轨迹最大改变 11.92 mm。
|
||
|
||
二阶差分包含真实动作加速度,不能把它直接叫作测得的噪声。高斯平滑使用未来帧,当前实现属于离线处理;输出不是零延迟实时控制器。
|
||
|
||
证据:[抖动审查](../output/l20_2047635068/jitter_audit/README.md)、[平滑验证](../output/l20_2047635068/jitter_audit/temporal/validation.json)。
|
||
|
||
## 8. 第六步:完整视频接触配准
|
||
|
||
### 8.1 物体与位姿假设
|
||
|
||
当前使用参数化瓶子,高 157.856 mm、最大直径 54.110 mm;瓶肩与瓶颈是规则设计形状。它替换了早期轮廓异常的瓶子模型。
|
||
|
||
没有当前视频逐帧物体位姿,也缺少原三目相机到 VIPE 世界坐标的外参。当前构造固定的瓶子到手掌相对变换:平移 `[0.12,-0.065,0.15]` 米,绕 x 轴旋转 `-π/2`。再使用第 600 帧做场景整体对齐。
|
||
|
||
第 130–160 帧被设为估计抓取过渡,使用平滑权重启用修正。160 帧前瓶子目标固定,后续随估计手掌关系运动。这是人为配准假设,不是视频物体跟踪。
|
||
|
||
### 8.2 求解与连续性
|
||
|
||
每个关键帧优化 22 个修正量:16 个主动角、3 个腕部平移、3 个腕部旋转。
|
||
|
||
残差包含指末端表面距离、全手对物体穿透惩罚、姿态偏移正则和相邻关键帧修正量差异。当前全长脚本的主要尺度为:
|
||
|
||
| 项 | 代码含义 |
|
||
|---|---|
|
||
| 指末端距离 | `(distance + 0.0002) / 0.004`,目标轻微压入约 0.2 mm |
|
||
| 穿透惩罚 | 超过约 0.7 mm 的穿透进入惩罚,以 1 mm 归一化 |
|
||
| 手指连续性 | 与上一求解修正量的差异进入残差 |
|
||
| 腕部修正边界 | 平移各轴 ±65 mm,旋转向量各分量 ±0.55 rad |
|
||
| 求解频率 | 从第 160 帧开始,每两帧一个关键帧,补入末帧 |
|
||
| 求解器 | SciPy `least_squares`,每关键帧最多 65 次函数评估 |
|
||
| 后处理 | 插值修正量,`sigma=1.5` 帧高斯平滑,再乘过渡权重 |
|
||
|
||
前一关键帧解作为下一次初值。插值和平滑后再次展开关节、检查限位与接触。该流程有连续性代价,但不是带硬速度/加速度约束的全局轨迹最优化。
|
||
|
||
### 8.3 回放与检查
|
||
|
||
输出场景移除驱动器,由播放器每帧赋值 `qpos` 后调用 `mj_forward`。瓶子位姿同样由文件指定;场景地板只提供参照,起始瓶子没有物理支撑。
|
||
|
||
保存报告显示:1333 帧有限,限位违规为零,线性联动误差为零,主动角最大帧间变化 1.465°;持瓶阶段 1173 帧中 1172 帧存在手瓶接触。
|
||
|
||
独立 `mj_forward` 接触流形检查最大穿透约 1.008 mm。距离查询保存了约 32.018 mm 的孤立尖峰,与接触流形不一致,应保留两者并说明差异,不能只挑有利数字,也不能据此单独确认同等深度的真实几何穿透。
|
||
|
||
来源:[完整回放说明](../output/l20_full_replay/README.md)、[验证报告](../output/l20_full_replay/validation.json)。
|
||
|
||
## 9. 第七步:SPIDER 两秒动力学实验
|
||
|
||
准备阶段使用第 600–659 帧平滑轨迹、URDF 线性联动和参数化瓶子。初始帧通过多初值 least-squares 配准,并将同一初始修正施加到整个片段,避免逐帧独立接触修补。以五个末端最近表面点建立接触标记和物体参考点。
|
||
|
||
参考插值到 2.5 ms,生成 801 个参考状态,执行 800 步。腕部和手指有位置驱动器,瓶子有搜索用虚拟驱动器。
|
||
|
||
| 配置 | 保存值 |
|
||
|---|---:|
|
||
| 后端 | MuJoCo Warp GPU |
|
||
| 仿真步长 | 0.0025 s |
|
||
| 控制更新周期 | 0.1 s |
|
||
| 预测时长 | 0.6 s |
|
||
| 样本数 | 512 |
|
||
| 每次最大迭代数 | 6 |
|
||
| 指关节力矩限制 | ±1 Nm |
|
||
| 腕平移力限制 | ±200 N |
|
||
| 腕旋转力矩限制 | ±20 Nm |
|
||
| 瓶子质量 / 摩擦系数 | 0.2308 kg / 0.6,未实测 |
|
||
|
||
运行封装调用官方 `examples/run_mjwp.py`。快速入口不支持 `contact_guidance`,所以使用标准入口。搜索阶段物体虚拟辅助增益随迭代衰减,最后清零;独立执行回放的物体增益与偏置为零,没有焊接或每步重设瓶子位姿。
|
||
|
||
保持判据:全程手—物体相对位置相对参考偏差小于 20 mm,且末帧仍有接触。
|
||
|
||
| 测试 | 平均瓶子位置误差 | 接触持续时间 | 结果 |
|
||
|---|---:|---:|---|
|
||
| 原控制 GPU 基线 | 266.90 mm | 0.035 s | 落地 |
|
||
| SPIDER GPU 优化 | 17.76 mm | 2.000 s | 保持接触,门限未通过 |
|
||
| 独立 GPU 控制回放 | 20.14 mm | 2.000 s | 保持接触,门限未通过 |
|
||
| 独立 CPU 控制回放 | 75.97 mm | 1.3675 s | 滑脱落地 |
|
||
|
||
SPIDER GPU 最大手—物体相对位置偏差为 76.64 mm,最大穿透为 3.31 mm。日志有 64 次非有限候选回报警告;最终执行轨迹有限不等于全部候选采样数值稳定。
|
||
|
||
独立 GPU 回放从新模型与初始状态出发,复用控制输入而不调用优化器,仍保持接触。这说明保持现象不只存在于优化器内部状态,但 CPU 差异说明接触与控制仍然敏感。
|
||
|
||
来源:[SPIDER 说明](../output/spider_l20_contact/README.md)、[配置](../output/spider_l20_contact/config.json)、[验证](../output/spider_l20_contact/validation.json)。
|
||
|
||
## 10. 踩过的坑:现象、证据与处理
|
||
|
||
### 10.1 环境冲突与误用启动脚本
|
||
|
||
现有重定向运行约定清空 `PYTHONPATH`、`LD_LIBRARY_PATH`,避免外部 ROS 路径与 Pinocchio 动态库造成冲突。重建导出使用 `.dynhamr`,dex 使用 `.dex`,SPIDER 使用 `.spider`;不要默认它们可以互换。
|
||
|
||
`run_dex_2047635068.sh` 实际运行的是 **LEAP** 分支。重新跑 L20 应显式调用 `run_dex_l20.py`。该差异能直接在脚本中确认。
|
||
|
||
### 10.2 将模型名字、关节数量和命令槽位混为一谈
|
||
|
||
目录名 L20、JSON `model=G20`、URDF 内部历史名称并不完全一致。实现按文件关节名工作,尚未硬件确认具体型号。21 个模型关节、16 个主动控制量、20 个命令槽位是不同概念。
|
||
|
||
### 10.3 重复施加联动约束
|
||
|
||
JSON 非线性 LUT 与 URDF 线性 mimic 不相同。基础版移除生成文件中的线性约束,由 adaptor 接管。后续切换线性版时重算被动角,不能同时保留非线性被动角并期待线性约束自动一致。
|
||
|
||
### 10.4 坐标正确不等于精度可靠
|
||
|
||
MANO wrapper、腕点定义、行列向量乘法、WXYZ/XYZW 都需要显式保持一致。已有 Pinocchio/MuJoCo FK 检查约达 1e-13 m,一致性很好,但它只支持实现约定相符,不能证明单目重建正确。
|
||
|
||
已有坐标诊断未发现该输入掌面轴逐帧翻转,不能未经检查就把所有抖动归因于坐标翻转或角度单位错误。
|
||
|
||
### 10.5 优化器目标值与梯度不一致
|
||
|
||
安装的 PositionOptimizer 返回值缺少时间正则,梯度却包含它。修复补回 `norm_delta * sum((x-last_qpos)**2)`,有限差分最大误差从约 1.20e-4 降至 1.36e-13。
|
||
|
||
但同目标对照中全段关节二阶差分只改善约 1.99%,排除接触前阶段后还略升。它是确定的实现缺陷,不能当作大幅抖动的充分解释。
|
||
|
||
### 10.6 单帧接触修补引入剧烈跳解
|
||
|
||
旧版每八帧独立优化,插值后再修穿透帧,缺少邻帧连续性代价。第 460→461 帧源 L20 最大变化约 0.270°,旧接触修正后无名指 PIP 跳变 54.375°,下一帧反跳 51.614°。
|
||
|
||
旧方案将全段穿透压到约 1.499 mm,但轨迹仍不连续。后续全长方案使用连续热启动、每两帧求解、邻帧修正正则及平滑插值。小穿透与小关节步长必须分开验证。
|
||
|
||
### 10.7 原瓶子网格与碰撞轮廓问题
|
||
|
||
早期提供的 OBJ 封口存在越界、退化三角形,仅在项目副本修复索引和朝向,保留 6146 个顶点,修复后 12288 个三角形。原始目录未修改。
|
||
|
||
早期碰撞用十段圆柱,半径存在突然缩小又扩大的台阶;视觉网格和碰撞近似也有差异。最近碰撞片段切换可能加重优化不连续,但未通过完整物理 A/B 实验量化其独立贡献。后续使用参数化瓶子,不将理想化瓶肩瓶颈宣称为实测形状。
|
||
|
||
### 10.8 几何贴合误当成物理抓稳
|
||
|
||
早期球体接口与旧瓶子实验均出现几何接触收敛但自由物体滑脱。旧瓶子三秒测试末尾相对位移约 17.56 m,与滑落后持续自由落体有关。即使初始静态接触力分配残差很小,也未保证动态保持。
|
||
|
||
处理原则是分别报告目标点误差、表面间距、穿透、自由物体保持和控制回放结果。`mj_forward` 回放视频无法替代 `mj_step` 动力学检查。
|
||
|
||
### 10.9 平均误差下降误当成门限通过
|
||
|
||
SPIDER 的平均位置误差从约 267 mm 降到约 18 mm,但保持判据使用全程最大相对偏差和末帧接触。平均值改善不等于全程达到 20 mm 门限。
|
||
|
||
### 10.10 GPU 与 CPU 回放不一致
|
||
|
||
初始配准改善、仿真步长从 5 ms 降到 2.5 ms 后,CPU/GPU 复核更接近,但最终 CPU 仍滑脱。只能确认后端或接触数值敏感,尚未独立定位唯一原因。下一步应先改进接触与执行器稳定性,而非只延长视频。
|
||
|
||
### 10.11 距离查询尖峰与接触流形不一致
|
||
|
||
全长结果中 `mj_geomDistance` 出现约 32 mm 的孤立穿透量,而独立 `mj_forward` 接触流形最大约 1 mm。保存原始查询和独立验证,明确报告口径;不要静默删尖峰或直接把查询异常等同真实穿模。
|
||
|
||
### 10.12 有限输出不能抹掉采样警告
|
||
|
||
SPIDER 保存轨迹有限,日志仍有非有限候选。验证需同时记录完成标志、最终数组有限性、候选警告和独立回放,不能只看进程完成。
|
||
|
||
### 10.13 离线平滑和硬编码限制
|
||
|
||
当前平滑使用未来帧并改变轨迹;帧率 30、源片段 600–659、抓取区间 130–160、右手选择和瓶子相对位姿均有特定输入假设。换视频不能仅替换一个文件名。
|
||
|
||
### 10.14 旧报告与新脚本可能属于不同版本
|
||
|
||
原 `l20_2047635068/retarget_validation.json` 保存的是历史运行,当前脚本默认已开启目标函数修复。比较修复效果应使用 `jitter_audit/corrected/` 的报告。旧阶段 README 中“尚未执行”的语句可能只描述当时阶段;当前状态应结合下游独立目录及其验证报告读取。
|
||
|
||
## 11. 输出格式与读取注意事项
|
||
|
||
| 文件 | 内容与约定 |
|
||
|---|---|
|
||
| `human_joints.npz` | `(T,21,3)` 局部人手点,米;另含世界腕点与根姿态 |
|
||
| 基础 `motion.npz` | 21 关节角、16 主动角、命令、目标点、实际点、腕位姿与场景变换 |
|
||
| 基础 `trajectory.csv` | 秒、腕部 XYZ、WXYZ 四元数、按关节名排列的角度,rad |
|
||
| 基础 `commands_u8.csv` | 帧号及 20 命令槽位,仅对应生成该文件的 JSON 版本 |
|
||
| 平滑 `temporal/motion.npz` | 平滑后的主字段与部分继承字段;`qpos_raw` 等仍可能是上游历史数据 |
|
||
| SPIDER `optimized_trajectory.csv` | 时间、33 个标量位置坐标、28 个控制输入;不等于硬件命令 |
|
||
| 全长 `motion.npz` | 对应 `scene.xml` 的完整 qpos,含手腕、手指和瓶子坐标 |
|
||
| 全长 `scene.xml` | 场景与资产引用;单独打开只显示模型,需要 NPZ 才能播放 |
|
||
|
||
读取时以各文件字段、`joint_names` 或模型关节顺序为准。平滑脚本会更新 NPZ 内命令数组,但没有另外写出平滑版 `commands_u8.csv`,不要误用基础目录旧 CSV。
|
||
|
||
## 12. 复现步骤
|
||
|
||
以下命令依据现有脚本和保存的运行说明整理,本次未重跑。它们会重新生成对应输出。工作目录固定为 `/home/timessage/HandFlow`,并假定模型、环境与上游重建已存在。
|
||
|
||
### 12.1 基础导出、重定向、平滑
|
||
|
||
```bash
|
||
cd /home/timessage/HandFlow
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= \
|
||
third_party/Dyn-HaMR/.dynhamr/bin/python scripts/export_dynhamr_dex.py
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= .dex/bin/python \
|
||
scripts/run_dex_l20.py --consistent-objective \
|
||
--output-dir output/l20_2047635068/jitter_audit/corrected
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= \
|
||
.dex/bin/python scripts/smooth_l20_offline.py
|
||
```
|
||
|
||
### 12.2 准备瓶子场景与初始配准
|
||
|
||
参数化瓶子已存在于 `third_party/bottle_model_parametric/`。若需要重新生成,先核对并运行 `scripts/build_parametric_bottle.py`。随后:
|
||
|
||
```bash
|
||
env PYTHONPATH= LD_LIBRARY_PATH= \
|
||
.spider/bin/python scripts/prepare_spider_l20.py
|
||
```
|
||
|
||
该步骤生成全长回放依赖的 `scene_act.xml` 和 `trajectory_kinematic_act.npz`,同时准备 SPIDER 两秒任务。
|
||
|
||
### 12.3 全长运动学回放
|
||
|
||
```bash
|
||
env PYTHONPATH= LD_LIBRARY_PATH= MUJOCO_GL=osmesa \
|
||
.spider/bin/python scripts/build_l20_full_replay.py
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= MUJOCO_GL=osmesa \
|
||
.spider/bin/python scripts/verify_l20_full_replay.py
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= MUJOCO_GL=osmesa \
|
||
.spider/bin/python scripts/play_l20_full.py --render
|
||
```
|
||
|
||
构建脚本的初始报告使用距离查询;独立验证脚本会补充接触流形检查。所以生成后应执行验证,不应把构建结束的初始 JSON 当成最终验证报告。
|
||
|
||
### 12.4 SPIDER 优化与独立复核
|
||
|
||
在可访问 GPU 的环境中运行:
|
||
|
||
```bash
|
||
env PYTHONPATH= LD_LIBRARY_PATH= \
|
||
.spider/bin/python -u scripts/run_spider_l20_contact.py
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= \
|
||
.spider/bin/python scripts/replay_spider_l20_gpu.py
|
||
|
||
env PYTHONPATH= LD_LIBRARY_PATH= \
|
||
.spider/bin/python scripts/evaluate_spider_l20.py
|
||
```
|
||
|
||
优化完成应结合 `SPIDER_RUN_COMPLETE`、输出数组、验证报告与独立控制回放确认,不能只看日志正在运行。
|
||
|
||
### 12.5 直接查看已有成品
|
||
|
||
```bash
|
||
/home/timessage/HandFlow/output/l20_full_replay/replay.sh
|
||
```
|
||
|
||
空格暂停/继续,左右方向键逐帧,R 重播,鼠标调整视角。
|
||
|
||
- [完整视频](../output/l20_full_replay/full_replay.mp4)
|
||
- [完整回放说明](../output/l20_full_replay/README.md)
|
||
- [平滑基础 CSV](../output/l20_2047635068/jitter_audit/temporal/trajectory.csv)
|
||
- [SPIDER 对照视频](../output/spider_l20_contact/spider_contact_comparison.mp4)
|
||
|
||
## 13. 换视频或换机器人时需要改什么
|
||
|
||
| 修改对象 | 必须检查的内容 |
|
||
|---|---|
|
||
| 输入视频 | 帧率、长度、左右手选择、重建文件路径、单位与坐标系 |
|
||
| 手模型 | URDF 关节名、限位、指尖标记、掌面轴、主动/被动关系 |
|
||
| 标定表 | 电机槽位、零位偏置、有效命令范围、曲线是否单调及是否实测 |
|
||
| 联动模式 | 明确采用 JSON 还是 URDF,生成与验证使用同一模式 |
|
||
| 物体 | 几何尺寸、视觉/碰撞一致性、物体位姿来源、质量与摩擦 |
|
||
| 接触时段 | 当前 130–160 与 600–659 帧假设不能直接沿用 |
|
||
| 动态执行 | 执行器力矩/速度能力、控制频率、接触稳定性及独立回放 |
|
||
|
||
当前代码没有覆盖任意输入:退化骨段可能导致方向归一化失败;右手轨迹选择有严格断言;短视频无法使用第 600 帧初始化;较大旋转可能触发平滑断言。新增输入应先做小段数据与模型检查,再运行全段。
|
||
|
||
## 14. 后续工作的验证顺序
|
||
|
||
以下为建议,尚未完成:
|
||
|
||
1. 对齐真实型号、联动与标定解释,确定最终采用哪一种控制模型。
|
||
2. 获取或核验物体逐帧位姿与坐标外参,降低手掌关系假设的影响。
|
||
3. 在短片段中定位接触布局、碰撞几何、执行器与 CPU/GPU 差异,先通过无辅助物体驱动的独立回放保持门限。
|
||
4. 增加明确的关节速度、加速度与控制平滑约束,单独报告接触代价和动作偏离。
|
||
5. 短片段通过后,再扩展接近、闭合、持握、抬升以及全长动力学实验。
|
||
|
||
不能用延长运动学视频、增大采样预算或降低平均误差,替代上述稳定性验证。
|
||
|
||
## 15. 主要证据索引
|
||
|
||
- [Dyn-HaMR 上游结果](../output/results_2047635068/README.md)
|
||
- [LEAP 基线与环境约定](../output/dex_2047635068/README.md)
|
||
- [L20 基础实现说明](../output/l20_2047635068/README.md)
|
||
- [修正后的基础验证](../output/l20_2047635068/jitter_audit/corrected/retarget_validation.json)
|
||
- [抖动诊断与消融](../output/l20_2047635068/jitter_audit/README.md)
|
||
- [离线平滑验证](../output/l20_2047635068/jitter_audit/temporal/validation.json)
|
||
- [旧瓶子网格修复、接触跳变与物理失败](../output/l20_2047635068/bottle_grasp/README.md)
|
||
- [全长回放最终验证](../output/l20_full_replay/validation.json)
|
||
- [SPIDER 配准与运行边界](../output/spider_l20_contact/README.md)
|
||
- [SPIDER 最终验证](../output/spider_l20_contact/validation.json)
|
||
|
||
本文件汇总的是仓库中第三方组件与本地集成脚本的行为和已有证据,不用于推断个人贡献归属。
|