Summary
Implement `Imu` and `ImuData` for the OVPhysX backend, satisfying the `BaseImu` and `BaseImuData` contracts. Reports angular velocity and linear acceleration in the sensor's body frame using numerical differentiation of velocities.
Validation: Standalone script — attach IMU to falling/rotating rigid body, verify gravity acceleration and angular velocity.
Scope
- `imu.py` (~300 lines), `imu_data.py` (~80 lines), `kernels.py` (~100 lines)
- Copy PhysX tests with config swap
No OVPhysX API Blockers
All required data (body transforms, velocities, COM) is already available through existing Articulation TensorBindings. No new ovphysx APIs needed.
Dependencies
Spec
Full design spec: `docs/superpowers/specs/2026-04-20-ovphysx-imu-sensor-design.md`
Parent issue: #5315
📋 Full Design Spec (click to expand)
OVPhysX IMU Sensor — Design Spec
Issue: #5318 — [OVPHYSX] IMU sensor
Date: 2026-04-20
Status: Draft
Summary
Implement Imu and ImuData for the OVPhysX backend, satisfying the BaseImu and BaseImuData contracts. The IMU sensor reports angular velocity and linear acceleration in the sensor's body frame. It uses numerical differentiation of velocities (same as PhysX approach).
Validation environment: No existing task uses ImuCfg directly. Write a standalone validation script that attaches an IMU to a falling/rotating rigid body and verifies output matches expected physics (gravity acceleration, angular velocity from known torque).
Guiding Principles
- Mirror PhysX
Imu implementation
- Do not modify
BaseImu or BaseImuData contracts
- Numerical differentiation for linear acceleration (same as PhysX — ovphysx does not provide native acceleration)
Contract to Satisfy
BaseImu (source/isaaclab/isaaclab/sensors/imu/base_imu.py)
Inherits SensorBase. Additional abstract:
| Property/Method |
Type |
Description |
data |
BaseImuData |
IMU data container |
_initialize_impl() |
method |
Setup rigid body view and offsets |
_update_buffers_impl(env_mask) |
method |
Fetch state and compute IMU outputs |
BaseImuData (source/isaaclab/isaaclab/sensors/imu/base_imu_data.py)
| Property |
Shape |
Type |
Description |
ang_vel_b |
(N,) |
wp.vec3f |
Angular velocity in body frame [rad/s] |
lin_acc_b |
(N,) |
wp.vec3f |
Linear acceleration in body frame [m/s^2], includes gravity |
Architecture
File Layout
source/isaaclab_ovphysx/isaaclab_ovphysx/sensors/
├── __init__.py
├── __init__.pyi
├── kernels.py (shared sensor kernels)
└── imu/
├── __init__.py
├── __init__.pyi
├── imu.py (~300 lines)
├── imu_data.py (~80 lines)
└── kernels.py (~100 lines)
Implementation Pattern
imu.py:
-
_initialize_impl():
- Find target prim and its rigid-body ancestor
- Resolve fixed transform from ancestor body to target prim (done once)
- Compose with configured sensor offset
- Get body state from ovphysx via TensorBindings:
RIGID_BODY_ROOT_POSE or ARTICULATION_BODY_POSE for transforms
RIGID_BODY_ROOT_VELOCITY or ARTICULATION_BODY_VELOCITY for velocities
- Body COM data for lever arm correction
- Query world gravity from OvPhysxManager (needed for gravity bias)
- Allocate buffers including
prev_lin_vel_w for numerical differentiation
-
_update_buffers_impl(env_mask):
- Read body transforms and velocities from ovphysx bindings
- Read COM positions (may be CPU — copy to GPU)
- Launch
imu_update_kernel per environment:
- Apply sensor offset quaternion to body orientation
- Correct linear velocity for COM offset (lever arm cross product)
- Numerically differentiate:
lin_acc = (vel_current - vel_prev) / dt + gravity_bias
- Rotate angular velocity and linear acceleration to body frame
- Store results and update
prev_lin_vel_w
imu_data.py:
- Simple container with
_ang_vel_b and _lin_acc_b warp arrays
- Properties return the arrays directly
OVPhysX API Requirements
| API |
Purpose |
Notes |
| Body transforms |
Orientation for frame rotation |
Already available via Articulation bindings |
| Body velocities |
Linear + angular velocity |
Already available |
| Body COM |
Lever arm correction |
Already available (CPU) |
| Gravity vector |
Acceleration bias |
From OvPhysxManager or USD scene |
No new ovphysx APIs needed — all required data is already available through existing TensorBindings used by the Articulation. The IMU just reads body state from a different entry point (the sensor's target body rather than the root).
Warp Kernels
| Kernel |
Purpose |
imu_update_kernel |
Per-env: offset composition, COM correction, numerical diff, frame rotation |
imu_reset_kernel |
Zero velocity history and output buffers |
These are direct ports of the PhysX kernels — the math is identical, only the data source changes.
Tests
Backend-specific tests (copy from PhysX)
Source: source/isaaclab_physx/test/sensors/test_imu.py
Target: source/isaaclab_ovphysx/test/sensors/test_imu.py
Changes: swap physics config to OvPhysxCfg.
Validation script
Write source/isaaclab_ovphysx/test/sensors/check_imu.py:
- Create a rigid body with known initial angular velocity
- Attach IMU sensor
- Step physics
- Verify
ang_vel_b matches expected value
- Verify
lin_acc_b includes gravity (~9.81 m/s^2 downward in body frame)
Dependencies
Estimated Scope
imu.py: ~300 lines
imu_data.py: ~80 lines
kernels.py: ~100 lines
- Tests: ~150 lines of adaptations
- Validation script: ~100 lines
Summary
Implement `Imu` and `ImuData` for the OVPhysX backend, satisfying the `BaseImu` and `BaseImuData` contracts. Reports angular velocity and linear acceleration in the sensor's body frame using numerical differentiation of velocities.
Validation: Standalone script — attach IMU to falling/rotating rigid body, verify gravity acceleration and angular velocity.
Scope
No OVPhysX API Blockers
All required data (body transforms, velocities, COM) is already available through existing Articulation TensorBindings. No new ovphysx APIs needed.
Dependencies
Spec
Full design spec: `docs/superpowers/specs/2026-04-20-ovphysx-imu-sensor-design.md`
Parent issue: #5315
📋 Full Design Spec (click to expand)
OVPhysX IMU Sensor — Design Spec
Issue: #5318 — [OVPHYSX] IMU sensor
Date: 2026-04-20
Status: Draft
Summary
Implement
ImuandImuDatafor the OVPhysX backend, satisfying theBaseImuandBaseImuDatacontracts. The IMU sensor reports angular velocity and linear acceleration in the sensor's body frame. It uses numerical differentiation of velocities (same as PhysX approach).Validation environment: No existing task uses
ImuCfgdirectly. Write a standalone validation script that attaches an IMU to a falling/rotating rigid body and verifies output matches expected physics (gravity acceleration, angular velocity from known torque).Guiding Principles
ImuimplementationBaseImuorBaseImuDatacontractsContract to Satisfy
BaseImu (source/isaaclab/isaaclab/sensors/imu/base_imu.py)
Inherits
SensorBase. Additional abstract:dataBaseImuData_initialize_impl()_update_buffers_impl(env_mask)BaseImuData (source/isaaclab/isaaclab/sensors/imu/base_imu_data.py)
ang_vel_b(N,)wp.vec3flin_acc_b(N,)wp.vec3fArchitecture
File Layout
Implementation Pattern
imu.py:
_initialize_impl():RIGID_BODY_ROOT_POSEorARTICULATION_BODY_POSEfor transformsRIGID_BODY_ROOT_VELOCITYorARTICULATION_BODY_VELOCITYfor velocitiesprev_lin_vel_wfor numerical differentiation_update_buffers_impl(env_mask):imu_update_kernelper environment:lin_acc = (vel_current - vel_prev) / dt + gravity_biasprev_lin_vel_wimu_data.py:
_ang_vel_band_lin_acc_bwarp arraysOVPhysX API Requirements
No new ovphysx APIs needed — all required data is already available through existing TensorBindings used by the Articulation. The IMU just reads body state from a different entry point (the sensor's target body rather than the root).
Warp Kernels
imu_update_kernelimu_reset_kernelThese are direct ports of the PhysX kernels — the math is identical, only the data source changes.
Tests
Backend-specific tests (copy from PhysX)
Source:
source/isaaclab_physx/test/sensors/test_imu.pyTarget:
source/isaaclab_ovphysx/test/sensors/test_imu.pyChanges: swap physics config to
OvPhysxCfg.Validation script
Write
source/isaaclab_ovphysx/test/sensors/check_imu.py:ang_vel_bmatches expected valuelin_acc_bincludes gravity (~9.81 m/s^2 downward in body frame)Dependencies
Estimated Scope
imu.py: ~300 linesimu_data.py: ~80 lineskernels.py: ~100 lines