Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
9afd8fc
Add RIGID_BODY_* TensorType aliases
AntoineRichard Apr 28, 2026
4b3503b
Relocate shared Warp kernels to isaaclab_ovphysx.assets.kernels
AntoineRichard Apr 28, 2026
5f8c4c6
Add asset_kind='rigid_object' mode to MockOvPhysxBindingSet
AntoineRichard Apr 28, 2026
65084f7
Scaffold OVPhysX RigidObjectData skeleton
AntoineRichard Apr 28, 2026
0a79c66
Fix RigidObjectData defaults and is_primed gating
AntoineRichard Apr 28, 2026
3cb5de1
Implement RigidObjectData root-state properties
AntoineRichard Apr 28, 2026
b2afe59
Reset buffer timestamps in _invalidate_caches
AntoineRichard Apr 28, 2026
95dc4fa
Implement body-state and body-frame derived properties
AntoineRichard Apr 28, 2026
1e9e9aa
Fix projected_gravity_b test to use unit-vector gravity
AntoineRichard Apr 28, 2026
5963cfe
Implement RigidObjectData body mass/inertia/COM properties
AntoineRichard Apr 28, 2026
9a69088
Scaffold OVPhysX RigidObject skeleton
AntoineRichard Apr 28, 2026
af2e8a9
Apply Marco's RIGID_BODY_* contract corrections
AntoineRichard Apr 28, 2026
0ec4611
Add RigidObject _create_buffers and _process_cfg
AntoineRichard Apr 28, 2026
af529eb
Implement RigidObject root pose and velocity writers
AntoineRichard Apr 28, 2026
fed5d23
Implement RigidObject mass/COM/inertia setters
AntoineRichard Apr 28, 2026
6cb0c36
Implement RigidObject.write_data_to_sim wrench application
AntoineRichard Apr 28, 2026
f10f59c
Implement RigidObject lifecycle methods
AntoineRichard Apr 28, 2026
bbad12b
Export RigidObject and RigidObjectData publicly
AntoineRichard Apr 28, 2026
5c07601
Add OVPhysX backend to test_rigid_object_iface
AntoineRichard Apr 28, 2026
0a950bd
Add OVPhysX preset to Allegro hand env
AntoineRichard Apr 28, 2026
6b16fe9
Bump isaaclab_ovphysx to 0.2.0 for RigidObject
AntoineRichard Apr 28, 2026
db27e50
Drop RIGID_BODY_ACCELERATION dependency, FD acc from velocity
AntoineRichard Apr 28, 2026
a07c425
Fix stale-buffer bug in body_com_pose_b lazy read
AntoineRichard Apr 28, 2026
6e81211
Add kitless guard to test_rigid_object_iface
AntoineRichard Apr 28, 2026
cd38c46
Fix shape mismatch in 1-D body-property setter writes
AntoineRichard Apr 28, 2026
b3b93b3
Replace mock test_rigid_object with PhysX-copy kitless adapter
AntoineRichard Apr 28, 2026
b9eb426
Add kitless real-OvPhysxManager warmup + load tests
AntoineRichard Apr 28, 2026
e320fe1
Rewrite test_rigid_object to use real SimulationContext + Nucleus assets
AntoineRichard Apr 28, 2026
45557cd
Fix RigidObject._initialize_impl swallows on body_names and device
AntoineRichard Apr 28, 2026
aa0ee90
Match Newton's pattern in external_force_on_single_body
AntoineRichard Apr 28, 2026
7153229
Address W1 audit fixes: is_primed, naming, body_names, set_coms reshape
AntoineRichard Apr 29, 2026
e762ab5
Revert RigidObject.reset auto-write to match PhysX/Newton
AntoineRichard Apr 29, 2026
1e3dcf8
Port test_external_force_at_position to PhysX/Newton pattern
AntoineRichard Apr 29, 2026
b1a841e
Derive root_link_vel_w from root_com_vel_w via lever-arm kernel
AntoineRichard Apr 29, 2026
231e9be
Implement deprecated state-concat properties on RigidObjectData
AntoineRichard Apr 29, 2026
482e7af
Address remaining audit investigates: docstring, demotions, removal
AntoineRichard Apr 29, 2026
5e09119
Reorganize RigidObjectData to match PhysX/Newton structure
AntoineRichard Apr 29, 2026
b0532f2
Polish RigidObject docstrings + rename _write_root_state
AntoineRichard Apr 29, 2026
ed30c2c
Add docstrings to every kernel in isaaclab_ovphysx.assets.kernels
AntoineRichard Apr 29, 2026
7adf3b6
Polish test_rigid_object.py: drop gates, GPU coverage, docstring cleanup
AntoineRichard Apr 29, 2026
66df142
Unify _configure_physx_scene_prim across CPU and GPU
AntoineRichard Apr 29, 2026
2bd2752
Align test_rigid_object.py 1-to-1 with isaaclab_physx
AntoineRichard Apr 29, 2026
f06e64b
Use session-scoped sim fixture for rigid-object tests
AntoineRichard Apr 29, 2026
0887d2d
Mirror PhysX/Newton patterns in OVPhysX RigidObject
AntoineRichard Apr 29, 2026
8b180fb
Update RigidObject tests for new contract; document two-pass CI
AntoineRichard Apr 29, 2026
e2b2f55
Compact 0.2.15 changelog entry
AntoineRichard Apr 30, 2026
588c1c8
Squash 0.2.x changelog entries into a single 0.2.15 release
AntoineRichard Apr 30, 2026
d74e904
Drop full_data and dead helpers from OVPhysX RigidObject
AntoineRichard Apr 30, 2026
5cdc178
Cache flat wrench-buffer view in _create_buffers
AntoineRichard Apr 30, 2026
abbeda4
Trim kitless module stubs in iface test guards
AntoineRichard Apr 30, 2026
b340a55
Fix OVPhysX iface fixture to mirror PhysX/Newton setup
AntoineRichard Apr 30, 2026
08180d3
Move ovphysx lifecycle workaround into OvPhysxManager
AntoineRichard May 5, 2026
8bc3a4a
Address PR #5426 review feedback
AntoineRichard May 5, 2026
26a442b
Merge branch 'develop' into antoiner/feat/ovphysx_rigidobject
AntoineRichard May 5, 2026
c453822
Switch isaaclab_ovphysx PR changelog to fragments
AntoineRichard May 5, 2026
658e73c
Make OVPhysX RigidObject._get_binding strict
AntoineRichard May 5, 2026
cf1adf0
Address PR review on RigidObjectData
AntoineRichard May 5, 2026
1b62917
Convert IsaacLab regex prim-path to wheel glob in RigidObject
AntoineRichard May 6, 2026
e164b65
Bump rigid-object changelog fragment to major tier
AntoineRichard May 6, 2026
0998415
[OVPHYSX] Articulation rewrite (data class + asset class + kernels)
AntoineRichard May 5, 2026
e3a782e
Wire OVPhysX preset into Allegro Repose direct task
AntoineRichard May 6, 2026
f2e5e2a
[OVPHYSX] Articulation rewrite (data class + asset class + kernels)
AntoineRichard May 5, 2026
18c90dc
Wire OVPhysX preset into Allegro Repose direct task
AntoineRichard May 6, 2026
3ca52e7
Expose RigidObjectCollection from isaaclab_ovphysx.assets
AntoineRichard May 6, 2026
c2bcbd6
Add class stubs to RigidObjectCollection modules
AntoineRichard May 6, 2026
9a8eb0c
Port PhysX RigidObjectCollection tests to ovphysx
AntoineRichard May 6, 2026
8d2c36a
Parametrize collection iface test for ovphysx backend
AntoineRichard May 6, 2026
a112eb9
Add RigidObjectCollection class skeleton (NotImplementedError stubs)
AntoineRichard May 6, 2026
dfc1eae
Implement RigidObjectCollection initialization (per-body bindings)
AntoineRichard May 6, 2026
5be3408
Add env/body id resolvers for collection writers
AntoineRichard May 6, 2026
8a4399a
Implement body pose/velocity reads in collection data class
AntoineRichard May 6, 2026
cfedeff
Use _read_binding_into for inertia reads in collection data
AntoineRichard May 6, 2026
c013c56
Implement collection derived properties (gravity, heading, body-frame…
AntoineRichard May 6, 2026
aeb7c8b
Wire collection update path
AntoineRichard May 6, 2026
db68d6a
Implement collection body pose writers
AntoineRichard May 8, 2026
b975312
Implement collection body velocity writers
AntoineRichard May 8, 2026
2d471b1
Implement collection mass/com/inertia setters
AntoineRichard May 8, 2026
b544c86
Implement find_bodies and deprecated state writers for RigidObjectCol…
AntoineRichard May 8, 2026
38fcc06
Allocate collection wrench buffers and implement write_data_to_sim
AntoineRichard May 8, 2026
5a4703e
Add changelog fragment for ovphysx RigidObjectCollection
AntoineRichard May 8, 2026
f12294d
Align RigidObjectCollection with Articulation single-binding pattern
AntoineRichard May 8, 2026
bf438a1
Fix default_body_pose/vel regression by allocating buffers and wiring…
AntoineRichard May 8, 2026
eed7c31
Adapt OvPhysxManager to ovphysx 0.4 PhysX(active_cuda_gpus=) API
AntoineRichard May 8, 2026
9bb04c2
Bypass parent __init__ in collection (mirror PhysX) to set _is_initia…
AntoineRichard May 8, 2026
1c4d37a
Revert "Adapt OvPhysxManager to ovphysx 0.4 PhysX(active_cuda_gpus=) …
AntoineRichard May 8, 2026
e66cd03
Adapt OvPhysxManager to ovphysx 0.4 active_cuda_gpus API (cherry-pick…
AntoineRichard May 8, 2026
17733aa
Mirror PhysX collection __init__: spawn prims and register callbacks
AntoineRichard May 8, 2026
d629241
Fix RigidObjectCollection backend: use RIGID_BODY_* bindings via Fuse…
AntoineRichard May 8, 2026
5992872
Fix RigidObjectCollection test failures: add _env_body_ids_to_view_id…
AntoineRichard May 8, 2026
d4359f2
Track missing __init__.py and __init__.pyi for rigid_object_collectio…
AntoineRichard May 11, 2026
5f82db9
Use native fused multi-prim binding for OVPhysX object collection
AntoineRichard May 11, 2026
8137254
Set _data.is_primed=True after first update (mirror RigidObject/Artic…
AntoineRichard May 11, 2026
80d2b87
Clean up Step-N comments and normalize env_ids in reset() (mirror Rig…
AntoineRichard May 11, 2026
edc83fd
Merge branch 'develop' into antoiner/feat/ovphysx_rigidobject
kellyguo11 May 11, 2026
08bb545
Merge branch 'develop' into antoiner/feat/ovphysx_articulation
kellyguo11 May 11, 2026
1ff4c21
Align OVPhysX RigidObject layout with PhysX/Newton
AntoineRichard May 11, 2026
0ef8d77
Align OVPhysX articulation kernels with PhysX style
AntoineRichard May 11, 2026
22c4698
Reorder Articulation properties and trim dev cruft
AntoineRichard May 11, 2026
f21cd1f
Align ArticulationData class docstring and __init__ comments
AntoineRichard May 11, 2026
f8dd86f
Align Articulation module/class docstring with PhysX reference
AntoineRichard May 11, 2026
0e00d64
Use PhysX-style class docstring for Articulation
AntoineRichard May 11, 2026
a3d6ded
Align RigidObjectCollection class header with PhysX/Newton
AntoineRichard May 11, 2026
a753cdf
Add Operations - Finders/Write to simulation section markers
AntoineRichard May 11, 2026
7b2acea
Move write_body_velocity wrappers up to match PhysX/Newton order
AntoineRichard May 11, 2026
fdc356e
Reorder write_body_velocity COM/link and trim cruft comments
AntoineRichard May 11, 2026
36f61d1
Trim cruft comments and ignores on pose-writer methods
AntoineRichard May 11, 2026
95e2929
Strip remaining type-ignore decorators and pose-wrapper notes
AntoineRichard May 11, 2026
7961bd9
Move deprecated state writers to end of class
AntoineRichard May 11, 2026
6558d7c
Replace dashed banners with triple-quoted section markers
AntoineRichard May 11, 2026
bda38bd
Align RigidObjectCollectionData class docstring with PhysX
AntoineRichard May 11, 2026
b3d01d5
Replace dashed banners and trim cruft in data file
AntoineRichard May 11, 2026
d6e9187
Merge branch 'cp/rigidobject' into cp/articulation
AntoineRichard May 12, 2026
413dcd7
Merge branch 'cp/articulation' into cp/collection
AntoineRichard May 12, 2026
e50ec6e
Fix stale articulation reads with FK update in step()
AntoineRichard May 12, 2026
375f31d
Allocate _body_incoming_joint_wrench_buf in ArticulationData
AntoineRichard May 12, 2026
3abc6a5
Update tests for renamed JointDrive cfg field names
AntoineRichard May 12, 2026
5403548
Merge branch 'cp/articulation' into cp/collection
AntoineRichard May 12, 2026
5c5a5cd
Refresh forward kinematics in body_link_pose_w getter
AntoineRichard May 12, 2026
75e7aa5
Merge branch 'cp/articulation' into cp/collection
AntoineRichard May 12, 2026
53cf7c1
Merge branch 'develop' into antoiner/feat/ovphysx_rigidobject
AntoineRichard May 12, 2026
922cd72
Skip test_rigid_object.py when the ovphysx wheel is absent
AntoineRichard May 12, 2026
2f7ea69
Merge branch 'cp/rigidobject' into cp/articulation
AntoineRichard May 12, 2026
7a26cfb
Merge branch 'cp/articulation' into cp/collection
AntoineRichard May 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions scripts/run_ovphysx.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
# Use when ovphysx is installed into Kit's Python.
#
# Usage: ./scripts/run_ovphysx.sh [your_script.py or -m pytest ...]
#
# CI note: the OVPhysX wheel's device mode is a process-global C++/Carbonite
# static (gap G5 in docs/superpowers/specs/2026-04-28-ovphysx-wheel-gaps-for-marco.md).
# To exercise both CPU and GPU coverage, invoke this script TWICE in separate
# processes -- e.g.
# ./scripts/run_ovphysx.sh -m pytest <path> -k 'cpu'
# ./scripts/run_ovphysx.sh -m pytest <path> -k 'cuda:0'
# A single invocation locks to whichever device is requested first.
set -e

ISAACLAB_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
Expand Down
Empty file.
52 changes: 38 additions & 14 deletions source/isaaclab/test/assets/test_articulation_iface.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,33 @@
from unittest.mock import MagicMock

# When running kitless (e.g., ovphysx backend via run_ovphysx.sh), AppLauncher
# will try to boot Kit and hang. Skip it entirely when LD_PRELOAD is cleared
# (the signature of run_ovphysx.sh) or when EXP_PATH is not set.
_kitless = os.environ.get("LD_PRELOAD", "") == "" and "EXP_PATH" not in os.environ
# will try to boot Kit and hang. Skip it entirely: run_ovphysx.sh sets
# LD_PRELOAD to the ovphysx libcarb.so, which is the signature of a kitless
# ovphysx run. Also guard the case where neither LD_PRELOAD nor EXP_PATH is
# set (bare Python, no Kit at all).
_kitless = "ovphysx" in os.environ.get("LD_PRELOAD", "") or (
os.environ.get("LD_PRELOAD", "") == "" and "EXP_PATH" not in os.environ
)

if not _kitless:
from isaaclab.app import AppLauncher

simulation_app = AppLauncher(headless=True).app
else:
simulation_app = None
# Stub out the Kit/Omniverse modules that are not present under
# run_ovphysx.sh (pxr, carb, omni, omni.kit[.app] are real on PYTHONPATH).
# ``omni`` is a real namespace package, so missing submodules also need
# to be installed as attributes on it -- ``sys.modules`` alone is not
# enough because attribute access on the real ``omni`` won't fall
# through to ``sys.modules``.
import omni as _omni

for _mod in ("physics", "physics.tensors", "physx", "timeline", "usd"):
_stub = MagicMock()
sys.modules[f"omni.{_mod}"] = _stub
# Bind the leaf attribute so that ``omni.<leaf>`` resolves.
setattr(_omni, _mod.split(".", 1)[0], _stub)
for _mod in ("isaacsim.core", "isaacsim.core.simulation_manager"):
sys.modules.setdefault(_mod, MagicMock())

Expand Down Expand Up @@ -271,20 +288,27 @@ def create_ovphysx_articulation(
object.__setattr__(articulation, "_num_spatial_tendons", num_spatial_tendons)

# Create ArticulationData
data = OvPhysxArticulationData(mock_bindings.bindings, device)
data._num_instances = num_instances
data._num_joints = num_joints
data._num_bodies = num_bodies
data._num_fixed_tendons = num_fixed_tendons
data._num_spatial_tendons = num_spatial_tendons
data = OvPhysxArticulationData(
mock_bindings.bindings,
device,
num_instances=num_instances,
num_bodies=num_bodies,
num_joints=num_joints,
num_fixed_tendons=num_fixed_tendons,
num_spatial_tendons=num_spatial_tendons,
body_names=body_names,
joint_names=joint_names,
fixed_tendon_names=fixed_tendon_names,
spatial_tendon_names=spatial_tendon_names,
)
data._is_fixed_base = False
data.body_names = body_names
data.joint_names = joint_names
data.fixed_tendon_names = fixed_tendon_names
data.spatial_tendon_names = spatial_tendon_names
data._create_buffers()
object.__setattr__(articulation, "_data", data)

# Allocate the articulation-side index/mask caches and wrench buffer that
# _initialize_impl would normally populate. Wrench composers created here
# are immediately overwritten by the mocks below.
articulation._create_buffers()

# Wrench composers
mock_inst_wrench = MockWrenchComposer(articulation)
mock_perm_wrench = MockWrenchComposer(articulation)
Expand Down
114 changes: 107 additions & 7 deletions source/isaaclab/test/assets/test_rigid_object_collection_iface.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,42 @@
The setup is a bit convoluted so that we can run these tests without requiring Isaac Sim or GPU simulation.
"""

"""Launch Isaac Sim Simulator first."""
"""Launch Isaac Sim Simulator first (when available)."""

from isaaclab.app import AppLauncher

HEADLESS = True
import os
import sys
from unittest.mock import MagicMock

# launch omniverse app
simulation_app = AppLauncher(headless=True).app
# When running kitless (e.g., ovphysx backend via run_ovphysx.sh), AppLauncher
# will try to boot Kit and hang. Skip it entirely: run_ovphysx.sh sets
# LD_PRELOAD to the ovphysx libcarb.so, which is the signature of a kitless
# ovphysx run. Also guard the case where neither LD_PRELOAD nor EXP_PATH is
# set (bare Python, no Kit at all).
_kitless = "ovphysx" in os.environ.get("LD_PRELOAD", "") or (
os.environ.get("LD_PRELOAD", "") == "" and "EXP_PATH" not in os.environ
)

from unittest.mock import MagicMock
if not _kitless:
from isaaclab.app import AppLauncher

simulation_app = AppLauncher(headless=True).app
else:
simulation_app = None
# Stub out the Kit/Omniverse modules that are not present under
# run_ovphysx.sh (pxr, carb, omni, omni.kit[.app] are real on PYTHONPATH).
# ``omni`` is a real namespace package, so missing submodules also need
# to be installed as attributes on it -- ``sys.modules`` alone is not
# enough because attribute access on the real ``omni`` won't fall
# through to ``sys.modules``.
import omni as _omni

for _mod in ("physics", "physics.tensors", "physx", "timeline", "usd"):
_stub = MagicMock()
sys.modules[f"omni.{_mod}"] = _stub
# Bind the leaf attribute so that ``omni.<leaf>`` resolves.
setattr(_omni, _mod.split(".", 1)[0], _stub)
for _mod in ("isaacsim.core", "isaacsim.core.simulation_manager"):
sys.modules.setdefault(_mod, MagicMock())

import numpy as np
import pytest
Expand Down Expand Up @@ -75,6 +101,23 @@
except ImportError:
pass

try:
from isaaclab_ovphysx.assets.rigid_object_collection.rigid_object_collection import (
RigidObjectCollection as OvPhysxRigidObjectCollection,
)
from isaaclab_ovphysx.assets.rigid_object_collection.rigid_object_collection_data import (
RigidObjectCollectionData as OvPhysxRigidObjectCollectionData,
)
from isaaclab_ovphysx.test.mock_interfaces.views import MockOvPhysxBindingSet

# Guard against stub implementations (not yet functional).
if not hasattr(OvPhysxRigidObjectCollection, "_create_buffers"):
raise AttributeError("OvPhysxRigidObjectCollection is a stub; skipping ovphysx backend")

BACKENDS.append("ovphysx")
except (ImportError, AttributeError):
pass


def create_physx_rigid_object_collection(
num_instances: int = 2,
Expand Down Expand Up @@ -209,6 +252,61 @@ def create_newton_rigid_object_collection(
return collection, mock_view


def create_ovphysx_rigid_object_collection(
num_instances: int = 2,
num_bodies: int = 3,
device: str = "cuda:0",
):
"""Create a test OVPhysX RigidObjectCollection instance with mocked tensor bindings."""
body_names = [f"object_{i}" for i in range(num_bodies)]

collection = object.__new__(OvPhysxRigidObjectCollection)

rigid_objects = {f"object_{i}": RigidObjectCfg(prim_path=f"/World/Object_{i}") for i in range(num_bodies)}
collection.cfg = RigidObjectCollectionCfg(rigid_objects=rigid_objects)

# Use articulation-mode bindings with num_joints=0 to get (N, B, ...) shaped tensors.
mock_bindings = MockOvPhysxBindingSet(
num_instances=num_instances,
num_joints=0,
num_bodies=num_bodies,
body_names=body_names,
asset_kind="articulation",
)
mock_bindings.set_random_data()

object.__setattr__(collection, "_device", device)
object.__setattr__(collection, "_ovphysx", MagicMock())
object.__setattr__(collection, "_bindings", mock_bindings.bindings)
object.__setattr__(collection, "_num_instances", num_instances)
object.__setattr__(collection, "_num_bodies", num_bodies)
object.__setattr__(collection, "_body_names_list", body_names)

# Create RigidObjectCollectionData
data = OvPhysxRigidObjectCollectionData(mock_bindings.bindings, num_bodies, device)
data.num_instances = num_instances
data.num_bodies = num_bodies
data._is_primed = True
object.__setattr__(collection, "_data", data)

# Allocate the buffers that RigidObjectCollection normally allocates in _initialize_impl.
collection._create_buffers()

# Replace the real wrench composers with mocks for iface coverage.
mock_inst_wrench = MockWrenchComposer(collection)
mock_perm_wrench = MockWrenchComposer(collection)
object.__setattr__(collection, "_instantaneous_wrench_composer", mock_inst_wrench)
object.__setattr__(collection, "_permanent_wrench_composer", mock_perm_wrench)

# Prevent __del__ / _clear_callbacks from raising
object.__setattr__(collection, "_initialize_handle", None)
object.__setattr__(collection, "_invalidate_initialize_handle", None)
object.__setattr__(collection, "_prim_deletion_handle", None)
object.__setattr__(collection, "_debug_vis_handle", None)

return collection, mock_bindings


def create_mock_rigid_object_collection(
num_instances: int = 2,
num_bodies: int = 3,
Expand All @@ -232,6 +330,8 @@ def get_rigid_object_collection(
):
if backend == "physx":
return create_physx_rigid_object_collection(num_instances, num_bodies, device)
elif backend == "ovphysx":
return create_ovphysx_rigid_object_collection(num_instances, num_bodies, device)
elif backend == "newton":
return create_newton_rigid_object_collection(num_instances, num_bodies, device)
elif backend.lower() == "mock":
Expand Down
107 changes: 100 additions & 7 deletions source/isaaclab/test/assets/test_rigid_object_iface.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,42 @@
The setup is a bit convoluted so that we can run these tests without requiring Isaac Sim or GPU simulation.
"""

"""Launch Isaac Sim Simulator first."""
"""Launch Isaac Sim Simulator first (when available)."""

from isaaclab.app import AppLauncher

HEADLESS = True
import os
import sys
from unittest.mock import MagicMock

# launch omniverse app
simulation_app = AppLauncher(headless=True).app
# When running kitless (e.g., ovphysx backend via run_ovphysx.sh), AppLauncher
# will try to boot Kit and hang. Skip it entirely: run_ovphysx.sh sets
# LD_PRELOAD to the ovphysx libcarb.so, which is the signature of a kitless
# ovphysx run. Also guard the case where neither LD_PRELOAD nor EXP_PATH is
# set (bare Python, no Kit at all).
_kitless = "ovphysx" in os.environ.get("LD_PRELOAD", "") or (
os.environ.get("LD_PRELOAD", "") == "" and "EXP_PATH" not in os.environ
)

from unittest.mock import MagicMock
if not _kitless:
from isaaclab.app import AppLauncher

simulation_app = AppLauncher(headless=True).app
else:
simulation_app = None
# Stub out the Kit/Omniverse modules that are not present under
# run_ovphysx.sh (pxr, carb, omni, omni.kit[.app] are real on PYTHONPATH).
# ``omni`` is a real namespace package, so missing submodules also need
# to be installed as attributes on it -- ``sys.modules`` alone is not
# enough because attribute access on the real ``omni`` won't fall
# through to ``sys.modules``.
import omni as _omni

for _mod in ("physics", "physics.tensors", "physx", "timeline", "usd"):
_stub = MagicMock()
sys.modules[f"omni.{_mod}"] = _stub
# Bind the leaf attribute so that ``omni.<leaf>`` resolves.
setattr(_omni, _mod.split(".", 1)[0], _stub)
for _mod in ("isaacsim.core", "isaacsim.core.simulation_manager"):
sys.modules.setdefault(_mod, MagicMock())

import numpy as np
import pytest
Expand Down Expand Up @@ -66,6 +92,15 @@
except ImportError:
pass

try:
from isaaclab_ovphysx.assets.rigid_object.rigid_object import RigidObject as OvPhysxRigidObject
from isaaclab_ovphysx.assets.rigid_object.rigid_object_data import RigidObjectData as OvPhysxRigidObjectData
from isaaclab_ovphysx.test.mock_interfaces.views import MockOvPhysxBindingSet

BACKENDS.append("ovphysx")
except (ImportError, AttributeError):
pass


def create_physx_rigid_object(
num_instances: int = 2,
Expand Down Expand Up @@ -206,6 +241,62 @@ def create_newton_rigid_object(
return rigid_object, mock_view


def create_ovphysx_rigid_object(
num_instances: int = 2,
device: str = "cuda:0",
):
"""Create a test OvPhysX RigidObject instance with mocked tensor bindings."""
body_names = ["base_link"]

obj = object.__new__(OvPhysxRigidObject)

obj.cfg = RigidObjectCfg(prim_path="/World/object")

# Create mock binding set
mock_bindings = MockOvPhysxBindingSet(
num_instances=num_instances,
num_joints=0,
num_bodies=1,
body_names=body_names,
asset_kind="rigid_object",
)
mock_bindings.set_random_data()

object.__setattr__(obj, "_device", device)
object.__setattr__(obj, "_ovphysx", MagicMock())
object.__setattr__(obj, "_bindings", mock_bindings.bindings)
object.__setattr__(obj, "_num_instances", num_instances)
object.__setattr__(obj, "_num_bodies", 1)
object.__setattr__(obj, "_body_names", body_names)

# Create RigidObjectData
data = OvPhysxRigidObjectData(mock_bindings.bindings, device)
data.num_instances = num_instances
data.num_bodies = 1
data._is_primed = True
object.__setattr__(obj, "_data", data)

# Build the buffers RigidObject normally allocates in _initialize_impl
# (_ALL_INDICES, _ALL_*_MASK, pinned CPU staging buffers, wrench buf).
# _create_buffers also instantiates real WrenchComposers; those get
# replaced with mocks just below.
obj._create_buffers()

# Replace the real wrench composers with mocks for iface coverage.
mock_inst_wrench = MockWrenchComposer(obj)
mock_perm_wrench = MockWrenchComposer(obj)
object.__setattr__(obj, "_instantaneous_wrench_composer", mock_inst_wrench)
object.__setattr__(obj, "_permanent_wrench_composer", mock_perm_wrench)

# Prevent __del__ / _clear_callbacks from raising
object.__setattr__(obj, "_initialize_handle", None)
object.__setattr__(obj, "_invalidate_initialize_handle", None)
object.__setattr__(obj, "_prim_deletion_handle", None)
object.__setattr__(obj, "_debug_vis_handle", None)

return obj, mock_bindings


def create_mock_rigid_object(
num_instances: int = 2,
device: str = "cuda:0",
Expand All @@ -226,6 +317,8 @@ def get_rigid_object(
):
if backend == "physx":
return create_physx_rigid_object(num_instances, device)
elif backend == "ovphysx":
return create_ovphysx_rigid_object(num_instances, device)
elif backend == "newton":
return create_newton_rigid_object(num_instances, device)
elif backend.lower() == "mock":
Expand Down
Loading
Loading