Skip to content

Support OVPhysX in randomize_rigid_body_collider_offsets MDP event - #7569

Merged
kellyguo11 merged 5 commits into
developfrom
antoiner/fix-ovphysx-collider-offsets
Sep 5, 2026
Merged

Support OVPhysX in randomize_rigid_body_collider_offsets MDP event#7569
kellyguo11 merged 5 commits into
developfrom
antoiner/fix-ovphysx-collider-offsets

Conversation

@AntoineRichard

@AntoineRichard AntoineRichard commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Description

Stacked on #7563. This branch needs the REST_OFFSET / CONTACT_OFFSET / RIGID_BODY_*_OFFSET aliases and the CPU-only routing for those tensor types that #7563 adds. Review/merge that first; this diff collapses to a single commit once it lands, at which point the base should be retargeted to develop.

randomize_rigid_body_collider_offsets had no OVPhysX implementation. Its backend dispatch tested only for "newton" and fell through a bare else to _RandomizeRigidBodyColliderOffsetsPhysx, which calls get_rest_offsets / get_contact_offsets / set_rest_offsets / set_contact_offsets on asset.root_view. On OVPhysX that view is an OvPhysxView, which defines none of them, so adding the term to a config raised AttributeError during OvPhysxManager.reset() (via PHYSICS_READY) and the environment never built. The error surfaced from inside the PhysX implementation, so it did not name the unsupported backend either.

Found by the OVQA agent harness on Isaac-Cartpole (release/3.0.0, ovphysx 0.5.11). No shipped task uses the term today, so this is latent rather than a live regression.

Fix

  • New _RandomizeRigidBodyColliderOffsetsOvPhysx, mirroring the PhysX variant. OVPhysX runs the PhysX solver, so rest/contact offsets are written directly, per collision shape, through the asset's OvPhysxView: REST_OFFSET / CONTACT_OFFSET for articulations, RIGID_BODY_REST_OFFSET / RIGID_BODY_CONTACT_OFFSET for rigid objects. Both bindings are CPU-resident [N, S] buffers, so the full tensor is read-modify-written on the host with the selected envs as write indices.
  • Dispatch now matches randomize_rigid_body_material in the same file: ovphysxmanager first (it contains the substring physx), then Newton, then PhysX, and a ValueError naming the manager for anything else instead of silently selecting PhysX.
  • Docstring lists OVPhysX as a supported backend.

Note on write order

PhysX enforces restOffset < contactOffset and on OVPhysX a violating setRestOffset is only logged, not raised. The term writes rest before contact, same as the PhysX variant, so raising both above a small authored contact offset can silently skip the rest write. Kept for PhysX parity; flagging in case we want to reorder in both backends.

Verification

New source/isaaclab_ov/test/test_randomize_rigid_body_collider_offsets_mdp.py drives the public term (stubbed cfg / env / asset_cfg) against a real OVPhysX RigidObject and Articulation, so the dispatch itself is covered. It reproduced the reported AttributeError before the fix. Assertions: selected envs land in the sampled range, unselected envs are untouched, and omitting one distribution leaves that offset alone. Passes on cuda:0 and cpu (separate processes, ovphysx device lock). PhysX and Newton paths are unchanged.

Dependencies: #7563.

Fixes # (no tracking issue; reported by the OVQA agent harness)

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Release backport

  • Backport this pull request to the active release branch after it merges into develop

Screenshots

Not applicable: no visual change.

Checklist

Docker and GPU tests run on demand. Push the commits you want tested, then
comment run-ci on the pull request.

  • 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
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump extension.toml — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

_CPU_ONLY_TYPES omitted eight tensor types that are CPU-resident even on a
GPU simulation: the articulation and rigid-body collision-shape contact and
rest offsets, both gravity-disable flags, and the DOF drive type and drive
model.

Because _native_device consults this set, it returned the simulation device
for host-resident data. Every access staged a hidden host-to-device copy on a
path the view believed was device-native, and _check_device rejected a buffer
placed on the host, where the data actually lives, with DeviceMismatch.

Residency was measured rather than assumed: ovphysx exposes no residency
query, so each type was classified by counting CUDA memcpys around a binding
read into a host buffer and into a device buffer, under the DirectGPU
configuration isaaclab_ov itself sets. All eight measured CPU-resident across
every GPU sample scene in the ovphysx wheel, and all previously classified
members measured as declared.

The guarding test compared the view's derived set against the canonical set it
is derived from, so it could not fail for any contents. It now asserts against
an independent inventory of measured residency, mirroring the existing
_EXPECTED_READ_ONLY_NAMES pattern, so an incomplete set is caught.
ovphysx documents ARTICULATION_DOF_DRIVE_TYPE as read-only, but the attribute
was missing from _READ_ONLY_NAMES, so set_attribute accepted writes to it and
forwarded them to the binding instead of raising.

An audit of the whole classification against the wheel's type table found this
to be the only gap: of the twenty-one types ovphysx documents as read-only,
twenty were already classified, and no member was misclassified.

This is a behavior change. Writes to articulation_dof_drive_type that were
previously accepted now raise OvPhysxView.ReadOnlyAttribute. Drive type is
authored through the USD drive schema, not the tensor path.

The existing read-only behavior test is parameterized over the expected
inventory, so adding the name there also asserts that a write raises and
leaves no binding behind.
The eight types added to the CPU-only classification were referenced through
the raw ``_TT`` enum, leaving the candidate tuple as a mix of module aliases
and raw enum members and giving a future reader no reason why these eight were
different.

This module is the alias layer over the ovphysx enum, so a type worth
classifying is worth naming. Each alias carries the shape, dtype and units
taken from the wheel's own type table, which the raw references did not.

Naming follows the established convention: the ``ARTICULATION_`` prefix is
dropped for articulation types, as with DOF_STIFFNESS and BODY_MASS, and
retained for rigid-body ones, as with RIGID_BODY_MASS.
The term's backend dispatch tested only for Newton and fell through to
the PhysX implementation on every other manager. On OVPhysX the asset's
root_view is an OvPhysxView, which has none of the PhysX offset
accessors, so adding the term to an environment config raised
AttributeError from OvPhysxManager.reset() and the environment never
built.

Add an OVPhysX implementation that writes rest and contact offsets per
collision shape through the asset's OvPhysxView, selecting the
articulation or rigid-body offset tensor types by asset class. Match
the dispatch of randomize_rigid_body_material: check ovphysxmanager
first, then Newton, then PhysX, and raise a ValueError naming the
backend for anything else instead of silently selecting PhysX.

Cover the public term on a real OVPhysX RigidObject and Articulation so
the dispatch itself is exercised.
@github-actions github-actions Bot added bug Something isn't working isaac-lab Related to Isaac Lab team labels Sep 4, 2026
@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds OVPhysX support to rigid-body collider-offset randomization and replaces implicit backend fallback with explicit dispatch.

  • Adds an OVPhysX implementation using backend-specific per-shape tensor attributes.
  • Routes OVPhysX, Newton, and PhysX managers explicitly and rejects unsupported managers.
  • Adds real-backend tests for rigid objects and articulations on CPU and CUDA.
  • Adds changelog fragments for the affected packages.

Confidence Score: 5/5

The PR appears safe to merge with no actionable correctness or security issues identified.

The backend dispatch now selects a dedicated OVPhysX implementation, and the added tests cover rigid-object and articulation writes for selected and all environments across CPU and CUDA configurations.

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/envs/mdp/events.py Adds OVPhysX collider-offset handling and explicit backend selection while retaining the existing PhysX and Newton implementations.
source/isaaclab_ov/test/test_randomize_rigid_body_collider_offsets_mdp.py Exercises public-term dispatch and selected/all-environment offset writes for real OVPhysX rigid objects and articulations on CPU and CUDA.
source/isaaclab/changelog.d/antoiner-fix-ovphysx-collider-offsets.minor.rst Documents OVPhysX collider-offset support and explicit unsupported-backend errors.
source/isaaclab_ov/changelog.d/antoiner-fix-ovphysx-collider-offsets.skip Marks the OVPhysX package change as test-only for changelog purposes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[randomize_rigid_body_collider_offsets] --> B{Physics manager}
    B -->|ovphysxmanager| C[OVPhysX implementation]
    B -->|contains newton| D[Newton implementation]
    B -->|contains physx| E[PhysX implementation]
    B -->|other| F[Raise ValueError]
    C --> G[Read and write per-shape offset attributes]
    D --> H[Map offsets to Newton geometry properties]
    E --> I[Use PhysX root-view offset accessors]
Loading

Reviews (1): Last reviewed commit: "Support OVPhysX in randomize_rigid_body_..." | Re-trigger Greptile

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

The OVPhysX backend and explicit dispatch extend randomize_rigid_body_collider_offsets as intended, but the new implementation can silently fail to apply a valid rest/contact target pair because it always writes the rest offset first.

  • Design and architecture: The backend-specific class follows the existing dispatch and implementation pattern. The remaining concern is confined to OVPhysX write sequencing rather than the overall backend separation.
  • API: The public term signature and existing PhysX/Newton paths remain unchanged, and OVPhysX support is documented. However, callers cannot rely on both requested offsets being applied when the target rest offset exceeds the currently authored contact offset, even if the final sampled pair is valid.
  • Implementation: The CPU tensor routing, articulation-versus-rigid-object tensor selection, indexed full-buffer writes, and public-path tests support the implementation. The rest offset is nevertheless written before the contact offset; OVPhysX only logs rejection when the intermediate state violates rest < contact, so the rest write can be silently dropped. The writes should be sequenced according to current and target values so valid final pairs are applied reliably.

Minor fixes needed. Posted 1 actionable finding inline.

Automated review; human maintainers own approval decisions.

distribution=distribution,
)
# the wheel requires a full-shaped source buffer even for indexed writes
self.asset.root_view.set_attribute(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Suggestion · Implementation — Rest offset written before contact offset

This new path writes the sampled rest offset before the contact offset. As the added test comment records, PhysX requires rest < contact and OVPhysX only logs a violating setRestOffset, so raising both above a small authored contact offset silently drops the rest write while contact succeeds, leaving a stale rest offset with no error. Sequencing the two writes based on current and target values (or writing contact first when it increases) would make every valid target pair land.

Base automatically changed from antoiner/fix-ovphysx-cpu-only-types to develop September 4, 2026 22:10
@kellyguo11
kellyguo11 requested a review from a team September 4, 2026 22:10
@kellyguo11

Copy link
Copy Markdown
Contributor

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 4, 2026
@kellyguo11
kellyguo11 merged commit 1b182e7 into develop Sep 5, 2026
51 of 53 checks passed
@kellyguo11
kellyguo11 deleted the antoiner/fix-ovphysx-collider-offsets branch September 5, 2026 01:42
@isaaclab-bot

isaaclab-bot Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Backported to release/3.0.0 as a31ae1a.

isaaclab-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…7569)

# Description

> **Stacked on #7563.** This branch needs the `REST_OFFSET` /
`CONTACT_OFFSET` / `RIGID_BODY_*_OFFSET` aliases and the CPU-only
routing for those tensor types that #7563 adds. Review/merge that first;
this diff collapses to a single commit once it lands, at which point the
base should be retargeted to `develop`.

`randomize_rigid_body_collider_offsets` had no OVPhysX implementation.
Its backend dispatch tested only for `"newton"` and fell through a bare
`else` to `_RandomizeRigidBodyColliderOffsetsPhysx`, which calls
`get_rest_offsets` / `get_contact_offsets` / `set_rest_offsets` /
`set_contact_offsets` on `asset.root_view`. On OVPhysX that view is an
`OvPhysxView`, which defines none of them, so adding the term to a
config raised `AttributeError` during `OvPhysxManager.reset()` (via
`PHYSICS_READY`) and the environment never built. The error surfaced
from inside the PhysX implementation, so it did not name the unsupported
backend either.

Found by the OVQA agent harness on Isaac-Cartpole (release/3.0.0,
ovphysx 0.5.11). No shipped task uses the term today, so this is latent
rather than a live regression.

**Fix**

- New `_RandomizeRigidBodyColliderOffsetsOvPhysx`, mirroring the PhysX
variant. OVPhysX runs the PhysX solver, so rest/contact offsets are
written directly, per collision shape, through the asset's
`OvPhysxView`: `REST_OFFSET` / `CONTACT_OFFSET` for articulations,
`RIGID_BODY_REST_OFFSET` / `RIGID_BODY_CONTACT_OFFSET` for rigid
objects. Both bindings are CPU-resident `[N, S]` buffers, so the full
tensor is read-modify-written on the host with the selected envs as
write indices.
- Dispatch now matches `randomize_rigid_body_material` in the same file:
`ovphysxmanager` first (it contains the substring `physx`), then Newton,
then PhysX, and a `ValueError` naming the manager for anything else
instead of silently selecting PhysX.
- Docstring lists OVPhysX as a supported backend.

**Note on write order**

PhysX enforces `restOffset < contactOffset` and on OVPhysX a violating
`setRestOffset` is only logged, not raised. The term writes rest before
contact, same as the PhysX variant, so raising both above a small
authored contact offset can silently skip the rest write. Kept for PhysX
parity; flagging in case we want to reorder in both backends.

**Verification**

New
`source/isaaclab_ov/test/test_randomize_rigid_body_collider_offsets_mdp.py`
drives the public term (stubbed `cfg` / `env` / `asset_cfg`) against a
real OVPhysX `RigidObject` and `Articulation`, so the dispatch itself is
covered. It reproduced the reported `AttributeError` before the fix.
Assertions: selected envs land in the sampled range, unselected envs are
untouched, and omitting one distribution leaves that offset alone.
Passes on `cuda:0` and `cpu` (separate processes, ovphysx device lock).
PhysX and Newton paths are unchanged.

Dependencies: #7563.

Fixes # (no tracking issue; reported by the OVQA agent harness)

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Screenshots

Not applicable: no visual change.

## Checklist

Docker and GPU tests run on demand. Push the commits you want tested,
then
comment `run-ci` on the pull request.

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package (do **not** edit
`CHANGELOG.rst` or bump `extension.toml` — CI handles that)
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

---------

Co-authored-by: Kelly Guo <kellyg@nvidia.com>

(cherry picked from commit 1b182e7)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants