Files
hand-motion-pipeline/scripts/report_yesterday_spider.py
liyang ae28d55f81 Update to 2026-09-17 pipeline snapshot; add weights, L20 assets and recording via Git LFS
Source: RGB-D -> Dyn-HaMR -> L20 retargeting -> FoundationPose -> reference repair -> SPIDER,
documented in docs/PIPELINE_LATEST.md and docs/SETUP_AND_WEIGHTS.md. Adds FoundationPose and
nvdiffrast upstream snapshots, requirements/pipeline_venv.txt and the FoundationPose weight
manifest/downloader.

Assets (Git LFS): weights/ (WiLoR detector, HandFlow denoiser, UniDepth-L), FoundationPose
checkpoints, HaMeR checkpoint, Dyn-HaMR HMP model and BMC constraints, L20 URDF/meshes, the
20260915_171525 D405 recording and the two box CADs. MANO models are not redistributed
(third_party/hamer/_DATA/data/mano/README.txt). Environments, caches and run outputs excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:43:37 +08:00

22 lines
6.6 KiB
Python
Raw Permalink 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.
from pathlib import Path
import json,cv2,numpy as np
ROOT=Path(__file__).resolve().parents[1];O=ROOT/'output/foundationpose_spider_20260915'
v=json.loads((O/'validation.json').read_text());p=json.loads((O/'preparation.json').read_text());extra={}
for name in ['foundationpose_overlay.mp4','original_foundationpose_spider.mp4']:
c=cv2.VideoCapture(str(O/name));count=0
while c.read()[0]:count+=1
c.release();extra[name]={'decoded_frames':count,'expected_frames':352,'passed':count==352}
(O/'video_integrity.json').write_text(json.dumps(extra,indent=2))
lines=['# 昨日双手抓取:FoundationPose + SPIDER','', '输入:`docs/20260915_171525`352 帧。复用昨日 RGB-D 校正后的 Dyn-HaMR/L20 双手轨迹;没有重新做人手推理。','', '## 已完成的链路','', '1. FoundationPose 根据 RGB、对齐深度、内参与两个 STL 逐帧估计物体相机坐标位姿。','2. 使用昨日 RGB-D 相机里程计统一手、物体坐标;用初始深度拟合桌面方向。','3. 逐指尖选择最近可观测物体,生成可切换的接触目标;接触阈值 25 mm,释放阈值 35 mm。','4. 先做有界关节/手腕平移接触与碰撞初始化,再运行真正的 `third_party/spider/examples/run_mjwp.py`,使用 MuJoCo Warp 物理滚动优化。','5. 最终实际滚动物体执行器增益为零;物体不是逐帧强制写回参考轨迹。','', '## 观测边界','', '- 红盒 307/352 帧通过可见颜色覆盖与深度一致性筛选,未通过帧插值补全。','- 蓝盒 177/352 帧可用;177 帧起遮挡,参考位姿保持最后可用世界位姿,并停止将其作为新的接触目标来源。蓝盒遮挡段不是观测结果,后续红蓝相对装配也不是已验证事实。','- 有效判定不是外部真值:颜色像素 >500、投影覆盖 >65%、重叠像素深度中位残差 <20 mm。蓝盒遮挡边界另行显式屏蔽。','- 接触是几何假设,不是触觉标签。左右手均可切换到红盒接触。','- 物体质量各 0.12 kg、摩擦系数 0.8 是仿真假设;桌面方向来自深度,不是 IMU。','- 每个物体采用 20 个 CoACD 凸分块;孔洞和凹槽碰撞仍是近似。物体关节增加 0.001 armature 抑制欧拉角坐标翻转时的数值病态,非实测惯量。','', '## 本次实际结果','', '| 指标 | 昨日手 + 新物体位姿 | 接触/碰撞初始化 | SPIDER 物理结果 |','|---|---:|---:|---:|']
for label,key in [('最大手物穿透/mm','max_hand_object_penetration_mm'),('逐帧最大穿透中位数/mm','median_frame_max_penetration_mm'),('推断接触目标平均间隙/mm','inferred_contact_target_gap_mean_mm'),('有关联手物碰撞的帧数','hand_object_contact_frames')]:
vals=[v[k][key] for k in ['original_hands_new_objects','kinematic_contact_warmstart','spider']];lines.append('| '+label+' | '+' | '.join(f'{x:.2f}' for x in vals)+' |')
for name,cn in [('upper','红盒'),('lower','蓝盒')]:
r=v['spider'][name];lines+=['',f'{cn}可观测帧的位置误差:平均 **{r["observed_position_error_mean_mm"]:.1f} mm**,最大 **{r["observed_position_error_max_mm"]:.1f} mm**;平均旋转误差 **{r["observed_rotation_error_mean_deg"]:.1f}°**。误差对照 FoundationPose 参考,并非外部真值。']
lines+=['',f'物理软约束残差:视频抽样最大关节限位超出 {v["spider"]["max_joint_limit_violation_rad"]:.4f} rad,最大 mimic 偏差 {v["spider"]["max_mimic_residual_rad"]:.4f} rad。', '',f'完整物理轨迹:{v["full_steps"]} 步,{v["duration_s"]:.2f} 秒,全部有限值:{v["all_states_finite"]}。20 mm 最大物体位置跟踪门槛通过:**{v["tracking_20mm_gate_passed"]}**。', '', '穿透统计使用碰撞近似模型,按视频 30 Hz 抽样;不能当成全部 400 Hz 物理步的最大穿透,也不能代表 STL 精确有符号距离。', '', '## 文件','', '- `original_foundationpose_spider.mp4`:原视频 / FoundationPose+接触初始化参考 / 实际 SPIDER 物理结果。','- `foundationpose_overlay.mp4`:物体投影检查,逐帧显示有效标记。','- `foundationpose_objects.npz`:原始相机/世界位姿与有效标记。','- `object_reference.npz`:明确补全后的仿真参考与源世界到仿真变换。','- `comparison_motion.npz`:原手、新参考、Spider 视频帧轨迹及完整物理轨迹。','- `spider_trajectory.csv`:完整物理 qpos 与控制量,关节顺序见表头。','- `validation.json`、`preparation.json`、`video_integrity.json`:验证和假设。','- `independent_gpu_replay.npz/json`:保存控制量的独立 GPU 重放与未优化控制基线。','', '## 适配与复现','', '两个 L20 各有 27 状态自由度、22 个执行器通道。包装器修正上游使用 actuator 数量切分双手状态奖励的索引;原始 L20 线性 mimic 被保留。由于存在双手换物接触,关闭“每只手永远对应固定物体”的拇指位移启发式,保留物体参考虚拟辅助衰减及逐指接触奖励。实际滚动始终无物体辅助。', '', '```bash','source scripts/foundationpose_env.sh','.venv/bin/python scripts/track_yesterday_boxes.py','.venv/bin/python scripts/decompose_yesterday_boxes.py','.venv/bin/python scripts/prepare_yesterday_spider.py','.spider/bin/python scripts/run_yesterday_spider.py','.spider/bin/python scripts/replay_yesterday_spider_gpu.py','.venv/bin/python scripts/evaluate_yesterday_spider.py','.venv/bin/python scripts/audit_yesterday_geometry.py','.venv/bin/python scripts/report_yesterday_spider.py','```','', '运行需要 GPU;未提供硬件控制命令,也未验证真实机械手稳定抓取。']
if not v['tracking_20mm_gate_passed']:lines.insert(2,'**状态:完整链路已跑通,但物理抓取跟踪未通过 20 mm 门槛;不能宣称已经修复稳定抓取。**\n')
if (O/'geometry_audit.json').exists():
g=json.loads((O/'geometry_audit.json').read_text());z=g['full_rate_spider_collision'];lines+=['','## 独立几何检查','',f'全部 {z["steps"]} 个物理步的最大手物碰撞穿透:{z["max_hand_object_penetration_mm"]:.2f} mmCoACD 近似几何)。','', '红盒精确闭合 CAD 的 42 个手部关键点探针结果见 `geometry_audit.json`。这是点探针检查,不能替代完整机械手网格相交检测。']
if 'independent_replay_integrity' in v:
x=v['independent_replay_integrity'];lines+=['','## 保存控制量重放','',f'独立 GPU 重放全部有限值:{x["all_finite"]};相对原 Spider 轨迹最大 qpos 数值差:{x["max_difference_from_native_spider_qpos"]:.6g}(混合位置/角度单位)。独立重放未复现原 Spider 物体轨迹,存在明显接触动力学差异,不能作为已验证可重放的抓取控制。']
(O/'README.md').write_text('\n'.join(lines)+'\n');print(json.dumps(extra,indent=2))