From d5fcd041a2892d01ff5dd2a1d75bbee95c886776 Mon Sep 17 00:00:00 2001 From: Kelly Guo Date: Thu, 26 Feb 2026 12:31:30 -0800 Subject: [PATCH 1/3] Apply suggestion from @kellyguo11 Signed-off-by: Kelly Guo --- source/isaaclab_teleop/docs/CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/isaaclab_teleop/docs/CHANGELOG.rst b/source/isaaclab_teleop/docs/CHANGELOG.rst index 84fca39109e..89d0f70137f 100644 --- a/source/isaaclab_teleop/docs/CHANGELOG.rst +++ b/source/isaaclab_teleop/docs/CHANGELOG.rst @@ -9,6 +9,7 @@ Fixed * Update Isaac Teleop API usage for querying controller button states. + 0.2.0 (2026-02-24) ~~~~~~~~~~~~~~~~~~~ From 8399d85066b2bb2fde8d91d1a45e162e5bb52b9f Mon Sep 17 00:00:00 2001 From: Hougant Chen Date: Thu, 26 Feb 2026 17:31:33 -0500 Subject: [PATCH 2/3] Fixes crashes when Stop XR is pressed and when Kit is closed while Teleop is running. --- source/isaaclab_teleop/config/extension.toml | 2 +- source/isaaclab_teleop/docs/CHANGELOG.rst | 9 ++++ .../isaaclab_teleop/session_lifecycle.py | 42 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/source/isaaclab_teleop/config/extension.toml b/source/isaaclab_teleop/config/extension.toml index 937a40316fd..812ca070d27 100644 --- a/source/isaaclab_teleop/config/extension.toml +++ b/source/isaaclab_teleop/config/extension.toml @@ -1,6 +1,6 @@ [package] # Semantic Versioning is used: https://semver.org/ -version = "0.3.0" +version = "0.3.1" # Description title = "Isaac Lab Teleop" diff --git a/source/isaaclab_teleop/docs/CHANGELOG.rst b/source/isaaclab_teleop/docs/CHANGELOG.rst index 89d0f70137f..ba664976a44 100644 --- a/source/isaaclab_teleop/docs/CHANGELOG.rst +++ b/source/isaaclab_teleop/docs/CHANGELOG.rst @@ -1,6 +1,15 @@ Changelog --------- +0.3.1 (2026-02-26) +~~~~~~~~~~~~~~~~~~~ + +Fixed +^^^^^ + +* Add cleanup for Isaac Teleop session when Stop XR button is clicked and when Kit is closed. + + 0.3.0 (2026-02-26) ~~~~~~~~~~~~~~~~~~~ diff --git a/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py b/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py index 56e07c8c7e3..7118f2fbcf5 100644 --- a/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py +++ b/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py @@ -81,6 +81,34 @@ def __init__(self, cfg: IsaacTeleopCfg): except (ImportError, ModuleNotFoundError): logger.info("isaacsim.kit.xr.teleop.bridge not available; IsaacTeleop will create its own OpenXR session") + try: + import carb.settings + + # Subscribe to the setting (may not fire when Kit closes; see pre-shutdown below) + self._xr_enabled_subscription = carb.settings.get_settings().subscribe_to_node_change_events( + "/xr/enabled", + self._on_xr_enabled_changed, + ) + except (ImportError, ModuleNotFoundError): + logger.info("carb.settings not available; IsaacTeleop will not be able to detect XR enabled state") + + try: + import omni.kit.app + from carb.eventdispatcher import get_eventdispatcher + + # Subscribe to Kit pre-shutdown so we tear down our session before XRCore + # tears down the OpenXR instance/session (XRCore uses order=0; lowest runs first). + # The /xr/enabled setting often does not fire on close, so this is required. + self._pre_shutdown_subscription = get_eventdispatcher().observe_event( + event_name=omni.kit.app.GLOBAL_EVENT_PRE_SHUTDOWN, + on_event=self._on_pre_shutdown, + observer_name="IsaacTeleop session lifecycle", + order=-100, + ) + except (ImportError, ModuleNotFoundError): + logger.info("omni.kit.app/carb.eventdispatcher not available; IsaacTeleop will not clean up on Kit close") + self._pre_shutdown_subscription = None + @property def is_active(self) -> bool: """Whether the teleop session is currently running.""" @@ -190,6 +218,20 @@ def _on_request_required_extensions(self) -> list[str]: logger.info(f"Required extensions: {required_extensions}") return required_extensions + def _on_xr_enabled_changed(self, item, event_type): + import carb.settings + + enabled = carb.settings.get_settings().get("/xr/enabled") + logger.info(f"XR enabled changed to: {enabled}") + + if not enabled: + self._teardown_dead_session() + + def _on_pre_shutdown(self, _event): + """Called when Kit is closing; run full cleanup since the app is exiting.""" + logger.info("Shutting down IsaacTeleop session due to Kit close") + self.stop() + # ------------------------------------------------------------------ # Deferred session creation # ------------------------------------------------------------------ From 7efa8851305461fef398e5de18b611c73a38938f Mon Sep 17 00:00:00 2001 From: Hougant Chen Date: Fri, 27 Feb 2026 11:32:21 -0500 Subject: [PATCH 3/3] Even though we are already shutting down through this event, ensure unsubscribe from GLOBAL_EVENT_PRE_SHUTDOWN event for completeness. --- source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py b/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py index 7118f2fbcf5..5ed79798691 100644 --- a/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py +++ b/source/isaaclab_teleop/isaaclab_teleop/session_lifecycle.py @@ -107,7 +107,6 @@ def __init__(self, cfg: IsaacTeleopCfg): ) except (ImportError, ModuleNotFoundError): logger.info("omni.kit.app/carb.eventdispatcher not available; IsaacTeleop will not clean up on Kit close") - self._pre_shutdown_subscription = None @property def is_active(self) -> bool: @@ -230,6 +229,8 @@ def _on_xr_enabled_changed(self, item, event_type): def _on_pre_shutdown(self, _event): """Called when Kit is closing; run full cleanup since the app is exiting.""" logger.info("Shutting down IsaacTeleop session due to Kit close") + self._pre_shutdown_subscription.unsubscribe() + self._pre_shutdown_subscription = None self.stop() # ------------------------------------------------------------------