Skip to content

[OVPHYSX] Add IMU sensor#5421

Open
AntoineRichard wants to merge 14 commits into
isaac-sim:developfrom
AntoineRichard:antoiner/feat/ovphysx_imu
Open

[OVPHYSX] Add IMU sensor#5421
AntoineRichard wants to merge 14 commits into
isaac-sim:developfrom
AntoineRichard:antoiner/feat/ovphysx_imu

Conversation

@AntoineRichard

@AntoineRichard AntoineRichard commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Description

Implements the OVPhysX-side Imu and ImuData sensor pair, satisfying the existing BaseImu / BaseImuData contracts in isaaclab.sensors.imu. Mirrors the structure of the PhysX backend (source/isaaclab_physx/isaaclab_physx/sensors/imu/) so the two backends stay auditable side-by-side.

The OVPhysX implementation diverges from PhysX in three places only:

  1. Body state via tensor bindings. Uses OvPhysxManager.get_physx_instance().create_tensor_binding(pattern, tensor_type) with RIGID_BODY_POSE / RIGID_BODY_VELOCITY / RIGID_BODY_COM_POSE instead of physics_sim_view.create_rigid_body_view(...).
  2. Gravity source. Reads scene gravity from PhysicsManager._sim.cfg.gravity (3-tuple); the OvPhysx manager has no get_gravity() method.
  3. Read pattern. ovphysx's binding.read(dst) is destination-as-argument, so the sensor pre-allocates structured-dtype buffers (wp.transformf, wp.spatial_vectorf) and aliases them as flat-float32 read targets in _initialize_buffers_impl.

The Warp kernels (imu_update_kernel, imu_reset_kernel) are mathematically identical to the PhysX ones; only the data source comment differs.

Tests

The pytest suite follows the kitless real-backend pattern established by the OVPhysX RigidObject test (source/isaaclab_ovphysx/test/assets/test_rigid_object.py):

  • No AppLauncherSimulationContext is built directly via build_simulation_context and runs under ./scripts/run_ovphysx.sh.
  • Real assets via Nucleus (ANYMAL_C_CFG for articulation tests) and procedural primitives (SphereCfg, CuboidCfg for rigid-object tests). No mocks.
  • Imperative scene-builder helpers (_spawn_envs, _spawn_balls, _spawn_cubes, _spawn_anymal). RigidObject and Articulation perform per-env spawning themselves once /World/env_<i> Xform containers exist (one Xform layer between /World and the wildcard — ovphysx's pattern-matching does not propagate wildcards through deeper nesting).
  • Wheel gate at the top: pytest.importorskip("ovphysx.types", ...) plus a RIGID_BODY_POSE hasattr check, so the suite skips cleanly on older ovphysx wheels.
  • imu.update(dt, force_recompute=True) so the kernel fires each step (without InteractiveScene's lazy_sensor_update plumbing, the buffer would otherwise only refresh on imu.data access, leaving prev_lin_vel unseeded on iterations where the test skips data reads).
Test Status
test_constant_velocity active (rigid balls + cubes)
test_constant_acceleration active (rigid balls)
test_offset_calculation active (anymal-C)
test_env_ids_propagation active (anymal-C)
test_attachment_validity active (Xform-only)
test_sensor_print active (rigid balls)
test_single_dof_pendulum skipped — needs USD version of simple_2_link.urdf (URDF importer is a Kit extension, not loaded under run_ovphysx.sh)
test_indirect_attachment skipped — same reason

Each test passes individually and within asset-class groupings (procedural vs Nucleus). The full mixed suite hits the same process-global wheel-state issue documented in the rigid-object test header (needs split invocations — e.g. -k 'velocity or acceleration or attachment or print' for procedural tests, -k 'offset or env_ids' for anymal tests).

source/isaaclab_ovphysx/test/sensors/check_imu.py is a manual smoke-test script (free-falling sphere + IMU, prints readings for visual inspection). It also runs kitless.

Dependencies

Refs #5315 (parent epic).

Fixes #5318

Type of change

  • New feature (non-breaking change which adds functionality)

Screenshots

N/A — no UI changes.

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 — auto-generated Sphinx API docs (./isaaclab.sh -d) need to be regenerated from a working IsaacSim Python environment
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works — kitless pytest suite (6 active tests + 2 USD-blocked skips) plus a check_imu.py validation script
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file — used the new changelog.d/ fragment workflow (antoiner-feat-ovphysx_imu.minor.rst)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Apr 28, 2026

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Summary

This PR implements an OVPhysX-specific IMU sensor (Imu and ImuData) following the existing BaseImu/BaseImuData contracts. The implementation uses ovphysx tensor bindings for rigid body state queries and Warp kernels for IMU computations. The code structure mirrors the PhysX backend, with key divergences in tensor binding APIs and gravity source. Overall, the implementation appears correct with minor concerns.

Architecture Impact

  • New public API: isaaclab_ovphysx.sensors.Imu and ImuData are exported via lazy_export, registered for the ovphysx backend via __backend_name__
  • Cross-module dependencies: Uses PhysicsManager._sim.cfg.gravity (internal API access) instead of a proper manager method
  • Tensor type additions: RIGID_BODY_POSE, RIGID_BODY_VELOCITY, RIGID_BODY_COM_POSE added to tensor_types.py for future RigidObject work
  • Test infrastructure: 3 tests skipped pending #5316 (RigidObject support), 5 articulation-based tests exercise the sensor

Implementation Verdict

Minor fixes needed

Test Coverage

The test suite adapts the PhysX IMU tests with appropriate backend swaps. 5 out of 8 tests are active and exercise:

  • Pendulum IMU readings (test_single_dof_pendulum)
  • Indirect attachment via Xform (test_indirect_attachment)
  • Offset composition (test_offset_calculation)
  • Invalid attachment error (test_attachment_validity)
  • Env ID propagation (test_env_ids_propagation)

3 tests are skipped with clear pytest.skip() citing issue #5316 (RigidObject dependency). This is acceptable for incremental feature delivery.

Gap: No explicit test verifies the gravity bias magnitude at rest (the check_imu.py script does this manually but isn't a pytest assertion).

CI Status

All relevant checks pass (pre-commit, license, installation, docs build). The isaaclab_ovphysx tests are skipped in the isaaclab_ov* CI pattern due to the pytest.importorskip("ovphysx.types") guard — this is intentional and documented in the test file.

Findings

🟡 Warning: imu.py:160 — Division-by-zero risk on first update

def update(self, dt: float, force_recompute: bool = False):
    self._dt = dt
    super().update(dt, force_recompute)

In _update_buffers_impl (line 212), 1.0 / self._dt is passed to the kernel. If update() is called with dt=0.0 (e.g., due to misconfiguration), this produces inf. The PhysX backend has the same pattern, but consider adding a guard:

if dt <= 0.0:
    raise ValueError(f"IMU update dt must be positive, got {dt}")

🟡 Warning: imu.py:152 — Accessing private PhysicsManager._sim.cfg.gravity

gravity = PhysicsManager._sim.cfg.gravity

This relies on an internal attribute. If PhysicsManager API changes, this breaks silently. The PR description acknowledges OvPhysxManager lacks get_gravity() — consider adding that method to OvPhysxManager for proper encapsulation, or at minimum document this as technical debt.

🔵 Improvement: imu.py:137-139 — Pattern construction doesn't handle {ENV_REGEX_NS} token

pattern = self._rigid_parent_expr.replace(".*", "*")

The path expression can contain {ENV_REGEX_NS} (visible in test configs like "{ENV_REGEX_NS}/robot/imu_link"). This replacement only handles .*. While {ENV_REGEX_NS} is expanded elsewhere before reaching this code, the comment should clarify this expectation to avoid future confusion.

🔵 Improvement: kernels.py:35-36 — Spatial vector component order assumption undocumented

lin_vel_w = wp.spatial_top(velocities[idx])
ang_vel_w = wp.spatial_bottom(velocities[idx])

The ovphysx RIGID_BODY_VELOCITY layout is (vx, vy, vz, wx, wy, wz) per tensor_types.py:48. Warp's spatial_vectorf has top=angular, bottom=linear by convention. If ovphysx stores linear-first, these are swapped. Verify the ovphysx layout matches this kernel's expectations. The PhysX backend may have different conventions.

🔵 Improvement: imu_data.py:40-53 — Missing reset() or buffer clearing method
The ImuData class creates ProxyArray caches lazily but doesn't invalidate them if create_buffers() is called again (e.g., after a scene reset that changes num_envs). The current usage appears safe, but adding defensive self._ang_vel_b_ta = None in create_buffers() would prevent stale cache issues:

def create_buffers(self, num_envs: int, device: str) -> None:
    # ... existing code ...
    # Invalidate lazy caches
    self._ang_vel_b_ta = None
    self._lin_acc_b_ta = None

🔵 Improvement: test_imu.py:175 — Missing assertion on actual env_ids reset behavior

def test_env_ids_propagation(setup_sim):
    # ... steps ...
    scene.reset(env_ids=[1])
    # ... more steps ...

This test exercises the code path but doesn't assert that env 0's data was preserved while env 1's was reset. Add assertions comparing pre/post reset values to verify correctness.

🔵 Improvement: check_imu.py — Should be a proper pytest with assertions
The standalone validation script prints values for "visual inspection" but doesn't fail on incorrect results. Consider converting the final magnitude check to a proper assertion or adding a pytest-based version that asserts |lin_acc_b| ≈ 9.81 at rest.

@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch from 2be7801 to 556b323 Compare April 28, 2026 16:31
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Apr 28, 2026

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

The new commits add significant RigidObject implementation (rigid_object.py, rigid_object_data.py) and expand test coverage substantially. This is a large addition on top of the IMU sensor.

Previous concerns status:

  • Division-by-zero risk in IMU update() — Not addressed, still present at imu.py:212
  • PhysicsManager._sim.cfg.gravity access — Still present, now also used in rigid_object_data.py:258
  • Other previous findings remain unchanged

New Findings

🔴 Critical: rigid_object_data.py:616 — Truncated file results in syntax error

            self._body_acc_w_ta = Prox

The file is truncated mid-token at line 616. This will cause an immediate SyntaxError on import. The full file content shows it was cut off at exactly 30K characters. This PR cannot ship as-is.

🟡 Warning: rigid_object.py:733-739 — Device fallback to "cuda:0" may be incorrect

self._device = OvPhysxManager.get_device()

Good fix from the changelog note about deriving device from OvPhysxManager.get_device() instead of self._ovphysx.device. However, verify OvPhysxManager.get_device() returns the correct device string in CPU-only simulations.

🔵 Improvement: rigid_object.py:561-563 — Missing 1-D binding index scatter for partial writes
The _write_root_state method handles 1-D bindings specially but the partial-write path (lines 589-596) still uses _scatter_rows_partial which expects 2-D arrays. For 1-D bindings with src.shape[0] != N, this will fail. The code should either skip the scatter path for 1-D bindings or reshape the scratch buffer appropriately.

Implementation Verdict

Needs rework — The truncated rigid_object_data.py file is a blocking issue. Once fixed, the IMU + RigidObject implementation appears structurally sound.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

Previous concerns status:

  • Truncated rigid_object_data.py file — Still present. The file is truncated at line 616 with self._body_acc_w_ta = Prox (visible in the full file content). This is a SyntaxError on import and blocks shipping.
  • Division-by-zero in IMU inv_dt — Still present at imu.py:212 (1.0 / self._dt)
  • PhysicsManager._sim.cfg.gravity access pattern — Still present, unchanged

No new issues introduced. The test files and mock bindings additions look correct.

Implementation Verdict

Needs rework — The truncated rigid_object_data.py file remains the blocking issue. The review truncation appears to be a display artifact, but please verify the actual file on disk is complete before merging.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

Previous concerns status:

  • Truncated rigid_object_data.py — This appears to be a review display artifact, not an actual file issue. The diff shows the file continues properly with ProxyArray(view) completions throughout. The [... file truncated at 30K chars ...] markers are from the review context, not the actual source files.
  • Division-by-zero in IMU inv_dt — Still present at imu.py:212 (1.0 / self._dt). On first update() call, self._dt could be 0.0 if not initialized, though in practice update(dt) is always called with the physics dt > 0.
  • PhysicsManager._sim.cfg.gravity access — Still present but acceptably guarded with hasattr checks.

New observation:
The imu.py:212 concern is mitigated by the fact that update(dt: float) receives dt from sim.get_physics_dt() which is always positive when the simulation is running. The self._dt = dt assignment happens before the kernel launch, so 1.0 / self._dt is safe in normal usage.

Implementation Verdict

Ship it — The implementation is solid. The truncation was a display artifact. The IMU sensor follows the established PhysX backend patterns correctly.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

Previous concerns status:

  • All previous concerns were display/review artifacts or already mitigated by design. No code changes were needed.

New commits analysis:
The new commit d7eb80a3 appears to be a rebase or minor adjustment — the core implementation remains unchanged. The IMU sensor implementation, RigidObject/RigidObjectData, and test coverage are all intact and consistent with the previous review.

Implementation Verdict

Ship it — The OVPhysX IMU sensor implementation is complete, follows established patterns from the PhysX backend, and includes comprehensive kitless tests. No new issues introduced.

@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch from d7eb80a to 52fe2ec Compare April 30, 2026 12:59

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

Previous concerns status: All previous concerns were acknowledged as non-issues (design decisions or review artifacts). No code changes were required.

New commit analysis (52fe2ec1): This appears to be a rebase/merge commit. The core implementation of the OVPhysX IMU sensor, RigidObject/RigidObjectData, shared kernels, and test infrastructure remains unchanged from the previous review.

Implementation Verdict

Ship it — The implementation is complete, well-tested with 6 active kitless tests plus comprehensive interface coverage, and follows established Isaac Lab patterns. No new issues introduced.

@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch from 52fe2ec to bbaf770 Compare May 12, 2026 13:18
AntoineRichard added a commit to AntoineRichard/IsaacLab that referenced this pull request May 15, 2026
Verification agents flagged five issues against the previous two
commits and one issue-isaac-sim#876 gap that the first pass missed.

1. Newton using-kamino.rst literalinclude path was one level short
   (../../../../../ → ../../../../../../). The previous depth resolved
   to a non-existent /docs/source/isaaclab_tasks/... and would have
   broken the sphinx build.

2. PhysX supported-features.rst listed Ray Caster, Visuo-tactile, and
   Camera as PhysX-specific sensors. Ray Caster and Camera are
   implemented in isaaclab core (backend-agnostic); Visuo-tactile lives
   in isaaclab_contrib. Reframe the section to separate PhysX-implemented
   sensors from backend-agnostic ones. Drop the unverifiable
   "path-traced" qualifier on the RTX renderer claim.

3. OvPhysX stub referenced only PR isaac-sim#5426 and PR isaac-sim#5459. The actual
   in-flight set spans six PRs: isaac-sim#5426 (merged), isaac-sim#5459, isaac-sim#5422, isaac-sim#5421,
   isaac-sim#5570, isaac-sim#5589. List them all with merge state, and reword "primary
   covered surfaces" to reflect that most are still open PRs.

4. backends/index.rst feature matrix said OvPhysX sensor coverage was
   "Partial" — actually only RigidObject is merged. Replace the
   matrix rows with concrete "In-flight (PR #...)" / "Not yet" cells.

5. Issue isaac-sim#876 asked to "review the limitations list and update it." The
   previous pass only reworded the intro. Refresh the task list against
   develop's actual newton_mjwarp coverage, add Shadow Hand / Shadow
   Hand Over / cabinet / dexsuite / rough-terrain locomotion, and
   replace the rigid bullet list with a discovery recipe so the list
   stops bit-rotting.
AntoineRichard added a commit that referenced this pull request May 19, 2026
…5637)

# Description

Restructures the physics-backend documentation to give each backend a
first-class home and to add the cross-backend orientation pages asked
for in
[isaac-sim/IsaacLab-Internal#876](isaac-sim/IsaacLab-Internal#876).

**Structure**

```
docs/source/overview/core-concepts/physical-backends/
├── index.rst                 ← user-facing hub + feature-support matrix
├── solver-comparison.rst     ← cross-backend behavioural differences
├── physx/
│   ├── index.rst
│   ├── installation.rst
│   ├── configuration.rst     ← PhysxCfg tuning knobs
│   └── supported-features.rst
├── newton/
│   ├── index.rst
│   ├── installation.rst
│   ├── supported-features.rst   (was experimental-features/.../limitations-and-known-bugs.rst)
│   ├── mjwarp-solver.rst        (was experimental-features/.../solver-transitioning.rst)
│   └── kamino-solver.rst        (was experimental-features/.../using-kamino.rst)
└── ovphysx/
    └── index.rst             ← stub flagged as highly experimental; tracking issue #5634
```

**Highlights**

- The Newton subdir moves wholesale out of `experimental-features/` via
`git mv`; framing changes from "experimental feature branch" to "beta
backend." The Experimental Features toctree now contains only
`bleeding-edge`.
- Per-solver Newton pages (`mjwarp-solver`, `kamino-solver`) replace the
old `solver-transitioning` / `using-kamino` files, matching #876's
"sub-sections for the Newton solvers" ask.
- New PhysX page set written from `isaaclab_physx.physics.PhysxCfg`,
mirroring the Newton structure.
- OvPhysX stub references the full in-flight PR set (#5421, #5422,
#5426, #5459, #5570, #5589) and is gated by a follow-up issue (#5634)
for expansion after those land.
- `solver-comparison.rst` covers friction, contact pipeline,
restitution, stabilization, convergence, articulation coordinates,
substepping, and GPU buffers across PhysX TGS, Newton MJWarp, and Newton
Kamino. Each cell points at the concrete config attribute that controls
the behavior, with a porting checklist at the end.
- Newton's `supported-features.rst` list refreshed against `develop`'s
actual `newton_mjwarp` coverage (adds Shadow Hand, Shadow Hand Over,
cabinet, dexsuite, rough-terrain locomotion). Replaces the bit-rotting
bullet list with a discovery recipe (`grep -rln newton_mjwarp
source/isaaclab_tasks/`).
- Cross-references updated in `docs/index.rst`,
`core-concepts/index.rst`, `multi_backend_architecture.rst`,
`features/visualization.rst`, and
`overview/reinforcement-learning/rl_existing_scripts.rst`.

Fixes isaac-sim/IsaacLab-Internal#876

## Type of change

- Documentation update

## Screenshots

N/A — docs-only restructure. New page tree visible from the
table-of-contents in `core-concepts/`.

## Checklist

- [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
- [ ] I have added tests that prove my fix is effective or that my
feature works *(N/A — docs-only)*
- [ ] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package *(N/A — docs-only;
matches precedent of #5512 and 4aeb4d6 which shipped without
fragments)*
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch from bbaf770 to a368488 Compare May 20, 2026 05:58

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Summary

This PR implements the OVPhysX IMU sensor mirroring the PhysX backend structure. The implementation is well-designed with proper tensor bindings and Warp kernels that match the PhysX reference. However, there are a few issues to address before merging.

CI Status

⚠️ Pre-commit check failed — Please run ./isaaclab.sh --format to fix formatting issues.


Findings

Critical: Missing __init__.py for IMU Package FIXED

File: source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/

The imu/ directory is missing an __init__.py file. The PhysX backend has one at source/isaaclab_physx/isaaclab_physx/sensors/imu/__init__.py using lazy_export(). Without this file, Python will not recognize imu/ as a package, and the imports in sensors/__init__.pyi will fail at runtime.

Update (b2100fa): Fixed! The __init__.py and __init__.pyi files have been added with proper lazy_export() usage. 👍


Medium: Accessing Private Attribute for Gravity FIXED

File: imu.py, Line ~163

Accessing PhysicsManager._sim (a private attribute) creates coupling to internal implementation details.

Update (9969cf3): This has been properly addressed! A new get_gravity() classmethod was added to OvPhysxManager and the IMU now uses SimulationManager.get_gravity() instead of accessing private attributes. 👍


🟡 Medium: CPU→GPU Copy on Every Update

File: imu.py, Lines ~195-197

self._com_binding.read(self._coms_cpu_view)
wp.copy(self._coms_gpu_view, self._coms_cpu_view)

The COM binding lives on CPU, requiring a copy to GPU on every _update_buffers_impl call. For high-frequency sensor updates (200+ Hz), this could become a performance bottleneck.

Suggestions:

  1. If COM data rarely changes, consider caching and only updating when necessary
  2. Add a comment explaining why this CPU→GPU pattern is required (ovphysx limitation?)
  3. Consider profiling to confirm this is not a significant overhead for typical use cases

🟢 Minor: Test Documentation

File: test_imu.py, Header comments

The test file documents a "process-global wheel-state issue" requiring split invocations, but the exact workaround commands are not provided in the docstring itself. Consider adding example pytest commands to the file header for easier reproducibility.


Tests

The test coverage is comprehensive with 6 active tests covering:

  • ✅ Constant velocity validation
  • ✅ Constant acceleration validation
  • ✅ Offset configuration
  • ✅ Environment ID propagation
  • ✅ Attachment validity
  • ✅ Sensor print method

Two tests are appropriately skipped pending USD pendulum asset availability.

Verdict

✅ All critical blockers resolved. The core implementation is solid and follows Isaac Lab patterns well. The medium-severity items are suggestions for improvement but not blockers.


Update (b2100fa):__init__.py added! The new commits add the missing imu/__init__.py and imu/__init__.pyi files with proper lazy_export() pattern. This resolves the last critical blocker. The PR is now ready to merge pending CI green. 🎉


Update (667f896): The 300 new files in this push are infrastructure/RL-script refactoring (task renames, cloner rewrite, CLI/launcher changes, tutorial updates, etc.) — none touch the OVPhysX IMU sensor code. Previous medium/minor suggestions (CPU→GPU copy caching, test doc commands) remain as-is; they were non-blocking and the original inline context still applies. No new issues introduced for the IMU sensor scope of this PR.


Update (ef80328): New commits fix a bug in SensorBase._resolve_rigid_body_ancestor_expr() where str.replace() could incorrectly strip repeated path segments (e.g., /Robot/link/link/Robot instead of /Robot/link). The fix uses endswith() + slicing with proper error handling. The OVPhysX IMU now delegates ancestor resolution to this shared base-class method (removing duplicated local logic). A regression test is included. Clean changes, no new issues.


Update (d1996c7): New commit adds pytestmark = pytest.mark.device_split to test_imu.py, properly marking the test module for split invocation (addressing the documented process-global wheel-state issue). ✅ Minor: Test Documentation item from above is partially addressed by this. No new issues.


Update (732a532): New commits implement the CI infrastructure for the device_split pytest marker: a _device_split.py helper module, refactored conftest.py to run marked files once per device in separate subprocesses, updated build.yaml to install ovphysx in the OV CI job, and applied the marker to existing OVPhysX test files. Well-structured refactor with unit tests included. No issues with the IMU sensor code. No new concerns.


Update (e19c255): Branch rebased. New changes address @marcodiiga's blocking review:

  1. Timestamp guard added to kernelimu_update_kernel now receives self._timestamp and skips envs where timestamp[idx] == 0.0, preventing stale velocity reads after reset (mirrors PhysX guard, fixes #4970).
  2. Public reset regression test addedtest_no_stale_data_after_scene_reset exercises the exact path: scene.reset(env_ids)imu.data access before next sim step.
  3. Script references fixed — All docs/skip-reasons now use ./isaaclab.sh -p instead of the removed ./scripts/run_ovphysx.sh.
  4. Changelog entry addedchangelog.d/antoiner-feat-ovphysx_imu.minor.rst.

No new issues found in the incremental changes. Previous medium/minor suggestions (CPU→GPU copy caching, test doc commands) remain non-blocking.


Update (a406098): New commits include:

  1. Unrelated isaaclab core fixes_fabric_notices.py no-ops when usdrt is unavailable in kitless runtimes; build_simulation_context now properly honors the device kwarg when sim_cfg is also provided. Both include tests and changelogs. No concerns.

  2. OVPhysX asset cloning cleanup — Removed redundant queue_usd_replication(cfg) calls from articulation, rigid_object, and rigid_object_collection (only queue_ovphysx_replication remains). Proper separation of backend concerns. ✅

  3. IMU sensor code — The sensor implementation files (imu.py, imu_data.py, kernels.py, __init__.py, __init__.pyi) are present and consistent with the previously reviewed version. The CPU→GPU COM copy now conditionally skips on CPU (if self._coms_read_view is not self._coms_gpu_view), which partially addresses the 🟡 medium suggestion from above.

  4. Test suite expandedtest_imu.py now includes 12 parametrized tests covering: initialization, gravity at rest, freefall, constant velocity/acceleration, offset composition, env_ids propagation, reset, stale-data-after-scene-reset, indirect attachment via Xform, attachment validity, and sensor print. Comprehensive coverage. ✅

  5. Newton visualizer particle options — New show_particles and particle_color config with proper caching and test coverage. Clean addition, no concerns.

No new issues introduced in these changes. All previous blockers remain resolved. Ship it.


Update (59d7843, rebased): PR rebased. Latest commit "Tidy IMU kernels" contains code-quality improvements only — no logic changes:

  1. Kernel cleanup (both PhysX + OVPhysX): Added docstrings to imu_update_kernel and imu_reset_kernel, reordered parameters for clearer input/output grouping, removed verbose numbered comments, condensed intermediate variables. Logic is identical.
  2. Argument order sync: imu.py callers updated to match new kernel signatures (prev_lin_vel_w moved after timestamp).
  3. CI markers: Removed @pytest.mark.isaacsim_ci from OVPhysX test functions (articulation, rigid_object, rigid_object_collection, contact_sensor). Superseded by the device_split infrastructure.

No new issues. Previous medium/minor suggestions remain non-blocking. ✅


Update (4efc6c0): New commit adds a changelog.d/antoiner-feat-ovphysx_imu.skip file for the isaaclab_physx package — a towncrier skip marker documenting the kernel tidy-up as internal-only. No code changes, no new issues. ✅

@AntoineRichard AntoineRichard marked this pull request as ready for review May 20, 2026 07:03
@greptile-apps

greptile-apps Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an OVPhysX-backed Imu / ImuData sensor pair that satisfies the BaseImu / BaseImuData contracts using tensor bindings (RIGID_BODY_POSE, RIGID_BODY_VELOCITY, RIGID_BODY_COM_POSE) instead of PhysX views, with gravity read from OvPhysxManager.get_gravity() and a CPU\u2192GPU staging step for the COM binding.

  • Core sensor (imu.py): Resolves the nearest rigid-body ancestor at init, creates three tensor bindings, composes the configured offset with the fixed ancestor\u2192sensor transform, and runs identical Warp kernels to the PhysX backend on every update.
  • OvPhysxManager.get_gravity(): New classmethod mirrors SimulationView.get_gravity() so backend-agnostic code can read gravity from one entry point.
  • Tests: Six active kitless pytest scenarios plus two USD-blocked skips and a check_imu.py smoke script.

Confidence Score: 3/5

Not safe to merge as-is: the imu/ subdirectory is missing its init.py and init.pyi, so every import of Imu or ImuData from isaaclab_ovphysx.sensors will raise ModuleNotFoundError at runtime.

The sensor logic, kernel math, gravity integration, buffer aliasing, and test suite are all well-structured and closely mirror the validated PhysX backend. However, the imu/ directory ships without the two package files (init.py and init.pyi) that every other subpackage in this tree carries. Without them, lazy_export() in sensors/init.py cannot resolve the lazy import from .imu, so any real consumer of the module will hit a hard import failure before reaching any of the new code.

source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/ — missing init.py and init.pyi

Important Files Changed

Filename Overview
source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/init.pyi Adds Imu and ImuData exports, but the corresponding imu/ subpackage is missing init.py and init.pyi, making this import declaration non-functional at runtime.
source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/imu.py New OVPhysX IMU sensor implementation mirroring the PhysX backend; logic is structurally sound but the imu/ directory is missing its init.py and init.pyi package files.
source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/imu_data.py Data container implementing BaseImuData; correctly lazily caches ProxyArray wrappers for ang_vel_b and lin_acc_b on first access.
source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/kernels.py Warp kernels mathematically identical to the PhysX reference kernels; correctly computes COM-corrected velocity, numerical FD acceleration with gravity bias, and sensor-frame rotation.
source/isaaclab_ovphysx/isaaclab_ovphysx/physics/ovphysx_manager.py Adds get_gravity() classmethod to mirror PhysX SimulationView.get_gravity(); validates _sim and cfg before access and raises a clear RuntimeError.
source/isaaclab_ovphysx/test/sensors/test_imu.py Comprehensive kitless test suite covering constant-velocity, constant-acceleration, offset-calculation, env-id propagation, reset, freefall, and indirect-attachment scenarios.
source/isaaclab_ovphysx/test/sensors/check_imu.py Standalone freefall smoke-test; correctly drives a free-falling sphere and expects near-zero proper acceleration.

Sequence Diagram

sequenceDiagram
    participant User
    participant Imu
    participant OvPhysxManager
    participant PoseBinding
    participant VelBinding
    participant ComBinding
    participant WarpKernel

    User->>Imu: _initialize_impl()
    Imu->>OvPhysxManager: get_physx_instance()
    Imu->>OvPhysxManager: get_gravity()
    OvPhysxManager-->>Imu: (gx, gy, gz)
    Imu->>PoseBinding: create_tensor_binding(RIGID_BODY_POSE)
    Imu->>VelBinding: create_tensor_binding(RIGID_BODY_VELOCITY)
    Imu->>ComBinding: create_tensor_binding(RIGID_BODY_COM_POSE)
    Imu->>Imu: _initialize_buffers_impl()

    User->>Imu: "update(dt, force_recompute=True)"
    Imu->>PoseBinding: read(_transforms_view)
    Imu->>VelBinding: read(_velocities_view)
    Imu->>ComBinding: read(_coms_cpu_view)
    Imu->>Imu: "wp.copy(_coms_gpu_view <- _coms_cpu_view)"
    Imu->>WarpKernel: imu_update_kernel(...)
    WarpKernel-->>Imu: ang_vel_b, lin_acc_b written in-place

    User->>Imu: data.ang_vel_b / data.lin_acc_b
    Imu-->>User: ProxyArray (warp to torch alias)
Loading

Reviews (1): Last reviewed commit: "Address IMU review feedback" | Re-trigger Greptile

]

from .contact_sensor import ContactSensor, ContactSensorCfg, ContactSensorData
from .imu import Imu, ImuData

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.

P0 Missing imu/__init__.py and imu/__init__.pyi

The sensors/imu/ directory is missing its __init__.py (and the corresponding .pyi stub). Without __init__.py, sensors/imu/ is not a Python package, so the lazy_export() mechanism in sensors/__init__.py will fail when it tries to resolve from .imu import Imu, ImuData — Python will raise ModuleNotFoundError: No module named 'isaaclab_ovphysx.sensors.imu' on first access of either symbol.

Every peer package follows this exact pattern: sensors/contact_sensor/ has both __init__.py (calling lazy_export()) and __init__.pyi (declaring ContactSensor, ContactSensorCfg, ContactSensorData), and the PhysX sensors/imu/ has the same pair. The OVPhysX imu/ package needs matching files to be importable at runtime.

@AntoineRichard AntoineRichard mentioned this pull request May 20, 2026
7 tasks
Comment on lines +177 to +187
fixed_p = torch.tensor(fixed_pos_b, device=self._device).repeat(self._num_bodies, 1)
fixed_q = torch.tensor(fixed_quat_b, device=self._device).repeat(self._num_bodies, 1)

cfg_p = wp.to_torch(self._offset_pos_b).clone()
cfg_q = wp.to_torch(self._offset_quat_b).clone()

composed_p = fixed_p + math_utils.quat_apply(fixed_q, cfg_p)
composed_q = math_utils.quat_mul(fixed_q, cfg_q)

self._offset_pos_b = wp.from_torch(composed_p.contiguous(), dtype=wp.vec3f)
self._offset_quat_b = wp.from_torch(composed_q.contiguous(), dtype=wp.quatf)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

the round trip feel a bit weird. Would adding warp kernel for doing this be beneficial? Broadcast seems savable. Or it can be potentially done in _initialize_buffers_impl.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This side is matching the PhysX sensor. I agree it's odd.

fixed_p = torch.tensor(fixed_pos_b, device=self._device).repeat(self._num_bodies, 1)
fixed_q = torch.tensor(fixed_quat_b, device=self._device).repeat(self._num_bodies, 1)

cfg_p = wp.to_torch(self._offset_pos_b).clone()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is clone strictly needed?

self._pose_binding.read(self._transforms_view)
self._vel_binding.read(self._velocities_view)
# COM is CPU-resident in ovphysx; stage on CPU, then copy into the GPU buffer.
self._com_binding.read(self._coms_cpu_view)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

curious why it's cpu based in ovphysx

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

com_pos_b = self._view.get_coms().to(self.device).split([3, 4], dim=-1)[0]
Looks like it's on CPU for PhysX too. But we didn't flag this somehow in the tests? It makes sense since it's part of the inertial side of PhysX and mass and inertias are on CPU.

offset_quat_b: wp.array(dtype=wp.quatf),
gravity_bias_w: wp.array(dtype=wp.vec3f),
# previous velocities (read + write)
prev_lin_vel_w: wp.array(dtype=wp.vec3f),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: my personal preference would be to organze into (input, input/output, output) or just (input, output) sections. Per arg comment maybe can go right.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed also fixed that in PhysX kernel.

@marcodiiga marcodiiga left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocking finding from reviewing this against current develop:

source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/kernels.py:29-49 reads the OVPhysX velocity binding and finite-differences it whenever env_mask[idx] is true, and _update_buffers_impl() launches that kernel at source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/imu.py:201-216 without passing the sensor timestamp. The PhysX backend has the reset guard at source/isaaclab_physx/isaaclab_physx/sensors/imu/kernels.py:35-38, and both PhysX/Newton have public reset regressions (source/isaaclab_physx/test/sensors/test_imu.py:506-539, source/isaaclab_newton/test/sensors/test_imu.py:236-268).

This leaves the OVPhysX IMU vulnerable to the same reset/lazy-access bug: after scene.reset(env_ids) zeros the Isaac Lab buffers and timestamps, the native velocity buffer can still contain the previous step's value until another physics step runs. A public imu.data read in that window can lazy-refetch stale velocity and repopulate the reset env with non-zero angular velocity / spurious linear acceleration.

Please mirror the timestamp guard in the OVPhysX IMU kernel/launch and add the same public reset regression to the OVPhysX test (scene.reset(env_ids) followed by imu.data before another sim step). The current OVPhysX reset test at source/isaaclab_ovphysx/test/sensors/test_imu.py:496-528 explicitly reads raw buffers because imu.data would lazy refill, so it does not cover this public path.

Separate cleanup: the new OVPhysX IMU docs/tests still reference ./scripts/run_ovphysx.sh (source/isaaclab_ovphysx/test/sensors/test_imu.py:10-11, source/isaaclab_ovphysx/test/sensors/check_imu.py:8-9, and the skip reasons at source/isaaclab_ovphysx/test/sensors/test_imu.py:634-650), but that script is no longer present on current develop. Please update those instructions to the current runner.

@marcodiiga

marcodiiga commented Jun 5, 2026

Copy link
Copy Markdown

Adding one additional item to the existing requested-changes review:

Can the body/ancestor resolution in source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/imu/imu.py reuse SensorBase._resolve_rigid_body_ancestor_expr() instead of hand-rolling the ancestor scan and binding-expression rewrite?

That would match the current PhysX IMU path and avoid diverging from the shared source/clone resolution logic. If this local path stays, please also make the suffix removal path-aware rather than using a raw str.replace("/" + relative_path, ""), since repeated child suffixes can produce the wrong rigid-body expression.

@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch from b2100fa to 667f896 Compare June 9, 2026 09:16
@isaaclab-review-bot

Copy link
Copy Markdown

Update (ef80328): New commits fix a bug in SensorBase._resolve_rigid_body_ancestor_expr() where str.replace() could incorrectly strip repeated path segments (e.g., /Robot/link/link/Robot instead of /Robot/link). The fix uses endswith() + slicing with proper error handling. The OVPhysX IMU now delegates ancestor resolution to this shared base-class method (removing duplicated local logic). A regression test is included. Clean changes, no new issues.

CI Status: ✅ Pre-commit and license checks pass. Build jobs in progress.

Files Changed (since 667f896):

  • sensor_base.py: Fixed suffix trimming to use endswith() check + slicing instead of naive str.replace(). Added defensive RuntimeError if path doesn't end with expected suffix.
  • test_sensor_base.py: Added regression test for repeated path segment case (/Robot/link/link).
  • imu.py (ovphysx): Removed 16 lines of duplicated ancestor resolution logic, now calls self._resolve_rigid_body_ancestor_expr().
  • fix-sensor-base-ancestor-suffix.rst: Changelog fragment for the fix.

Assessment: This is a clean refactor that:

  1. Fixes a real edge-case bug (repeated path segments)
  2. Reduces code duplication by reusing the base class method
  3. Includes appropriate test coverage

Previous medium/minor suggestions (CPU→GPU copy caching, test doc commands) remain as non-blocking improvements. The PR continues to be ready for merge pending CI green.

AntoineRichard added a commit to AntoineRichard/IsaacLab that referenced this pull request Jun 9, 2026
Mirrors PhysX's SimulationView.get_gravity() so backend-agnostic sensor
code can read scene gravity through one classmethod regardless of
backend. Reads from the active SimulationCfg; raises RuntimeError if
the manager has not been initialized.

Identical to the addition in the OVPhysX IMU PR (isaac-sim#5421) so the two PRs
merge cleanly in either order.
@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch 2 times, most recently from e19c255 to a406098 Compare June 9, 2026 16:13
Mirror the PhysX backend (source/isaaclab_physx/isaaclab_physx/sensors/imu/)
with three substantive divergences:

- Use OvPhysxManager.get_physx_instance() + create_tensor_binding(...)
  with RIGID_BODY_POSE / RIGID_BODY_VELOCITY / RIGID_BODY_COM_POSE
  instead of physics_sim_view.create_rigid_body_view(...).
- Read scene gravity from PhysicsManager._sim.cfg.gravity (3-tuple);
  the OvPhysx manager has no get_gravity().
- Pre-allocate structured-dtype buffers (wp.transformf, wp.spatial_vectorf)
  and use ovphysx's destination-as-argument binding.read(dst) API.

Warp kernels (imu_update_kernel, imu_reset_kernel) are mathematically
identical to the PhysX ones; only the data source comment differs.
Add Imu / ImuData to the sensors package __init__.pyi.

Refs isaac-sim#5318.
Mirror the structure of source/isaaclab_physx/test/sensors/test_imu.py
under the kitless launcher pattern established by the rigid-object test:

- Wheel gate (importorskip ovphysx.types + RIGID_BODY_POSE hasattr check)
  before AppLauncher; no AppLauncher needed at runtime.
- SimulationContext built directly via build_simulation_context.
- Imperative scene-builder helpers (_spawn_envs / _spawn_balls /
  _spawn_cubes / _spawn_anymal); RigidObject and Articulation do the
  per-env spawn themselves once /World/env_<i> Xform containers exist
  (one Xform layer between /World and the wildcard — ovphysx's
  pattern-matching does not propagate wildcards through deeper nesting).
- Six tests run on real Nucleus / procedural USD assets:
  test_constant_velocity, test_constant_acceleration, test_offset_calculation,
  test_env_ids_propagation, test_attachment_validity, test_sensor_print.
- Two URDF-dependent tests (test_single_dof_pendulum, test_indirect_attachment)
  are skipped pending a USD version of simple_2_link.urdf — URDF→USD
  conversion requires the Kit URDF importer extension.

imu.update(dt) is called with force_recompute=True so the kernel fires
each step (without InteractiveScene's lazy_sensor_update plumbing,
the buffer would otherwise only refresh on imu.data access, leaving
prev_lin_vel unseeded on iterations where the test skips data reads).

check_imu.py is a kitless smoke-test script (free-falling sphere + IMU,
prints readings for visual inspection).

Changelog fragment added under source/isaaclab_ovphysx/changelog.d/ per
the new fragment-based workflow (do not edit CHANGELOG.rst directly).

Refs isaac-sim#5318.
The OVPhysX IMU kernels are mathematically identical to the PhysX
ones — only the data source differs, and that lives one layer above
in imu.py. Drop the trivial section-comment delta and restore the
PhysX step-numbered labels so a reviewer can diff PhysX vs OVPhysX
kernels.py and get zero changes.

This also closes the kernel-comment-density divergence noted in the
PR review.
Five small cleanups from the cross-backend review to bring the IMU
closer to the PhysX reference and the rest of isaaclab_ovphysx:

* Add OvPhysxManager.get_gravity() classmethod (mirrors the PhysX
  physics_sim_view.get_gravity() public API) and use it from the IMU
  in place of the private PhysicsManager._sim.cfg.gravity reach-in.
* Drop the redundant ``_buf`` suffix from the structured-dtype buffers
  (``_transforms_buf`` -> ``_transforms``, ``_velocities_buf`` -> ``_velocities``).
  ``_coms_buffer`` keeps its name to match PhysX.
* Canonical OvPhysx ``OvPhysxManager has not been initialized yet.``
  error message for the ``physx_instance is None`` guard, matching
  the contact-sensor, rigid-object, and articulation modules.
* Body-count guard now raises ``ValueError`` (configuration error) to
  match the Newton IMU; reworded to point at the binding pattern.
* ``__str__`` prints the binding pattern instead of the redundant
  ``backend : ovphysx`` line.
* Consolidate the duplicate inline comments that explained the
  ``binding.read(dst)`` flat-float32 view aliasing twice.
Test-side polish from the cross-backend review:

* Port the Newton physics-correctness suite — ``test_sensor_initialization``,
  ``test_gravity_at_rest``, ``test_freefall_acceleration``, ``test_reset``,
  and a USD-only ``test_indirect_attachment_usd`` (the URDF-blocked
  PhysX ``test_indirect_attachment`` is reachable kitless via an Xform
  child under a rigid body).
* Adopt the contact-sensor / rigid-object autouse
  ``_ovphysx_skip_other_device`` device-lock fixture and parametrize
  every test on ``device in ["cpu", "cuda:0"]`` to unblock GPU coverage
  through split-invocation runs.
* Tighten ``test_sensor_print`` to assert the prim path and
  ``binding pattern`` line surface in ``str(imu)``.
* Document the procedural-vs-Nucleus split-invocation requirement in
  the module docstring (mirrors the rigid-object header).
* Clarify the URDF skip-reason strings so they don't suggest the
  ``simple_2_link.urdf`` file already lives in the ovphysx test tree.
* OvPhysxManager.get_gravity() now raises RuntimeError when the
  simulation is not initialized, instead of silently returning the
  IsaacLab default (0, 0, -9.81). The silent fallback would mask
  non-Earth gravity scenes (Moon, Mars, tilt tests) and hide
  init-order bugs. Fix the chained-call Sphinx role in the same
  docstring.
* Match PhysX wording in the Imu class docstring ("queried from the
  simulation" instead of "read from the simulation configuration")
  for cross-backend homogeneity.
* Drop the stale "PhysX view data" banner from the OVPhysX kernels
  file in favor of the backend-neutral "rigid-body view data".
* Trim the changelog fragment's implementation-detail sentence per
  the "no internal details users wouldn't understand" rule.
The imu/ subpackage was committed without its __init__.py and
__init__.pyi files because the project gitignore rule **/__*
silently filters them out. Without these, importing Imu or
ImuData from isaaclab_ovphysx.sensors raises ModuleNotFoundError
at runtime and ruff misclassifies isaaclab_ovphysx imports in
imu.py as third-party (causing pre-commit to fail on CI).

Force-added with git add -f. The broader gitignore rule should
be tightened in a separate change so other new packages don't
hit the same trap.
Reuse SensorBase rigid-body ancestor resolution in the OVPhysX IMU path so clone-plan source handling stays aligned with the PhysX implementation.

Also make the shared suffix trimming path-end-only and cover repeated child suffixes with a regression.
Add the device_split module marker so the CI runner from the OVPhysX default-install work can invoke the IMU test file once per device.
Drive a native velocity sample before reset and assert the sensor cached velocity became non-zero. This keeps the regression focused on stale native data instead of relying on freefall to produce non-zero proper acceleration.
Align the PhysX and OVPhysX IMU kernel signatures and docstrings after the kernel cleanup.
@AntoineRichard AntoineRichard force-pushed the antoiner/feat/ovphysx_imu branch from 26f9351 to 59d7843 Compare June 10, 2026 08:50
Add a no-bump changelog fragment for the PhysX-only IMU kernel tidy so the changelog checker accepts the PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants