diff --git a/.gitattributes b/.gitattributes index 99e3579..49a11c3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,3 +15,4 @@ source/isaaclab_tasks/test/golden_images/**/*.png filter=lfs diff=lfs merge=lfs *.bat text eol=crlf *.sh text eol=lf +assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/geometries.usd filter=lfs diff=lfs merge=lfs -text diff --git a/assets/robots/dex_hand/linkerhand_g20_left/README.md b/assets/robots/dex_hand/linkerhand_g20_left/README.md new file mode 100644 index 0000000..8709cff --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/README.md @@ -0,0 +1,102 @@ +# L20 LEFT — 固定基座 PhysX 预览 + +用户确认该 G20 left 命名对应当前 L20;保留导入器生成的名称和目录结构。 + +## 入口与来源 + +- USD 入口:`linkerhand_g20_left/linkerhand_g20_left.usda`(USDA 是 USD 的文本格式)。 +- `linkerhand_g20_left/payloads/` 为完整依赖,需随入口一起移动。 +- 来源:用户提供的 `Linkerbot_URDF/L20/LEFT/linkerhand_g20_left.urdf` 及其 `meshes/`。 +- 源仓库提交:`afc0ac84a4e7cee4245ba421fb985bab014768a0`;转换时源仓库工作区干净。 +- 许可:未在源仓库根目录及其下一层找到许可证,分发授权待确认。 +- 同目录 `g20_left_G20.json` 不属于该转换脚本的输入,未导入为控制接口。 + +## 转换 + +从项目根目录执行,将 SOURCE_DIR 替换为本地源目录: + +```bash +SOURCE_DIR="/path/to/Linkerbot_URDF/L20/LEFT" +timeout 300s ~/isaacsim/python.sh ~/IsaacLab/scripts/tools/convert_urdf.py \ + "$SOURCE_DIR/linkerhand_g20_left.urdf" \ + assets/robots/dex_hand/linkerhand_g20_left --headless +``` + +实际使用 Python 3.12.13,Isaac Lab 提交 +`6a7acb0320a0bdc15b13e44e83b575e00797faf4`。 +转换缓存 `.asset_hash` 和包含本机路径的 `config.yaml` 不纳入版本。 +以下记录原始转换参数;当前预览覆盖配置见后文。 + +- 浮动基座(未传 `--fix-base`),不合并固定关节。 +- 位置驱动,stiffness=100、damping=1,均为工具默认值,非实测标定。 +- Convex Hull 碰撞,self_collision=False。 +- 默认物理 variant 为 `physx`;`mujoco` 层由转换器自动生成,不代表已经开展 MuJoCo 验证。 +- USD 单位:米、千克,Z-up。 + +## 验证与限制 + +- **PASS**:上述转换命令退出码 0;原始 URDF 的 22 个网格文件引用均存在。 +- **PASS**:使用 `~/isaacsim/python.sh` 的 `pxr.Usd.Stage.Open` 和 + `UsdUtils.ComputeAllDependencies` 检查当前入口,10 个 USD 层、0 个未解析依赖、 + 0 个组合错误;默认 prim 有效,默认 physx variant 中有 22 个刚体、21 个关节。 +- **风险**:源 URDF 有 5 个 mimic 约束,但生成的物理层未找到 mimic/coupling/gearing 定义。 + 不得声称耦合已正确保留,也不得把 21 个关节当成 21 个独立驱动。 +- **NOT_RUN**:完整耦合行为、reset/replay、任务发现及训练 E2E。 + 未接入任务;当前仅验证后文限定的拇指动作,不作为训练就绪资产。 +- 转换日志位于本机 `/tmp/dex_l20_convert.log`,含 OmniHub 启动失败重试及扩展警告; + 未阻止本地转换和上述静态 USD 检查,不代表运行环境无问题。 +- `payloads/geometries.usd` 为 6,384,624 字节,超过普通 Git 的 2000 KB 门槛; + 经用户确认 Gitea 支持,使用 Git LFS 管理;克隆后需执行 `git lfs pull`。 +- 当前 Cartpole 任务、包版本和训练配置未改变;源 URDF 未修改。 + +## 固定基座预览场景(2026-09-10) + +当前入口接入同目录 `fixed_base_setup.usda`:世界固定关节、4 m × 4 m +静态碰撞地面(顶面 z=-0.02 m)、DomeLight 和 DistantLight。 +固定关节承载唯一的 PhysicsArticulationRootAPI;手掌处移除原来的 +PhysicsArticulationRootAPI 和隐式继承该 API 的 NewtonArticulationRootAPI。 +本入口现在用于固定基座 PhysX 预览,其他物理 variant 未回归。 + +PhysX 使用 240 Hz、关节系统位置/速度迭代 16/4、自碰撞关闭。 +60 Hz 下实际 Play 出现关节 NaN;仅增加迭代次数仍失败。 +当前配置与有效验证见下文。曾报告的两次“10 秒通过”发生于过短循环时间轴, +只能代表累计回调,不能作为连续运行或 Stop→Play 稳定性证据。 +停止状态下 MCP `step_simulation(120)` 仅刷新界面,也不计为物理验证。 + +## 拇指驱动与有效验证 + +以本节为当前配置:保留 240 Hz、16/4 迭代和 21 对相邻连杆显式碰撞过滤。 +五个 `thumb_*` 关节使用 force 类型位置驱动,USD stiffness=0.017453292、 +damping=0.00034906585、maxForce=1 N·m、armature=0.0001 kg·m²; +PhysX 张量读回的增益为 1 N·m/rad 和 0.02 N·m·s/rad。 +armature 是附加到关节自由度的数值稳定参数,会改变有效惯量,尚未经硬件标定。 +其他手指驱动未调整,不能将本次结果推广到其他关节的大幅动作。 + +入口移除误保存的 `/Render` 编辑器节点,时间范围设为 0–1440 帧(24 fps,60 秒), +当前 GUI 时间轴关闭循环。旧播放区间约为 0.042 秒且开启循环,故前文两次 +“10 秒通过”只代表累计物理回调,撤回其连续运行与重启稳定性的验收结论。 + +实际在用户 Isaac Sim 6.0.1 窗口执行 `scripts/assets/check_thumb_drive_editor.py` +等价代码:0→30→60→80→0→−20→100→0 度,每段 480 个实际物理步, +共 3840 步。结果 PASS:无 NaN/Inf 或连杆逃逸,最大关节速度 1.000008 rad/s; +30/60/80 度指令的末端读数分别为 28.669/59.048/79.459 度; +−20/100 度指令被物理限位约束在约 0/80.214 度,再次回零约 0.000134 度。 +这验证了本序列的数值稳定与 3 度内跟随,不代表高精度控制或真实力矩验收。 +本地结果保存在 `/tmp/l20_thumb_drive_result.json`(不提交)。 + +先前崩溃日志出现 RTX `Out of resource descriptors!`,明确属于渲染资源耗尽。 +移除持久化编辑器渲染节点后本轮未复现,但未做长时间渲染泄漏验证, +不能宣称所有编辑器卡死问题已解决。未执行 Isaac Lab 任务或训练 E2E。 + +## 转换时的原始哈希(非当前修改后文件) + +| 文件 | SHA-256 | +| --- | --- | +| 源 URDF | `b8ef22e436ab311fb61f87091b72ae717821092471d628d0ea9475b5088daa5d` | +| `linkerhand_g20_left/linkerhand_g20_left.usda` | `83571a19a9ac6be575ced1ffff46708f752ad6462fde88c6a15435ac1ee431d5` | +| `linkerhand_g20_left/payloads/geometries.usd` | `6ba619abc15fd30b10c05cd494ec8b4839647004f43a17376e105f4654f1bfcd` | + +回归入口 `scripts/assets/check_thumb_drive_editor.py` 在已打开的 Isaac Sim Script Editor 中运行, +要求干净初始场景、至少 16 秒的播放范围并关闭循环。完成后暂停,结果位于 +`builtins._l20_drive_result`;脚本会改变 target,测试运行态不要保存为资产初始状态。 +未验证的早期 smoke 实验脚本不纳入本次提交。 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/fixed_base_setup.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/fixed_base_setup.usda new file mode 100644 index 0000000..04fa9e7 --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/fixed_base_setup.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d4e01f8c0cb4eb6187dae4f7ba01660b69256d77a0d54f908dcb43fbdde55b7 +size 15463 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/linkerhand_g20_left.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/linkerhand_g20_left.usda new file mode 100644 index 0000000..d697e54 --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/linkerhand_g20_left.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:357d3b24d5a572592dafc4b4c16ea5a0b7cb95f15cc78b7a205ee1724ebe7fc5 +size 4356 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/mujoco.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/mujoco.usda new file mode 100644 index 0000000..1bbebdd --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/mujoco.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3234a6907b8259f72eb3d9f74b38c4d53473b42d67e2a797fce75a4a96c1a49f +size 22309 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/physics.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/physics.usda new file mode 100644 index 0000000..e1eed66 --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/physics.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52c3799c0e494b7dc9795d0f6058901c6b0232702553c924cb42c866fdff7909 +size 38763 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/physx.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/physx.usda new file mode 100644 index 0000000..7cd0f5a --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/Physics/physx.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bd5628593ac5fb00b8a658d670b8d41a5205c930eb1f9edb15b7f3c3bd43ab2 +size 3966 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/base.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/base.usda new file mode 100644 index 0000000..b46b5ca --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/base.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:084df26517fe2cfcfea6fb5bc2c2fe3382182bf07b04dc4547f34e1575658146 +size 37697 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/geometries.usd b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/geometries.usd new file mode 100644 index 0000000..90fc694 --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/geometries.usd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ba619abc15fd30b10c05cd494ec8b4839647004f43a17376e105f4654f1bfcd +size 6384624 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/instances.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/instances.usda new file mode 100644 index 0000000..4c0df4e --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/instances.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6846beddde3bbdba8a5a39a329655314e40cebb6e29e323856e15dc50384d6a0 +size 21195 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/materials.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/materials.usda new file mode 100644 index 0000000..3db5b9f --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/materials.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eccbe067b9585993fe025e5ca0a533c048325d00023d5ec7c6cb3025cc7245e0 +size 1574 diff --git a/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/robot.usda b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/robot.usda new file mode 100644 index 0000000..3b70a97 --- /dev/null +++ b/assets/robots/dex_hand/linkerhand_g20_left/linkerhand_g20_left/payloads/robot.usda @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a1e950de525744a4ee32782a2cf67695175770c0c098b36cefd744df28f833b +size 6465 diff --git a/scripts/assets/check_thumb_drive_editor.py b/scripts/assets/check_thumb_drive_editor.py new file mode 100644 index 0000000..7a6c39b --- /dev/null +++ b/scripts/assets/check_thumb_drive_editor.py @@ -0,0 +1,61 @@ +"""Run inside Isaac Sim to test L20 thumb slider jumps; pauses on completion. + +Results: builtins._l20_drive_result. This changes the slider target temporarily. +Requires a clean initial scene and a nonlooping timeline long enough for 16 seconds. +""" +import asyncio, builtins + +async def drive_test(): + import asyncio, time, builtins, numpy as np, omni.usd, omni.timeline, omni.kit.app, omni.physx + from isaacsim.core.simulation_manager import SimulationManager + from pxr import Usd + s = omni.usd.get_context().get_stage() + tl = omni.timeline.get_timeline_interface() + joint = s.GetPrimAtPath('/tn__linkerhand_g20_lefturdf_cZ0/Physics/thumb_cmc_roll') + target = joint.GetAttribute('drive:angular:physics:targetPosition') + r = {'status': 'RUNNING', 'steps': 0, 'segments': [], 'max_speed': 0.0} + builtins._l20_drive_result = r + + def step(dt): + r['steps'] += 1 + sub = omni.physx.get_physx_interface().subscribe_physics_step_events(step) + + def arr(x): + return x.numpy() if hasattr(x, 'numpy') else np.asarray(x) + try: + tl.play() + a = None + deadline = time.monotonic() + 60 + for goal in [0, 30, 60, 80, 0, -20, 100, 0]: + with Usd.EditContext(s, s.GetRootLayer()): + target.Set(float(goal)) + start = r['steps'] + while r['steps'] - start < 480: + await asyncio.wait_for(omni.kit.app.get_app().next_update_async(), 10) + assert time.monotonic() < deadline, 'Wall timeout' + if r['steps'] < 4: + continue + if a is None: + a = SimulationManager.get_physics_simulation_view().create_articulation_view('/tn__linkerhand_g20_lefturdf_cZ0/Physics/fixed_base_joint') + names = list(a.shared_metatype.dof_names) + idx = names.index('thumb_cmc_roll') + q = arr(a.get_dof_positions()) + v = arr(a.get_dof_velocities()) + links = arr(a.get_link_transforms()) + assert all((np.isfinite(x).all() for x in [q, v, links])), 'Nonfinite state' + r['max_speed'] = max(r['max_speed'], float(np.abs(v).max())) + assert np.abs(v).max() < 10, 'Excessive speed' + assert np.abs(links[..., :3]).max() < 0.5, 'Escaped link' + assert q[0, idx] > -0.05 and q[0, idx] < 1.45, 'Roll limit violation' + actual = float(np.rad2deg(q[0, idx])) + r['segments'].append({'target_deg': goal, 'actual_deg': actual}) + assert abs(actual - min(80.214, max(0, goal))) < 3, 'Tracking error ' + str(actual) + r['status'] = 'PASS' + except Exception as e: + r['status'] = 'FAIL' + r['error'] = str(e) + finally: + tl.pause() + sub = None +builtins._l20_drive_task = asyncio.ensure_future(drive_test()) +print('Started bounded thumb target-jump test') diff --git a/source/dex_workbench/docs/CHANGELOG.rst b/source/dex_workbench/docs/CHANGELOG.rst index a38ef02..3e3da67 100644 --- a/source/dex_workbench/docs/CHANGELOG.rst +++ b/source/dex_workbench/docs/CHANGELOG.rst @@ -1,10 +1,23 @@ Changelog --------- +Unreleased +~~~~~~~~~~ + +Fixed +^^^^^ + +* Configure the L20 PhysX preview with a world-fixed articulation root, ground, + lighting, and 240 Hz physics to prevent the observed 60 Hz instability. + Add a bounded editor smoke script; Isaac Lab task integration is not included. +* Stabilize L20 thumb target reversals with bounded position drives and numerical + armature, explicitly filter adjacent links, and correct the preview timeline. + Remove persisted editor render nodes; long-duration RTX stability remains unverified. + 0.1.0 (2026-09-10) ~~~~~~~~~~~~~~~~~~ Added ^^^^^ -* Created an initial template for building an extension or project based on Isaac Lab \ No newline at end of file +* Created an initial template for building an extension or project based on Isaac Lab