Skip to content

fix(entity): write root velocity via free-joint DoFs, not set_vel/set_ang - #244

Merged
KraHsu merged 2 commits into
mainfrom
dev/fix-root-velocity-writes
Jul 10, 2026
Merged

fix(entity): write root velocity via free-joint DoFs, not set_vel/set_ang#244
KraHsu merged 2 commits into
mainfrom
dev/fix-root-velocity-writes

Conversation

@KraHsu

@KraHsu KraHsu commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #242 — and the same dead idiom everywhere else it was copied.

Genesis's RigidEntity API is asymmetric: get_vel / get_ang exist, but set_vel / set_ang exist only on FEM / tool entities. Every write site built on getattr(handle, "set_vel", None) therefore silently no-opped on rigid articulations:

  • mdp.push_by_setting_velocity — the entire event (the bug: push_by_setting_velocity 对 RigidEntity 静默失效(set_vel/set_ang 不存在) #242 report)
  • mdp.reset_root_state_uniform — the velocity half
  • ArticulationWriter.write_root_state — velocity halves (pose worked)
  • examples/wuji reorient — cube reset velocity zeroing, the interval velocity kick (its docstring calls it "the important robustness lever"; it read current velocity via the existing getters, then wrote through the missing setters), and the goal-marker velocity zeroing
  • examples/franka — cube reset velocity zeroing

Fix: new genelab.entity.write_root_velocity(handle, lin_vel_w, ang_vel_w, env_ids) routes the write through set_dofs_velocity on the base free joint's 6 DoFs (0–2 world-frame linear, 3–5 angular; free-joint discovery mirrors the binder's n_dofs >= 6 idiom), with a fallback to the direct setters for entity types that genuinely have them (FEM / tool entities, existing test fakes). All seven sites now call it. Fixed-base entities correctly write nothing (False return).

Impact note (in CHANGELOG): policies previously trained with push events effectively had those disturbances disabled; retraining may be needed where push robustness matters.

Test plan

  • 11 new tests in tests/test_root_velocity.py: fakes mirror the Genesis 1.2 surface (deliberately without set_vel/set_ang) so a regression to the old idiom fails instead of no-opping — covers the helper, both event terms, the writer seam, fixed-base and fallback paths
  • genesis_runtime-gated integration test: builds a real free box (RigidObjectCfg(fixed=False)), writes velocity, reads it back via get_vel/get_ang
  • Existing test_articulation_state root-state round-trip still passes (its fake has 1-DoF joints only → takes the fallback path)
  • Local: ruff check + ruff format --check clean; pyright adds no new errors over main; full suite 925 passed / 4 skipped (one pre-existing, environment-only Qt/plotter abort in full-process runs reproduces identically on clean main and is unrelated)

🤖 Generated with Claude Code

KraHsu added 2 commits July 10, 2026 13:23
…_ang

Genesis's RigidEntity exposes get_vel/get_ang but no set_vel/set_ang
(those setters exist only on FEM/tool entities), so every root-velocity
write built on getattr(handle, "set_vel", ...) silently no-opped on
rigid articulations: push_by_setting_velocity, the velocity half of
reset_root_state_uniform, Articulation.write_root_state, and the cube
kick/reset paths in the wuji and franka examples. Push-based domain
randomization never reached the simulator.

Root velocity now routes through genelab.entity.write_root_velocity,
which drives set_dofs_velocity on the base free joint's 6 DoFs (0-2
world-frame linear, 3-5 angular) and falls back to the direct setters
for entity types that genuinely have them (FEM/tool entities, test
fakes). A genesis_runtime-gated test round-trips the write through a
real free box and reads it back via get_vel/get_ang.

Fixes #242
Auditing every getattr-guarded Genesis call after #242 found one more
live silent no-op of the same class: Genesis 1.2's outer Viewer forwards
register_keybinds but not set_message_text, so the keyboard bridge's HUD
line never displayed. Fall back to viewer._pyrender_viewer (the same
wrapper gap the viewer.plugins / _viewer_plugins scene fallback covers).

Everything else checks out against Genesis 1.2: all DR setters, sensor
getters, and solver set_gravity exist; set_dofs_friction and
set_dofs_position_target are dead-but-harmless second arms of or-chains.
tests/test_genesis_api_contract.py now pins every getattr-guarded name
against the installed Genesis so upstream renames fail loudly at the
next version bump instead of silently disabling physics or UI.
@KraHsu

KraHsu commented Jul 10, 2026

Copy link
Copy Markdown
Owner Author

Follow-up: same-class audit (pushed as 10dad32)

The root cause of #242 isn't set_vel/set_ang specifically — it's the getattr(handle, "...", None) → silently skip idiom, which turns any upstream API mismatch into a silent no-op. Audited every getattr-guarded Genesis call in src/ + examples/ against the installed Genesis 1.2:

Verdict Sites
✅ Exist upstream, working all DR setters (set_dofs_kp/kv, set_dofs_frictionloss, set_dofs_armature, set_dofs_force_range, set_friction_ratio, set_mass_shift), sensor getters (get_contacts, get_links_net_contact_force, get_links_inertial_mass, get_dofs_force, get_dofs_control_force), RigidSolver.set_gravity, set_pos/set_quat
⚠️ Dead fallback arms, harmless set_dofs_friction, set_dofs_position_target — only the second arm of or-chains whose first arm exists
❌ Live silent no-op, fixed teleop HUD: outer Viewer forwards register_keybinds but not set_message_text → HUD text never displayed; now falls back to the inner _pyrender_viewer

Also added tests/test_genesis_api_contract.py: pins every getattr-guarded method name against the installed Genesis (import-only, runs on headless CI). A future Genesis bump that renames any of these seams now fails tests instead of silently disabling physics or UI.

@KraHsu
KraHsu merged commit 2c94cfe into main Jul 10, 2026
4 checks passed
@KraHsu
KraHsu deleted the dev/fix-root-velocity-writes branch July 10, 2026 05:38
KraHsu added a commit that referenced this pull request Jul 10, 2026
fix(entity): write root velocity via free-joint DoFs, not set_vel/set_ang
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: push_by_setting_velocity 对 RigidEntity 静默失效(set_vel/set_ang 不存在)

1 participant