Skip to content

Commit fb1aecd

Browse files
committed
more code improvements and fixes
1 parent a94c807 commit fb1aecd

16 files changed

Lines changed: 296 additions & 257 deletions

File tree

apps/isaaclab.python.headless.kit

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ log.outputStreamLevel = "Warn"
2323
# Omniverse related dependencies #
2424
##################################
2525
[dependencies]
26+
"omni.physics" = {}
27+
"omni.physics.stageupdate" = {}
2628
"omni.physx" = {}
2729
"omni.physx.tensors" = {}
2830
"omni.physx.fabric" = {}

apps/isaaclab.python.kit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ keywords = ["experience", "app", "usd"]
6060
"omni.kit.window.stage" = {}
6161
"omni.kit.window.status_bar" = {}
6262
"omni.kit.window.toolbar" = {}
63+
"omni.physics" = {}
6364
"omni.physics.stageupdate" = {}
6465
"omni.physx" = {}
6566
"omni.physx.tensors" = {}

docs/source/migration/migrating_to_isaaclab_3-0.rst

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2256,7 +2256,7 @@ replacement, prefer the Isaac Lab API** over the ``isaacsim.core.experimental.*`
22562256
* - ``isaacsim.core.utils.semantics``
22572257
- :mod:`isaaclab.sim.utils.semantics`
22582258
* - ``isaacsim.core.utils.extensions.enable_extension``
2259-
- ``isaacsim.core.experimental.utils.app.enable_extension`` (no Isaac Lab equivalent)
2259+
- :func:`isaaclab.sim.utils.enable_extension`
22602260
* - ``isaacsim.core.utils.viewports.set_camera_view``
22612261
- ``isaacsim.core.rendering_manager.ViewportManager.set_camera_view`` (or
22622262
``omni.kit.viewport.utility.camera_state.ViewportCameraState`` for lower-level control)
@@ -2287,6 +2287,32 @@ To keep call-site code symmetric across backends when migrating off
22872287
# or, for the Newton backend
22882288
from isaaclab_newton.physics import NewtonManager as SimulationManager
22892289
2290+
Isaac Sim extension modules must be explicitly enabled before direct import
2291+
-----------------------------------------------------------------------------
2292+
2293+
Isaac Lab 3.0 no longer automatically initializes Isaac Sim extensions only to
2294+
make their Python modules importable. Stock Isaac Lab Kit experiences now load a
2295+
smaller set of extensions so unused Isaac Sim packages do not pull in
2296+
unnecessary dependencies or deprecated aliases.
2297+
2298+
If your project imports an Isaac Sim extension module directly, enable the
2299+
extension after the Kit application has started and before importing from that
2300+
module:
2301+
2302+
.. code-block:: python
2303+
2304+
from isaaclab.sim.utils import enable_extension
2305+
2306+
enable_extension("isaacsim.core.experimental.prims")
2307+
from isaacsim.core.experimental.prims import XformPrim
2308+
2309+
This is especially important for migration replacements such as
2310+
``isaacsim.core.experimental.*`` and ``isaacsim.sensors.experimental.*``. Do not
2311+
import ``enable_extension`` from ``isaacsim.core.experimental.utils.app`` unless
2312+
that extension is already enabled; use :func:`isaaclab.sim.utils.enable_extension`
2313+
from Isaac Lab instead. The helper requires a running Kit application and raises
2314+
``RuntimeError`` if called from plain Python before Kit is launched.
2315+
22902316

22912317
Kit experience (``.kit``) updates
22922318
---------------------------------
@@ -2300,6 +2326,10 @@ If you maintain a custom Kit experience derived from one of the Isaac Lab apps u
23002326
* **Switch explicit Isaac Sim extension dependencies** to the non-deprecated equivalents
23012327
listed above (``isaacsim.core.experimental.*``, ``isaacsim.sensors.experimental.*``,
23022328
``isaacsim.robot.experimental.wheeled_robots``).
2329+
* **Do not rely on stock Isaac Lab apps to preload Isaac Sim extensions** that your
2330+
project imports directly. Either add those extensions to your custom ``.kit`` file
2331+
or enable them with :func:`isaaclab.sim.utils.enable_extension` before importing
2332+
their Python modules.
23032333
* **Remove unused Isaac Sim extensions that pull in** ``isaacsim.core.api`` — Isaac Lab
23042334
no longer depends on those, and keeping them resurrects the deprecated stack.
23052335

scripts/tutorials/04_sensors/run_ray_caster_camera.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@
3636
"""Rest everything follows."""
3737

3838
import os
39+
from typing import Any
3940

4041
import torch
4142

42-
import omni.replicator.core as rep
43-
4443
import isaaclab.sim as sim_utils
4544
from isaaclab.sensors.ray_caster import RayCasterCamera, RayCasterCameraCfg, patterns
4645
from isaaclab.utils import convert_dict_to_backend
@@ -98,9 +97,14 @@ def run_simulator(sim: sim_utils.SimulationContext, scene_entities: dict):
9897
# extract entities for simplified notation
9998
camera: RayCasterCamera = scene_entities["camera"]
10099

101-
# Create replicator writer
102-
output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "output", "ray_caster_camera")
103-
rep_writer = rep.BasicWriter(output_dir=output_dir, frame_padding=3)
100+
# Create the Replicator writer only when saving. The ray-cast camera itself
101+
# is Warp-based and does not require Replicator or RTX rendering extensions.
102+
rep_writer: Any | None = None
103+
if args_cli.save:
104+
import omni.replicator.core as rep
105+
106+
output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "output", "ray_caster_camera")
107+
rep_writer = rep.BasicWriter(output_dir=output_dir, frame_padding=3)
104108

105109
# Set pose: There are two ways to set the pose of the camera.
106110
# -- Option-1: Set pose using view
@@ -142,6 +146,7 @@ def run_simulator(sim: sim_utils.SimulationContext, scene_entities: dict):
142146
rep_output["annotators"][key] = {"render_product": {"data": data}}
143147
# Save images
144148
rep_output["trigger_outputs"] = {"on_time": camera.frame[camera_index]}
149+
assert rep_writer is not None
145150
rep_writer.write(rep_output)
146151

147152
# Pointcloud in world frame

skills/user/migrate-2x-to-3x/SKILL.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: isaaclab-migrating-2x-to-3x
3-
description: Migrates Isaac Lab 2.x projects to Isaac Lab 3.0 by routing agents through the official migration guide, current source APIs, and focused compatibility checks. Use when users mention Isaac Lab 3.0 migration, 2.x projects, quaternion order changes, ProxyArray data access, backend migration, or visualization CLI changes.
3+
description: Migrates Isaac Lab 2.x projects to Isaac Lab 3.0 by routing agents through the official migration guide, current source APIs, and focused compatibility checks. Use when users mention Isaac Lab 3.0 migration, 2.x projects, quaternion order changes, ProxyArray data access, backend migration, Isaac Sim extension imports, or visualization CLI changes.
44
audience: user
55
status: experimental
66
owners:
@@ -18,11 +18,17 @@ Do not copy migration tables into answers from memory. Read the official migrati
1818
## Workflow
1919

2020
1. Read the official migration guide in `docs/source/migration/migrating_to_isaaclab_3-0.rst`.
21-
2. Identify which migration area applies: visualization CLI, backend packages, schema cfgs, quaternion order, `ProxyArray`, asset views, RSL-RL config, or project-specific scripts.
21+
2. Identify which migration area applies: visualization CLI, backend packages, schema cfgs, quaternion order, `ProxyArray`, asset views, RSL-RL config, Isaac Sim extension enablement, or project-specific scripts.
2222
3. Search the downstream project for old API symbols before editing.
23-
4. Apply the smallest focused migration change.
24-
5. Run a targeted smoke test or import test.
25-
6. If the official docs are missing a recurring migration issue, update `docs/source/migration/migrating_to_isaaclab_3-0.rst` instead of expanding this skill with standalone documentation.
23+
4. For user code that imports Isaac Sim extension modules directly:
24+
- Prefer an Isaac Lab in-tree API when the migration guide lists one.
25+
- If the direct Isaac Sim import is still needed, add `from isaaclab.sim.utils import enable_extension` and call `enable_extension("<extension_name>")` after the Kit application starts and before the first import from that extension.
26+
- Do not import `enable_extension` from `isaacsim.core.experimental.utils.app`; that module may not be importable until its extension is already enabled.
27+
- For custom `.kit` files, either list every direct Isaac Sim extension dependency explicitly or enable each extension before importing its Python module.
28+
- Do not add extension enables to plain Python modules that can be imported before Kit starts unless the code is guarded so it runs only inside a launched Kit app.
29+
5. Apply the smallest focused migration change.
30+
6. Run a targeted smoke test or import test. For direct Isaac Sim imports, use an app-launched command such as `./isaaclab.sh -p -m pytest PATH_TO_TEST` or a script that starts `AppLauncher` before enabling extensions.
31+
7. If the official docs are missing a recurring migration issue, update `docs/source/migration/migrating_to_isaaclab_3-0.rst` instead of expanding this skill with standalone documentation.
2632

2733
## Validation
2834

source/isaaclab/changelog.d/fix-controller-extension-enable.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Added
44
* Added :func:`isaaclab.sim.enable_extension`, :func:`isaaclab.sim.disable_extension`, and
55
:func:`isaaclab.sim.get_extension_path` for interacting with Kit extensions without Isaac Sim utility dependencies.
66

7+
Changed
8+
^^^^^^^
9+
10+
* Changed the stock Kit experiences to stop registering deprecated Isaac Sim extension aliases and deprecated extension
11+
search paths. Custom Kit experiences should depend on current ``isaacsim.*`` or ``omni.*`` extensions directly.
12+
713
Fixed
814
^^^^^
915

source/isaaclab_physx/isaaclab_physx/__init__.py

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,149 @@
66
"""Package containing the PhysX simulation interfaces for IsaacLab core package."""
77

88
import importlib.metadata
9-
10-
from ._simulation_manager_patch import _SimulationManagerPatch
9+
import sys
10+
from contextlib import suppress
11+
from types import ModuleType
12+
from typing import Any
1113

1214
try:
1315
__version__ = importlib.metadata.version("isaaclab_physx")
1416
except importlib.metadata.PackageNotFoundError:
1517
__version__ = "0.0.0"
1618

19+
_SIMULATION_MANAGER_ENABLE_HOOK: Any | None = None
20+
21+
22+
def _patch_isaacsim_simulation_manager(enable_if_available: bool = False) -> None:
23+
"""Patch Isaac Sim's ``SimulationManager`` to use :class:`PhysxManager`.
24+
25+
This redirects future ``from isaacsim.core.simulation_manager import SimulationManager``
26+
consumers to :class:`isaaclab_physx.physics.PhysxManager`, but the original
27+
Isaac Sim ``SimulationManager`` class has *already* registered timeline
28+
(PLAY/STOP) and stage (OPENED/CLOSED) subscriptions during its extension
29+
startup. Those subscriptions live on the original class, not the module
30+
attribute, so swapping the attribute alone is not enough.
31+
32+
Starting with Isaac Sim 6.0.0-alpha.180 (commit ``8df6beeb0`` on
33+
``develop``, "hmazhar/autofix_bugs"), the original
34+
``SimulationManager._on_stop``/``_on_play``/``_on_stage_*`` methods were
35+
decorated with ``@staticmethod`` so they finally fire correctly from the
36+
Carb event subscriptions. Before that fix they were silently broken (the
37+
subscriptions invoked them as bound methods, so the ``event`` argument was
38+
being passed as ``self``/``cls`` and the bodies never executed).
39+
40+
The newly-working ``_on_stop`` calls
41+
``SimulationManager.invalidate_physics()``, which calls
42+
``view.invalidate()`` on its ``omni.physics.tensors`` simulation view.
43+
Because ``omni.physics.tensors.create_simulation_view("warp", stage_id=...)``
44+
returns the same underlying SimulationView per stage_id, that invalidation
45+
also wrecks the view that :class:`PhysxManager` (and any articulation
46+
``_root_view`` derived from it) relies on. The result is the runtime error
47+
``Simulation view object is invalidated and cannot be used again to call
48+
getDofVelocities`` on the very first ``scene.update()`` after
49+
``sim.reset()``.
50+
51+
To prevent this, we disable the original class's default callbacks here
52+
*before* swapping the module attribute, so :class:`PhysxManager` becomes
53+
the single owner of the simulation lifecycle.
54+
55+
This function is intentionally lazy. Config loading may import
56+
:mod:`isaaclab_physx` before Kit has launched; in that case, there is no app
57+
interface and no Isaac Sim callbacks to patch yet.
58+
59+
When ``enable_if_available`` is set, :meth:`PhysxManager.initialize` asks Kit
60+
to enable the extension before Isaac Lab creates PhysX tensor views. This
61+
prevents later optional Isaac Sim imports (for example from a controller or
62+
gripper utility) from starting the original manager after our tensor views
63+
exist and invalidating them during its startup reset.
64+
"""
65+
if enable_if_available:
66+
_subscribe_to_simulation_manager_enable()
67+
_enable_isaacsim_simulation_manager_if_available()
68+
69+
original_module = sys.modules.get("isaacsim.core.simulation_manager")
70+
if original_module is None:
71+
return
72+
73+
from .physics.physx_manager import IsaacEvents, PhysxManager
74+
75+
# Tear down the original Isaac Sim SimulationManager's default timeline /
76+
# stage subscriptions so they cannot invalidate the omni.physics.tensors
77+
# view that PhysxManager owns. ``enable_all_default_callbacks(False)``
78+
# covers warm_start (PLAY), on_stop (STOP), stage_open (OPENED) and
79+
# stage_close (CLOSED). Older Isaac Sim builds may not expose this API, so
80+
# fall back gracefully.
81+
original_class = _get_original_simulation_manager_class(original_module, PhysxManager)
82+
if original_class is not None and original_class is not PhysxManager:
83+
try:
84+
original_class.enable_all_default_callbacks(False)
85+
except Exception:
86+
# Defensive: API changed or original class never finished startup.
87+
# Manually clear the subscription handles if they exist so any
88+
# remaining references go through the dead-callback path.
89+
for attr in (
90+
"_default_callback_warm_start",
91+
"_default_callback_on_stop",
92+
"_default_callback_stage_open",
93+
"_default_callback_stage_close",
94+
):
95+
if hasattr(original_class, attr):
96+
setattr(original_class, attr, None)
97+
98+
original_module.SimulationManager = PhysxManager
99+
original_module.IsaacEvents = IsaacEvents
100+
101+
102+
def _get_original_simulation_manager_class(original_module: ModuleType, physx_manager: type) -> type | None:
103+
"""Return Isaac Sim's implementation class, including after a module-level patch."""
104+
original_class = getattr(original_module, "SimulationManager", None)
105+
if original_class is not physx_manager:
106+
return original_class
107+
108+
implementation_module = sys.modules.get("isaacsim.core.simulation_manager.impl.simulation_manager")
109+
return getattr(implementation_module, "SimulationManager", None)
110+
111+
112+
def _get_kit_extension_manager() -> Any | None:
113+
"""Return Kit's extension manager when Kit is running."""
114+
try:
115+
import omni.kit.app # noqa: PLC0415
116+
except Exception:
117+
return None
118+
119+
with suppress(RuntimeError):
120+
app = omni.kit.app.get_app()
121+
return app.get_extension_manager()
122+
return None
123+
124+
125+
def _subscribe_to_simulation_manager_enable() -> None:
126+
"""Patch Isaac Sim's manager if it is enabled after PhysxManager starts."""
127+
global _SIMULATION_MANAGER_ENABLE_HOOK
128+
if _SIMULATION_MANAGER_ENABLE_HOOK is not None:
129+
return
130+
131+
extension_manager = _get_kit_extension_manager()
132+
if extension_manager is None:
133+
return
134+
135+
_SIMULATION_MANAGER_ENABLE_HOOK = extension_manager.subscribe_to_extension_enable(
136+
on_enable_fn=lambda _: _patch_isaacsim_simulation_manager(),
137+
on_disable_fn=lambda _: None,
138+
ext_name="isaacsim.core.simulation_manager",
139+
hook_name="isaaclab_physx simulation manager lifecycle patch",
140+
)
17141

18-
_simulation_manager_patch = _SimulationManagerPatch()
19142

143+
def _enable_isaacsim_simulation_manager_if_available() -> None:
144+
"""Enable Isaac Sim's manager before PhysxManager creates tensor views."""
145+
extension_manager = _get_kit_extension_manager()
146+
if extension_manager is None:
147+
return
20148

21-
def _patch_isaacsim_simulation_manager() -> None:
22-
"""Patch Isaac Sim's ``SimulationManager`` to use Isaac Lab's PhysX manager."""
23-
_simulation_manager_patch.claim_physics_lifecycle()
149+
with suppress(Exception):
150+
if not extension_manager.is_extension_enabled("isaacsim.core.simulation_manager"):
151+
extension_manager.set_extension_enabled_immediate("isaacsim.core.simulation_manager", True)
24152

25153

26154
_patch_isaacsim_simulation_manager()

0 commit comments

Comments
 (0)