Skip to content

[OVPHYSX] Articulation rewrite (data class + asset class + kernels)#10

Draft
AntoineRichard wants to merge 1 commit intoantoiner/feat/ovphysx_rigidobjectfrom
antoiner/feat/ovphysx_articulation
Draft

[OVPHYSX] Articulation rewrite (data class + asset class + kernels)#10
AntoineRichard wants to merge 1 commit intoantoiner/feat/ovphysx_rigidobjectfrom
antoiner/feat/ovphysx_articulation

Conversation

@AntoineRichard
Copy link
Copy Markdown
Owner

Description

Drastic rewrite of OVPhysX Articulation and ArticulationData so they follow the same shape as the post-refactor OVPhysX RigidObject (PR isaac-sim#5426 on isaac-sim/IsaacLab), with the API surface mirroring Newton Articulation and behavior parity with PhysX Articulation. Single-PR atomic rewrite, clean break (no deprecation aliases for OVPhysX-introduced renames; framework-inherited deprecated shims kept).

The OVPhysX articulation diverged significantly from the rest of the framework conventions. This PR brings it back in line: same docstring template, same section ordering, same naming, same internal patterns, same lifecycle.

This PR is stacked on the rigid-object refactor (antoiner/feat/ovphysx_rigidobject, isaac-sim PR isaac-sim#5426). Once isaac-sim#5426 merges to develop, the upstream PR for this work will be retargeted to develop.

Status: draft. Implementation is complete (all writers, setters, properties, lifecycle, actuator pipeline); the verbatim PhysX test mirror that already lives in tree (test_articulation.py, ~210 parametrizations) currently shows 104 failures from a single root-cause bug — _binding_read(TT.BODY_COM_POSE, ...) during _initialize_impl is not routing through pinned-host staging despite the type being in _CPU_ONLY_TYPES. Iterating on that bug + remaining triage in a fresh-context follow-up session.

Fixes # (none — internal refactor; no associated issue)

Design references

  • Spec: docs/superpowers/specs/2026-04-30-ovphysx-articulation-rewrite-design.md (gitignored, local).
  • Plan: docs/superpowers/plans/2026-04-30-ovphysx-articulation-rewrite-plan.md (gitignored, local).
  • Test contract: source/isaaclab_ovphysx/test/assets/test_articulation.py is a verbatim 1-to-1 mirror of isaaclab_physx.test.assets.test_articulation (~210 parametrizations) — landed in the rigid-object PR [OVPHYSX] RigidObject + RigidObjectData asset isaac-sim/IsaacLab#5426. The _ovphysx_session_patches and _ovphysx_skip_other_device autouse fixtures bridge the kitless invocation gap (see the rigid-object test header).

Architectural changes

OVPhysX RigidObject is the design template. It has navigated the hybrid OVPhysX surface — Newton-style mask+index dual API + PhysX-style CPU-only bindings via pinned-host staging à la isaac-sim#5329 + pull-to-refresh binding.read(target):

  • Eager TimestampedBufferWarp allocation in _create_buffers (single source of truth — no _invalidate_caches / _ensure_*_buffers / _ensure_root_buffers machinery).
  • Pinned-host CPU staging buffers for every CPU-only binding (mass, COM, inertia, all DOF properties, tendon properties).
  • _binding_read / _binding_write / _stage_to_pinned_cpu helpers route CPU-only types through pinned-host memory.
  • Every public property returns a ProxyArray (warp + torch dual view); raw wp.array for one-shot config buffers.
  • Counts and names (num_instances, num_bodies, num_joints, body_names, joint_names, ...) demoted from @property to plain instance attributes.
  • Dual mask+index API on every writer/setter (*_index accepts partial data; *_mask accepts full data with a wp.bool mask).
  • All write_* / set_* parameters are kwarg-only after *,. No positional. No full_data flag anywhere.
  • The deprecated _write_body_state plumbing layer is removed; deprecated state-writer shims (write_root_state_to_sim, etc.) call the public write_*_to_sim_index methods directly, mirroring RigidObject.

Articulation-specific surface mirrors Newton 1-to-1: joint-state writers, joint-property writers (CPU-only), body-property setters (multi-body shape), joint-command target setters, external-wrench setters via WrenchComposer, fixed/spatial tendon setters, deprecated state-writer shims, full actuator pipeline (compute, _apply_actuator_model, _process_actuators_cfg).

Files changed

  • source/isaaclab_ovphysx/isaaclab_ovphysx/assets/articulation/articulation.py — full rewrite (~3863 lines, matches Newton).
  • source/isaaclab_ovphysx/isaaclab_ovphysx/assets/articulation/articulation_data.py — full rewrite (~2504 lines).
  • source/isaaclab_ovphysx/isaaclab_ovphysx/assets/kernels.py — gained 6 articulation kernels migrated from the stop-gap kernels_old.py (now deleted): _compose_root_com_pose, _compute_heading, _copy_first_body, _projected_gravity, _world_vel_to_body_ang, _world_vel_to_body_lin. Plus 2 new joint-property kernels (write_joint_position_limit_to_buffer_index/mask for trailing-dim-2 limits, write_joint_friction_to_buffer_index/mask for the broadcast-coefficient pattern).
  • source/isaaclab_ovphysx/isaaclab_ovphysx/assets/kernels_old.py — deleted.

Type of change

  • Breaking change (existing functionality will not work without user modification — OVPhysX is at 0.2.x, clean break is acceptable per semver-on-0.x; no deprecation aliases for OVPhysX-introduced renames).
  • Code modernization / refactor.

Validation

Verifications happen in three layers (Tasks 16-19 of the implementation plan, deferred to fresh-context follow-up):

  1. Real-backend porttest_articulation.py (already in tree, verbatim PhysX mirror). Run on GPU and CPU separately via ./scripts/run_ovphysx.sh -m pytest <path> -k 'cuda:0' and ... -k 'cpu' (the wheel's process-global device-mode lock makes a single invocation lock to one device). Expected end state: each pass shows <X> passed, <Y> xfailed, 0 failed. Y is bounded by the wheel-gaps spec; every xfail carries a reason pointing at the spec entry.

  2. Cross-backend interfacesource/isaaclab/test/assets/test_articulation_iface.py will gain an ovphysx backend, mirroring the rigid-object iface treatment from [OVPHYSX] RigidObject + RigidObjectData asset isaac-sim/IsaacLab#5426 (commit b340a551f6c). Run on both devices.

  3. API consistency audit — per-method side-by-side checklist comparing Newton, RigidObject (post-refactor), and the rewritten Articulation; verifies method name, kwarg-only signature, parameter order, return type, docstring template (one-liner → .. note::.. tip::Args:), section-header placement.

Outstanding

  • GPU/CPU triage (Tasks 16-17 of the plan): the verbatim PhysX test mirror currently shows 104 failures on GPU. Dominant root cause: _binding_read(TT.BODY_COM_POSE, ...) during _initialize_impl does not route through pinned-host staging despite BODY_COM_POSE being in TT._CPU_ONLY_TYPES. Likely a single bug in the read path; fix unblocks ~80% of failures.
  • Iface extension (Task 18): pending real-backend green.
  • API audit (Task 19): pending real-backend green.
  • CHANGELOG + version bump (Task 20): pending all of the above; planned bump 0.2.x0.3.0.

Type of change

  • Breaking change (existing functionality will not work without user modification)
  • Code modernization

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works (the verbatim PhysX test mirror is the contract; bug-fixing in progress)
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file (Task 20)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_articulation branch 2 times, most recently from 394ade8 to f72c5f4 Compare May 5, 2026 14:58
@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_rigidobject branch from 2b8cc8d to 26a442b Compare May 5, 2026 15:17
Add Articulation and ArticulationData for the OVPhysX backend, mirroring
the PhysX/Newton public API. Resolves PR isaac-sim#5459.

Articulation
^^^^^^^^^^^^

* index/mask split for every state writer, simulation-parameter writer,
  setter, and tendon setter; OVPhysX exposes both _index and _mask as
  first-class paths and intentionally drops the PhysX-specific
  ``full_data`` kwarg.
* Dedicated dynamic + viscous friction setters
  (write_joint_{dynamic,viscous}_friction_coefficient_to_sim_{index,mask})
  that touch only their slot of the combined (N, J, 3)
  DOF_FRICTION_PROPERTIES buffer.  The combined
  write_joint_friction_coefficient_to_sim_index/_mask still accepts all
  three components as kwargs (Coulomb static + dynamic + optional
  viscous) for source-compatible PhysX call sites.
* Deprecated non-indexed shorthand shims for friction (x3) and root /
  joint state (x4), forwarding to the index variants with a
  DeprecationWarning, matching PhysX's deprecated section.
* Wrench-composer return types tightened to non-None
  (instantaneous_wrench_composer / permanent_wrench_composer);
  composers are always set in _create_buffers, mirroring PhysX/Newton.
* Section organisation matches PhysX exactly: Properties -> Operations
  -> Operations - Finders -> Operations - State Writers -> Operations
  - Simulation Parameters Writers -> Operations - Setters -> Operations
  - Tendons -> Internal helper -> Internal simulation callbacks ->
  Internal helpers -- Actuators -> Internal helpers -- Debugging ->
  Deprecated methods.  Section delimiters use bare """Section."""
  docstring blocks (Newton/PhysX convention).

ArticulationData
^^^^^^^^^^^^^^^^

* Pull-on-demand timestamped buffers; CPU-only bindings route through
  pinned-host staging (PR isaac-sim#5329 pattern).
* Property names match PhysX exactly: joint_friction_coeff,
  joint_dynamic_friction_coeff, joint_viscous_friction_coeff (no
  *_static / *_dynamic / *_viscous renames).
* SI units annotated on every public property docstring
  ([m or rad, depending on joint type], [m/s or rad/s, ...], [N*m],
  [kg], etc.) per AGENTS.md.
* binding_getter parameter on __init__ typed as
  Callable[[int], Any] | None.
* Section organisation matches PhysX (Defaults -> Joint commands ->
  Joint properties -> Fixed tendon -> Spatial tendon -> Root state ->
  Body state -> Joint state -> Derived -> Sliced -> Internal helpers ->
  Deprecated properties).

Kernels
^^^^^^^

* Articulation-specific kernels in
  isaaclab_ovphysx/assets/articulation/kernels.py (soft-limit clamp,
  friction-data writer, finite-difference joint-acc helper, body-CoM
  pose composer); shared kernels promoted to
  isaaclab_ovphysx/assets/kernels.py.
* Per-kernel docstrings document purpose, shape/dtype/SI units, and
  divergence notes where the OVPhysX implementation differs (e.g.
  _fd_joint_acc takes inv_dt rather than dt to avoid per-element
  division).

Tests
^^^^^

* Real-backend test_articulation.py mirrors isaaclab_physx 1-to-1
  under run_ovphysx.sh; 99 tests pass on each of CPU + CUDA.
* test_articulation_helpers.py covers the kitless-only helpers
  (tendon scoping, mock binding shapes).
* Cross-backend test_articulation_iface.py runs the OVPhysX path:
  544 tests pass, 16 skipped, 0 failed on each of CPU + CUDA.  Brings
  the iface helper up to the actual ArticulationData constructor
  signature and broadcasts scalar inputs across joint / fixed-tendon
  / spatial-tendon mask setters that previously rejected them.

OVPhysX-only surface dropped
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* Articulation: set_external_force_and_torque_{index,mask} (use
  instantaneous_wrench_composer.add_forces_and_torques_*),
  set_spatial_tendon_limit_{index,mask}, and
  set_spatial_tendon_rest_length_{index,mask} (NotImplementedError
  stubs PhysX never had).
* ArticulationData: body_pose_w / body_lin_vel_w / body_ang_vel_w /
  body_acc_w / body_link_acc_w (base class provides matching
  defaults), body_inv_mass / body_inv_inertia, fixed_tendon_limit
  (PhysX exposes only fixed_tendon_pos_limits), spatial_tendon_limit /
  spatial_tendon_rest_length (no PhysX equivalent).
@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_articulation branch from f72c5f4 to 7a12614 Compare May 5, 2026 17:37
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.

1 participant