Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
556bd81
Fix PhysX rigid-object collection COM and inertia setters
AntoineRichard Sep 29, 2026
0d61d2c
Restructure shared asset tests into a capability-declared contract
AntoineRichard Sep 29, 2026
3bd4e7c
Reduce WrenchComposer tests to literal units and one PhysX delivery test
AntoineRichard Sep 29, 2026
16ac8af
Allow OVPhysX CPU and CUDA simulations in one process
AntoineRichard Sep 29, 2026
4bd517d
Consolidate OVPhysX articulation tests into composite scenes
AntoineRichard Sep 29, 2026
62c52be
Consolidate OVPhysX rigid-object tests into composite scenes
AntoineRichard Sep 29, 2026
feff387
Move OVPhysX asset unit tests under unit
AntoineRichard Sep 29, 2026
cf825d4
Cover partial joint-state writes and the deprecated joint-state writer
AntoineRichard Sep 29, 2026
6eab6fb
Consolidate PhysX articulation tests into one composite scene
AntoineRichard Sep 29, 2026
161cf9f
Consolidate PhysX rigid-object and collection tests into composite sc…
AntoineRichard Sep 29, 2026
994646d
Focus PhysX Newton-actuator tests on backend seams
AntoineRichard Sep 29, 2026
eda3cab
Cover PhysX deformables and surface grippers with local fixtures
AntoineRichard Sep 29, 2026
bde0964
Merge physx asset-test lane
AntoineRichard Sep 29, 2026
874f328
Merge ov asset-test lane
AntoineRichard Sep 29, 2026
59d7a64
Author local fixtures for kitless Newton asset tests
AntoineRichard Sep 29, 2026
10b9844
Rebuild Newton articulation tests on one composite local scene
AntoineRichard Sep 29, 2026
7ec1bc0
Run Newton actuator equivalence on local composite scenes
AntoineRichard Sep 29, 2026
c3ed18b
Run Newton rigid-object tests on persistent local scenes
AntoineRichard Sep 29, 2026
8d797e3
Cover Newton operational-space control on a local chain
AntoineRichard Sep 29, 2026
05cac20
Merge newton asset-test lane
AntoineRichard Sep 29, 2026
9b3baec
Sync with the split asset-test series
AntoineRichard Sep 29, 2026
7ee6184
Sync with the style-aligned asset-test series
AntoineRichard Sep 29, 2026
4fc854c
Sync with the reviewed asset-test series
AntoineRichard Sep 29, 2026
0a0ded2
Simplify asset tests and remove custom test scaffolding
StafaH Oct 2, 2026
ad9b10a
Merge develop and preserve upstream asset regression coverage
StafaH Oct 2, 2026
406fa72
Replace contract capability framework and merge asset contracts
StafaH Oct 2, 2026
b72ab09
Trim Newton asset and controller tests
StafaH Oct 2, 2026
a5aecd6
Trim PhysX asset tests
StafaH Oct 2, 2026
7cd3071
Trim OVPhysX asset, lifecycle, and unit tests
StafaH Oct 2, 2026
3346171
Trim WrenchComposer and actuator runtime tests
StafaH Oct 2, 2026
3647343
Remove device_split runner support
StafaH Oct 2, 2026
61d6e4b
Consolidate asset-test changelog fragments
StafaH Oct 2, 2026
c5c43d5
Merge contract and actuator runtime test files
StafaH Oct 2, 2026
14dc49d
Consolidate Newton asset tests into three files
StafaH Oct 2, 2026
9800f71
Consolidate PhysX asset tests and use local actuator fixtures
StafaH Oct 2, 2026
bd3f555
Consolidate OVPhysX asset tests and share scenes across devices
StafaH Oct 2, 2026
5e13ef9
Drop stale rigid-object-collection test timeout
StafaH Oct 2, 2026
758b8bb
Merge branch 'develop' into antoiner/asset-tests-redesign
StafaH Oct 2, 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
2 changes: 1 addition & 1 deletion .github/actions/run-package-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ inputs:
test-k-expr:
description: >-
Global pytest -k expression applied inside every per-file pytest run
spawned by tools/conftest.py (combined with device-split selectors).
spawned by tools/conftest.py.
default: ''
required: false
test-jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/run-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ inputs:
test-k-expr:
description: >-
Global pytest -k expression applied inside every per-file pytest run
spawned by tools/conftest.py (combined with device-split selectors).
spawned by tools/conftest.py.
Unlike pytest-options, this reaches the individual test processes, so it
can deselect parametrized cases (e.g. "not ovphysx").
default: ''
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tools-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ jobs:

- name: Run tools tests
env:
# The tests import the modules under test (crash_journal, _device_split) directly.
# The tests import the modules under test (crash_journal) directly.
PYTHONPATH: tools
# Files are listed explicitly rather than collected from tools/: test_settings.py is a
# configuration module, not a test, and tools/test/ needs the full Isaac Lab install.
#
# --noconftest keeps tools/conftest.py out of the session. That file is the CI test
# orchestrator - its pytest_sessionstart scans source/ and scripts/ and runs the whole
# suite, so loading it here would ignore the files named below.
run: python3 -m pytest tools/test_crash_journal.py tools/test_device_split.py tools/test_file_scheduler.py
run: python3 -m pytest tools/test_crash_journal.py tools/test_file_scheduler.py
.github/actions/_lib/test_registry_credential_fallback.py -v --noconftest

- uses: astral-sh/setup-uv@v6
Expand Down
2 changes: 1 addition & 1 deletion docs/source/concepts/ovphysx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Then run a small backend smoke test:

.. code-block:: bash

uv run --extra ovphysx --extra test python -m pytest source/isaaclab_ov/test/assets/test_rigid_object.py::test_initialization -k cpu
uv run --extra ovphysx --extra test python -m pytest source/isaaclab_ov/test/assets/test_rigid_object.py::test_rigid_object_real_ovphysx_seams -k cpu

To try a task that declares an OvPhysX physics preset, use the same preset CLI
syntax as the other backends:
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@ ignore-words-list = "aheared,collet,followng,haa,publically,rouines,slq,collapsa

markers = [
"isaacsim_ci: mark test to run in isaacsim ci",
"device_split: re-invoke this file once per device (CPU and GPU) in CI due to process-global device locks (e.g., ovphysx<=0.3.7 gap G5)",
"windows_ci: mark test to run on Windows platforms in CI",
"arm_ci: mark test to run on ARM platforms in CI (e.g. NVIDIA DGX Spark)",
"unit: test exercises isolated logic and does not launch the simulator",
Expand Down
Empty file.
157 changes: 1 addition & 156 deletions source/isaaclab/isaaclab/test/utils/actuator_equivalence.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
* :class:`EquivalenceAssertionsMixin` with the trajectory/telemetry
``test_*_match`` oracles,
* dummy TorchScript checkpoint factories for the neural actuator tests,
* mock scene/env plumbing for driving ``randomize_actuator_gains``,
* :class:`ActuatorStateResetBase` with the per-env actuator state reset
scenario.
* mock scene/env plumbing for driving ``randomize_actuator_gains``.

This module must stay free of backend packages (``isaaclab_newton``,
``isaaclab_physx``) and of ``isaaclab_assets``; everything backend-specific
Expand All @@ -25,11 +23,8 @@
import tempfile

import torch
import warp as wp

from ... import sim as sim_utils
from ...actuators import DCMotorCfg, DelayedPDActuatorCfg, IdealPDActuatorCfg, ImplicitActuatorCfg
from ...sim import SimulationCfg, build_simulation_context

# ---------------------------------------------------------------------------
# Actuator configurations under test
Expand All @@ -44,17 +39,6 @@
),
}

DC_MOTOR_ACTUATORS = {
"legs": DCMotorCfg(
joint_names_expr=[".*HAA", ".*HFE", ".*KFE"],
saturation_effort=120.0,
actuator_effort_limit=80.0,
actuator_velocity_limit=7.5,
stiffness={".*": 40.0},
damping={".*": 5.0},
),
}

MIXED_ACTUATORS = {
"hips": IdealPDActuatorCfg(
joint_names_expr=[".*HAA"],
Expand Down Expand Up @@ -313,142 +297,3 @@ def build_dr_term(env, asset_name, joint_ids=None):
asset_cfg = cfg.params["asset_cfg"]
asset_cfg.finalize(env.device)
return term, asset_cfg


# ---------------------------------------------------------------------------
# Per-env reset: actuator state isolation
# ---------------------------------------------------------------------------


class ActuatorStateResetBase:
"""Reset must clear the actuator state buffers for the requested envs only.

Inspects ``adapter.actuators[i].state.delay_state.num_pushes`` directly:

* After warmup, ``num_pushes > 0`` for every DOF (buffer was populated).
* After ``articulation.reset(env_ids=[0])``, the entries for env 0's DOFs
must be ``0`` and the entries for env 1's DOFs must remain ``> 0``.

Done independently on Lab and Newton paths. Backend-specific twins mix
this into a ``unittest.TestCase`` and provide :meth:`_make_sim_cfg`,
:meth:`_make_articulation`, and :meth:`_get_adapter`.
"""

RESET_ENV: int = 0
UNCHANGED_ENV: int = 1
NUM_ENVS: int = 2
DT: float = 1.0 / 120.0
TARGET_OFFSET: float = 0.1 # [rad] added to initial joint positions
RESET_WARMUP_STEPS: int = 3

def _make_sim_cfg(self, use_newton_actuators: bool) -> SimulationCfg:
"""Return the backend simulation config for the run."""
raise NotImplementedError

def _make_articulation(self):
"""Construct the backend articulation (DelayedPD on all joints) at ``/World/Env_.*/Robot``."""
raise NotImplementedError

def _get_adapter(self, articulation):
"""Return the Newton actuator adapter that owns ``articulation``'s actuators."""
raise NotImplementedError

def _build_and_warm(self, *, use_newton_actuators: bool):
ctx = build_simulation_context(
device="cuda:0",
gravity_enabled=True,
add_ground_plane=True,
sim_cfg=self._make_sim_cfg(use_newton_actuators),
)
sim = ctx.__enter__()
sim._app_control_on_stop_handle = None
for i in range(self.NUM_ENVS):
sim_utils.create_prim(f"/World/Env_{i}", "Xform", translation=(i * 3.0, 0, 0))
articulation = self._make_articulation()
sim.reset()

init_pos = wp.to_torch(articulation.data.joint_pos).clone()
target_pos = init_pos + self.TARGET_OFFSET
target_vel = torch.zeros_like(init_pos)
articulation.set_joint_position_target_index(target=target_pos)
articulation.set_joint_velocity_target_index(target=target_vel)
for _ in range(self.RESET_WARMUP_STEPS):
articulation.write_data_to_sim()
sim.step()
articulation.update(self.DT)
return ctx, sim, articulation

def test_newton_state_reset_isolated_to_reset_env(self):
"""Newton: ``num_pushes`` zeroes for env 0's DOFs only after reset of [0]."""
ctx, sim, articulation = self._build_and_warm(use_newton_actuators=True)
try:
adapter = self._get_adapter(articulation)
self.assertIsNotNone(adapter)
# Find a DelayedPD actuator (it's the only one with delay_state).
stateful_pairs = [
(act, st)
for act, st in zip(adapter.actuators, adapter._states_a)
if st is not None and getattr(st, "delay_state", None) is not None
]
self.assertGreater(len(stateful_pairs), 0, "expected at least one DelayedPD actuator with delay_state")

for act, state in stateful_pairs:
pushes_before = state.delay_state.num_pushes.numpy()
self.assertTrue(
(pushes_before > 0).all(),
"expected non-zero num_pushes for all DOFs after warmup",
)

articulation.reset(env_ids=torch.tensor([self.RESET_ENV], device=articulation.device, dtype=torch.long))

# Map each entry of ``act.indices`` to its env via the adapter's
# per-env DOF count. On the Newton backend the adapter is model-wide
# (includes free-joint DOFs on floating-base articulations); on
# PhysX it is per-articulation — ``adapter.num_joints`` is the
# correct stride in both cases.
for act, state in stateful_pairs:
pushes_after = state.delay_state.num_pushes.numpy()
indices_np = act.indices.numpy()
for i, global_dof in enumerate(indices_np):
env = int(global_dof) // adapter.num_joints
if env == self.RESET_ENV:
self.assertEqual(
int(pushes_after[i]),
0,
f"DOF {i} (env {env}) should be reset to 0, got {pushes_after[i]}",
)
else:
self.assertGreater(
int(pushes_after[i]),
0,
f"DOF {i} (env {env}) was NOT in reset env_ids but num_pushes is 0",
)
finally:
ctx.__exit__(None, None, None)

def test_lab_state_reset_isolated_to_reset_env(self):
"""Reset environments accept fresh commands while the remaining environments retain their history."""
ctx, sim, articulation = self._build_and_warm(use_newton_actuators=False)
try:
commands = articulation.actuators.target_command
old_target = commands.position.torch.clone()
# Episode reset samples the configured lag; construction alone leaves actuator lag at zero.
articulation.reset()
commands.set_position_index(value=old_target)
articulation.write_data_to_sim()
new_target = old_target + 0.02
articulation.reset(env_ids=torch.tensor([self.RESET_ENV], device=articulation.device))
commands.set_position_index(value=new_target)
articulation.write_data_to_sim()
expected_target = old_target.clone()
expected_target[self.RESET_ENV] = new_target[self.RESET_ENV]
for actuator in articulation.actuators.values():
joints = actuator.joint_indices
demand = (
actuator.stiffness * (expected_target[:, joints] - articulation.data.joint_pos.torch[:, joints])
- actuator.damping * articulation.data.joint_vel.torch[:, joints]
)
torch.testing.assert_close(actuator.computed_effort, demand)

finally:
ctx.__exit__(None, None, None)
Loading
Loading