Files
chenlin 8e7ab5fc76 feat(tracking): v0.1.2 双手轨迹回放与 GUI 预览
支持 L20 右手模型身份与严格浮动控制覆盖层,新增完整轨迹受限回放、时间拉伸及可选 GUI 显示。

验证:88 项 CPU/USD 回归、Ruff、格式与独立暂存审查通过。历史 80 倍降速回放完成 2x32000 步;整合后 GUI E2E 和完整 pre-commit 未执行,相关边界见 L20_TRACKING.md。

右手 USD、示教数据、媒体和日志未纳入提交;资产存储及许可仍待确认。保留原控制与安全阈值。
2026-09-14 13:57:57 +08:00
..

L20 右手:转换资产与受限跟踪验证

状态与入口

用户提供的 linker-bot/Linkerbot_URDF/L20/RIGHT/linkerhand_g20_right.urdf 已使用指定 IsaacLab/scripts/tools/convert_urdf.py 实际转换。保留源文件与生成命名:URDF 内部 robot 名为 linkerhand_L25NS_right.urdf,导入器生成入口为 linkerhand_g20_right/linkerhand_g20_right.usda。 用户明确该 RIGHT 目录为本次 L20 右手输入;不由上述名称推断驱动类型或电机数。

  • 原始转换结果保持不变,依赖包完整、引用相对路径,可整体移动;不是左手 USD 镜像副本。
  • tracking.usda 是单独生成的实验控制覆盖层,需搭配跟踪控制器,不能直接 Play 当作悬浮手。
  • tracking_manifest.json 记录原始转换资产身份、关节、限位、质量/惯量、联动与依赖。 dynamic_replay_ready=false 保留;实验入口检查实际覆盖层和运行时响应,不靠 ready 标记授权。
  • source_provenance.json 记录原始 URDF/JSON/STL 的相对路径、字节数、SHA256、轴向与转换设置。 原始文件保留在用户外部源目录,不复制18MiB STL,也未读取 JSON 作为控制协议。
  • 发布 BLOCKED:payloads/geometries.usd 为 4,329,903 bytes,超过普通 Git 单文件2000KB门槛。 生成USD仅获准放入本地工作区,不纳入v0.1.2提交(仅收录本说明及两个JSON清单);后续须确认 Gitea LFS 或获批的版本化外部存储,不能直接提交普通 Git。 现有.gitignore全局忽略*.usd/*.usda,且.gitattributes已有全局LFS规则;本次均未修改。 资产目前是本地忽略文件,不会随普通代码提交自动分发;已有LFS属性不等于本轮确认远端存储/发布许可。 源资产再分发许可尚未确认;用户授权本地仿真不等于授予再分发许可。

转换及核验

实际转换设置预先确定:--headless --fix-base --joint-stiffness 3 --joint-damping 0.1 --joint-target-type position, 不 merge joints,输出参数为目录。这些是未经硬件标定的仿真设置;不是从源硬件推断的增益。 转换输出先置于临时目录,核验后仅复制生成的 USD 目录;带个人源路径的 config.yaml、.asset_hash 和日志留在临时目录。

复现示例(环境变量由调用方指定,不写入 USD 引用):

# LINKERBOT_URDF 指向同版本源包;OUTPUT 必须是新的输出目录,避免覆盖已验证资产。
SOURCE_RIGHT="$LINKERBOT_URDF/L20/RIGHT"
timeout 300s ~/isaacsim/python.sh ~/IsaacLab/scripts/tools/convert_urdf.py \
  "$SOURCE_RIGHT/linkerhand_g20_right.urdf" "$OUTPUT" --headless --fix-base \
  --joint-stiffness 3 --joint-damping 0.1 --joint-target-type position

实际原始 URDF SHA256:aa198155651eb7e815f1c27bc8bd9c902e969e81c1165aed756779db378e715d。 转换源依赖包 SHA256:d38dc5e4d473119b237b86bdd36087788f726abd9f486b1678f4e719d5513098。 控制覆盖层完整包 SHA256:3e2071a60496b23bed252f4e2fc6e1d4540eecc8098578506419b5eb594f7da0。 导入器文档字符串带临时生成路径,不是外部资源引用;所有实际解析依赖均在本目录内。

实际检查结果:22个刚体、21个 revolute 状态关节、16个模型独立目标、5组被动联动。 名字排序与当前左手相同,但几何/惯量/轴方向/限位不宣称相同:

  • 右拇指 thumb_ip=1.03*thumb_mcp(左手1.02);其他四指 dip=.89*pip,全部 offset=0。
  • 右 thumb_cmc_pitch/roll/mcp 上限 .83/1.39/1.25 rad,四指 pip上限 1.75 rad;其余精确值见清单。
  • 原URDF thumb_cmc_yaw 轴为负Z;USD规范轴Z配合 localRot1 后为负Z。 全部21条变换后的轴与源URDF核对通过;不能只看USD的轴字母判断正负。
  • 源 root_joint 是叶 fixed joint,body0为非刚体且世界变换为单位阵的 default Xform,body1为根link。 ArticulationRoot 在 Geometry 容器,不是左手旧固定关节位置。
  • 覆盖层只禁用/停用该叶锚点、迁移根API及去掉五个 follower angular drives。 右源有 NewtonArticulationRootAPI;安装 schema 明确继承 PhysicsArticulationRootAPI,因此一起迁移到根link, 不能留在旧Geometry制造第二个有效根。原本存在的 Physics/Physx/Newton 根API迁移,保留旧/新位置已解析属性, 包括 newton:selfCollisionEnabled=false。左手没有的Newton根API不添加。
  • 门禁要求精确静态端点、单位世界变换、无时间采样/重置绕过、精确根容器;其他prim状态、API、属性、关系和变换保持。 注册schema回归证明迁移后只有一个有效Physics根。Newton后端没有运行;仅验证 PhysX。

真实运行证据(2026-09-11)

Isaac Sim6.0.1、PhysX110.1.13、RTX5080,seed42、单环境、240Hz,无物体/桌面/训练。 完整预算4次 Kit 启动,每次外部timeout300s:转换、右small、右HDF5、左small回归;均退出0。 回放三次各有明确 PASS JSON、两轮完整步数、reset/位置及速度重复性、有限值/限位/被动非零运动检查。 三次均报告浮动根、21个活动状态关节、1个有效根、旧锚点inactive;没有重复/嵌套根或CreateJoint警告。

用例 每轮步数 × 轮数 最大腕位置误差 m 最大腕姿态误差 rad 最大关节误差 rad 最大联动残差 rad
右small(2mmX、.01rad yaw、2s) 480×2 .000366063 .002292019 .009957471 .000525197
右range_4s HDF5(10mmX、.1rad yaw、4s) 960×2 .001207785 .010241941 .018221961 .000575949
左small回归 480×2 .000492342 .003755143 .008628675 .000221643

右range RMS同序:.000761782 / .007442808 / .013643790 / .000266136。 关节/联动列先取每帧各关节最大绝对误差再汇总。两轮汇总相同,但不保证跨运行GPU位级确定性。 左回归与之前左small指标完全相同;左右为不同模型,不能把表中数值解释为同一控制性能 benchmark。

原有控制参数与阈值不变:腕P/D100/10、姿态P/D.2/.02、wrench20N/1Nm;master驱动3/.1,effort.2Nm、velocity.5rad/s。 合成轨迹使用实际右手限位与1.03联动,源参考有限且全有效;所有关节有零位及正向空间,无需负向替代/裁剪。 每步仍只发受限wrench及独立目标,不逐步teleport;只有reset写状态。

实际运行命令(仓库根目录):

export PYTHONPATH="$PWD/source/dex_workbench${PYTHONPATH:+:$PYTHONPATH}"
RIGHT=assets/robots/dex_hand/linkerhand_g20_right
timeout 300s ~/isaacsim/python.sh scripts/tracking/track_l20.py "$RIGHT/tracking.usda" \
  --manifest "$RIGHT/tracking_manifest.json" --execute-experimental --headless --steps 480
~/isaacsim/python.sh -m dex_workbench_tracking.cli synthetic --manifest "$RIGHT/tracking_manifest.json" \
  --profile range_4s --output "$EVIDENCE/range.hdf5"
timeout 300s ~/isaacsim/python.sh scripts/tracking/track_l20.py "$RIGHT/tracking.usda" \
  --manifest "$RIGHT/tracking_manifest.json" --execute-experimental --headless --steps 960 \
  --hdf5 "$EVIDENCE/range.hdf5" --episode demo_000000

EVIDENCE 由调用方指定为仓库外持久目录。生成HDF5拒绝覆盖;重跑请选择新路径。 仅在用户Kit会话已释放、预算另获授权后执行。 上述9月11日历史运行使用临时证据目录 l20-right:{convert,small,hdf5,left}.log 和 *-result.txt;源/轴核验、CPU回归、插件准备、 日志解析及前后GPU检查在同目录。每次运行前后未发现残留Kit;并不证明所有资源完全恢复。

75项CPU/USD测试通过,含右资产重定位、左右身份错配(即使伪造hash/root)、端点/容器篡改、 注册schema下Newton根继承与时间采样检查。完整pre-commit工具缺失,不能宣称全量发布门禁通过。

兼容性与剩余边界

  • HDF5仍为l20_tracking_v1,新增显式hand_side=right,且必须配套右清单。旧无side左清单兼容; 右清单不得省略side或借用左URDF身份。旧版本读取器只认left,读右数据须升级本次代码。
  • prepared schema context新增Newton根schema,此前生成的覆盖层需要重新生成,不能编辑ready字段绕过。 生成时重复传入 --schema-plugin-path,分别指向安装的PhysX和Newton plugInfo.json,见根目录L20文档。
  • 原始USD/URDF、左侧资产、Cartpole、任务ID及用户Data目录均未修改;v0.1.2仅版本化相关代码与文本元数据。 干净克隆缺少本地右USD依赖,右资产CPU测试/回放仍BLOCKED,不将缺资产跳过当成通过。
  • 仍有TGS外力迭代、16/21 actuator(有意被动)、protobuf重复注册、visualizer/MaterialX/usdrt警告,未压制或调参消除。
  • 上述9月11日证据仅两个简单合成轨迹。9月14日另一次80倍慢放专家参考的完整回放及GUI展示边界 见根目录 L20_TRACKING.md 第5–6节;不证明专家原速、接触/自碰撞任务、 多环境、学习策略、Newton后端或硬件。增益待校准,无SysID/Sim2Real有效性声明。