Skip to content

Commit 9305232

Browse files
committed
wip
1 parent a886aa9 commit 9305232

6 files changed

Lines changed: 27 additions & 147 deletions

File tree

source/isaaclab/isaaclab/app/app_launcher.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ def __init__(self, launcher_args: argparse.Namespace | dict | None = None, **kwa
190190
self._sim_experience_file: str # Experience file to load
191191
self._visualizer_max_worlds: int | None # Optional max worlds override for Newton-based visualizers
192192
self._video_enabled: bool # Whether --video recording is enabled
193-
self._video_auto_start_kit: bool # Whether headless video should auto-inject Kit visualizer
194193

195194
# Exposed to train scripts
196195
self.device_id: int # device ID for GPU simulation (defaults to 0)
@@ -869,19 +868,6 @@ def _resolve_viewport_settings(self, launcher_args: dict):
869868
if self._headless and not self._livestream and not self._video_enabled:
870869
self._render_viewport = False
871870

872-
# Auto-start a headless Kit visualizer when recording video without an explicit
873-
# visualizer selection. This ensures app.update() is pumped and camera updates
874-
# can be forwarded from viewer settings.
875-
has_explicit_kit = self._cli_visualizer_explicit and "kit" in set(self._cli_visualizer_types)
876-
self._video_auto_start_kit = (
877-
self._video_enabled
878-
and self._headless
879-
and not self._livestream
880-
and not self._xr
881-
and not self._cli_visualizer_disable_all
882-
and not has_explicit_kit
883-
)
884-
885871
# hide_ui flag
886872
launcher_args["hide_ui"] = False
887873
if self._headless and not self._livestream:
@@ -1101,9 +1087,8 @@ def _load_extensions(self):
11011087
# (no Kit GUI) the AR profile must be enabled programmatically so that
11021088
# the OpenXR session starts without user interaction
11031089
settings.set_bool("/isaaclab/xr/auto_start", self._headless and self._xr)
1104-
# set setting to indicate video recording mode and optional Kit auto-start
1090+
# set setting to indicate video recording mode
11051091
settings.set_bool("/isaaclab/video/enabled", self._video_enabled)
1106-
settings.set_bool("/isaaclab/video/auto_start_kit", self._video_auto_start_kit)
11071092

11081093
# set setting to indicate no RTX sensors are used (set to True when RTX sensor is created)
11091094
settings.set_bool("/isaaclab/render/rtx_sensors", False)

source/isaaclab/isaaclab/sim/simulation_context.py

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ def __init__(self, cfg: SimulationCfg | None = None):
180180
self._has_gui = bool(self.get_setting("/isaaclab/has_gui"))
181181
self._has_offscreen_render = bool(self.get_setting("/isaaclab/render/offscreen"))
182182
self._xr_enabled = bool(self.get_setting("/isaaclab/xr/enabled"))
183-
self._video_auto_start_kit = bool(self.get_setting("/isaaclab/video/auto_start_kit"))
184183
# Note: has_rtx_sensors is NOT cached because it changes when Camera sensors are created
185184
self._pending_camera_view: tuple[tuple[float, float, float], tuple[float, float, float]] | None = None
186185

@@ -345,9 +344,7 @@ def has_offscreen_render(self) -> bool:
345344

346345
def has_active_visualizers(self) -> bool:
347346
"""Return whether any visualizer path is active for rendering/camera control."""
348-
return bool(self.get_setting("/isaaclab/visualizer/types")) or bool(
349-
self.get_setting("/isaaclab/video/auto_start_kit")
350-
)
347+
return bool(self.get_setting("/isaaclab/visualizer/types"))
351348

352349
def can_render_rgb_array(self) -> bool:
353350
"""Return whether rgb-array rendering is currently available."""
@@ -555,26 +552,6 @@ def _resolve_visualizer_cfgs(self) -> list[Any]:
555552
exc,
556553
)
557554

558-
# Headless video auto-start: inject a KitVisualizer when needed so that
559-
# app.update() is pumped and viewer camera updates can be applied in
560-
# rgb-array recording flows.
561-
if self._video_auto_start_kit and not cli_disable_all:
562-
has_kit = any(getattr(cfg, "visualizer_type", None) == "kit" for cfg in resolved)
563-
if not has_kit:
564-
try:
565-
import importlib
566-
567-
mod = importlib.import_module("isaaclab_visualizers.kit")
568-
kit_cfg_cls = getattr(mod, "KitVisualizerCfg")
569-
resolved.append(kit_cfg_cls(headless=True))
570-
logger.info("[SimulationContext] Auto-injecting KitVisualizer for headless video recording.")
571-
except (ImportError, ModuleNotFoundError, AttributeError, TypeError) as exc:
572-
logger.warning(
573-
"[SimulationContext] Headless video could not auto-inject a KitVisualizer: %s. "
574-
"Install isaaclab_visualizers[kit] or pass --visualizer kit.",
575-
exc,
576-
)
577-
578555
return resolved
579556

580557
def initialize_visualizers(self) -> None:
@@ -744,6 +721,7 @@ def render(self, mode: int | None = None) -> None:
744721
"""
745722
self.physics_manager.pre_render()
746723
self.update_visualizers(self.get_rendering_dt())
724+
self._pump_kit_app_if_needed()
747725
self._render_generation += 1
748726

749727
# Call render callbacks
@@ -769,9 +747,6 @@ def update_visualizers(self, dt: float) -> None:
769747
visualizers_to_remove.append(viz)
770748
continue
771749
if viz.is_rendering_paused():
772-
# Keep visualizer event loops responsive while rendering is paused
773-
# so UI controls (e.g. "Resume Rendering") remain interactive.
774-
viz.step(0.0)
775750
continue
776751
while viz.is_training_paused() and viz.is_running():
777752
viz.step(0.0)
@@ -788,6 +763,21 @@ def update_visualizers(self, dt: float) -> None:
788763
except Exception as exc:
789764
logger.error("Error closing visualizer: %s", exc)
790765

766+
def _pump_kit_app_if_needed(self) -> None:
767+
"""Pump Kit app-loop for headless rgb-array rendering when needed."""
768+
if not bool(self.get_setting("/isaaclab/video/enabled")):
769+
return
770+
if not has_kit():
771+
return
772+
if any(viz.pumps_app_update() for viz in self._visualizers):
773+
return
774+
try:
775+
from isaaclab_physx.renderers.isaac_rtx_renderer_utils import ensure_isaac_rtx_render_update
776+
777+
ensure_isaac_rtx_render_update()
778+
except Exception as exc:
779+
logger.debug("[SimulationContext] Skipping Kit app-loop pump in render(): %s", exc)
780+
791781
def update_scene_data_provider(self, force_require_forward: bool = False):
792782
if force_require_forward or self._should_forward_before_visualizer_update():
793783
self.physics_manager.forward()

source/isaaclab/setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"torch>=2.10",
2323
"onnx>=1.18.0", # 1.16.2 throws access violation on Windows
2424
"prettytable==3.3.0",
25-
"munch",
2625
"toml",
2726
# devices
2827
"hidapi==0.14.0.post2",

source/isaaclab/test/sim/test_simulation_context_visualizers.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,22 +136,11 @@ def test_update_visualizers_removes_closed_nonrunning_and_failed(caplog):
136136
assert stopped_viz.close_calls == 1
137137
assert failing_viz.close_calls == 1
138138
assert paused_viz.close_calls == 0
139-
assert paused_viz.step_calls == [0.0]
139+
assert paused_viz.step_calls == []
140140
assert healthy_viz.step_calls == [0.1]
141141
assert any("Error stepping visualizer" in r.message for r in caplog.records)
142142

143143

144-
def test_update_visualizers_keeps_rendering_paused_visualizer_ui_responsive():
145-
provider = _FakeProvider()
146-
paused_viz = _FakeVisualizer(rendering_paused=True)
147-
ctx = _make_context([paused_viz], provider=provider)
148-
149-
ctx.update_visualizers(0.3)
150-
151-
# Rendering-paused visualizers still receive zero-dt ticks to keep UI callbacks alive.
152-
assert paused_viz.step_calls == [0.0]
153-
154-
155144
def test_update_visualizers_handles_training_pause_loop():
156145
provider = _FakeProvider()
157146
viz = _FakeVisualizer(training_paused_steps=1)

source/isaaclab_mimic/isaaclab_mimic/datagen/generation.py

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@
55

66
import asyncio
77
import contextlib
8-
import os
98
import sys
109
import traceback
1110
from typing import Any
1211

1312
import torch
14-
import warp as wp
1513

1614
from isaaclab.envs import ManagerBasedRLMimicEnv
1715
from isaaclab.envs.mdp.recorders.recorders_cfg import ActionStateRecorderManagerCfg
1816
from isaaclab.managers import DatasetExportMode, TerminationTermCfg
1917
from isaaclab.managers.recorder_manager import RecorderManagerBaseCfg
20-
from isaaclab.utils.math import subtract_frame_transforms
2118

2219
from isaaclab_mimic.datagen.data_generator import DataGenerator
2320
from isaaclab_mimic.datagen.datagen_info_pool import DataGenInfoPool
@@ -30,59 +27,6 @@
3027
num_attempts = 0
3128

3229

33-
def _debug_wrist_cam_pose(env: ManagerBasedRLMimicEnv, env_id: int, tag: str, hand_body_idx: int | None):
34-
"""Print wrist camera and hand-link transforms for debugging camera alignment."""
35-
try:
36-
if "wrist_cam" not in env.scene.keys() or "robot" not in env.scene.keys():
37-
print(f"[WRIST_CAM_DEBUG] {tag} env={env_id} missing wrist_cam or robot in scene")
38-
return
39-
40-
wrist_cam = env.scene["wrist_cam"]
41-
robot = env.scene["robot"]
42-
cam_pos = wrist_cam.data.pos_w[env_id].detach().cpu()
43-
cam_quat = wrist_cam.data.quat_w_world[env_id].detach().cpu()
44-
cam_frame = int(wrist_cam.frame[env_id].item()) if wrist_cam.frame.numel() > env_id else -1
45-
live_pos_all, live_quat_all = wrist_cam._view.get_world_poses([env_id])
46-
live_cam_pos = live_pos_all[0].detach().cpu()
47-
live_cam_quat = live_quat_all[0].detach().cpu()
48-
49-
if hand_body_idx is None:
50-
print(
51-
f"[WRIST_CAM_DEBUG] {tag} env={env_id} cam_frame={cam_frame} "
52-
f"cam_pos={cam_pos.tolist()} cam_quat_xyzw={cam_quat.tolist()} "
53-
f"live_cam_pos={live_cam_pos.tolist()} live_cam_quat_xyzw={live_cam_quat.tolist()} "
54-
f"hand_body_idx=None"
55-
)
56-
return
57-
58-
hand_pos = wp.to_torch(robot.data.body_pos_w)[env_id, hand_body_idx].detach().cpu()
59-
hand_quat = wp.to_torch(robot.data.body_quat_w)[env_id, hand_body_idx].detach().cpu()
60-
rel_pos, rel_quat = subtract_frame_transforms(
61-
hand_pos.unsqueeze(0),
62-
hand_quat.unsqueeze(0),
63-
cam_pos.unsqueeze(0),
64-
cam_quat.unsqueeze(0),
65-
)
66-
live_rel_pos, live_rel_quat = subtract_frame_transforms(
67-
hand_pos.unsqueeze(0),
68-
hand_quat.unsqueeze(0),
69-
live_cam_pos.unsqueeze(0),
70-
live_cam_quat.unsqueeze(0),
71-
)
72-
print(
73-
f"[WRIST_CAM_DEBUG] {tag} env={env_id} cam_frame={cam_frame} "
74-
f"cam_pos={cam_pos.tolist()} cam_quat_xyzw={cam_quat.tolist()} "
75-
f"live_cam_pos={live_cam_pos.tolist()} live_cam_quat_xyzw={live_cam_quat.tolist()} "
76-
f"hand_pos={hand_pos.tolist()} hand_quat_xyzw={hand_quat.tolist()} "
77-
f"cam_rel_hand_pos={rel_pos[0].detach().cpu().tolist()} "
78-
f"cam_rel_hand_quat_xyzw={rel_quat[0].detach().cpu().tolist()} "
79-
f"live_cam_rel_hand_pos={live_rel_pos[0].detach().cpu().tolist()} "
80-
f"live_cam_rel_hand_quat_xyzw={live_rel_quat[0].detach().cpu().tolist()}"
81-
)
82-
except Exception as exc:
83-
print(f"[WRIST_CAM_DEBUG] {tag} env={env_id} logging_failed={exc}")
84-
85-
8630
async def run_data_generator(
8731
env: ManagerBasedRLMimicEnv,
8832
env_id: int,
@@ -150,18 +94,6 @@ def env_loop(
15094
global num_success, num_failures, num_attempts
15195
env_id_tensor = torch.tensor([0], dtype=torch.int64, device=env.device)
15296
prev_num_attempts = 0
153-
debug_wrist_cam = os.environ.get("ISAACLAB_DEBUG_WRIST_CAM", "0") == "1"
154-
post_reset_step_counters = [0 for _ in range(env.num_envs)]
155-
hand_body_idx = None
156-
if debug_wrist_cam:
157-
try:
158-
if "robot" in env.scene.keys():
159-
body_ids, _ = env.scene["robot"].find_bodies("panda_hand")
160-
hand_body_idx = int(body_ids[0]) if len(body_ids) > 0 else None
161-
print(f"[WRIST_CAM_DEBUG] enabled=1 hand_body_idx={hand_body_idx}")
162-
except Exception as exc:
163-
print(f"[WRIST_CAM_DEBUG] enabled=1 hand_body_idx_lookup_failed={exc}")
164-
16597
# simulate environment -- run everything in inference mode
16698
with contextlib.suppress(KeyboardInterrupt) and torch.inference_mode():
16799
while True:
@@ -176,11 +108,6 @@ def env_loop(
176108
while not env_reset_queue.empty():
177109
env_id_tensor[0] = env_reset_queue.get_nowait()
178110
env.reset(env_ids=env_id_tensor)
179-
reset_env_id = int(env_id_tensor[0].item())
180-
if 0 <= reset_env_id < env.num_envs:
181-
post_reset_step_counters[reset_env_id] = 0
182-
if debug_wrist_cam:
183-
_debug_wrist_cam_pose(env, reset_env_id, tag="after_reset", hand_body_idx=hand_body_idx)
184111
env_reset_queue.task_done()
185112

186113
actions = torch.zeros(env.action_space.shape)
@@ -191,16 +118,6 @@ def env_loop(
191118

192119
# perform action on environment
193120
env.step(actions)
194-
if debug_wrist_cam:
195-
for env_id in range(env.num_envs):
196-
if post_reset_step_counters[env_id] <= 1:
197-
_debug_wrist_cam_pose(
198-
env,
199-
env_id,
200-
tag=f"after_step_{post_reset_step_counters[env_id]}",
201-
hand_body_idx=hand_body_idx,
202-
)
203-
post_reset_step_counters[env_id] += 1
204121

205122
# mark done so the data generators can continue with the step results
206123
for i in range(env.num_envs):

source/isaaclab_visualizers/isaaclab_visualizers/kit/kit_visualizer.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import logging
1212
from typing import TYPE_CHECKING
1313

14+
import carb
1415
from pxr import UsdGeom
1516

1617
from isaaclab.visualizers.base_visualizer import BaseVisualizer
@@ -109,7 +110,10 @@ def step(self, dt: float) -> None:
109110

110111
app = omni.kit.app.get_app()
111112
if app is not None and app.is_running():
113+
settings = carb.settings.get_settings()
114+
settings.set_bool("/app/player/playSimulations", False)
112115
app.update()
116+
settings.set_bool("/app/player/playSimulations", True)
113117
except (ImportError, AttributeError) as exc:
114118
logger.debug("[KitVisualizer] App update skipped: %s", exc)
115119

@@ -143,15 +147,11 @@ def is_running(self) -> bool:
143147
return False
144148

145149
def is_training_paused(self) -> bool:
146-
"""Return whether Kit timeline transport is paused."""
150+
"""Return whether simulation play flag is paused in Kit settings."""
147151
try:
148-
import omni.timeline
149-
150-
timeline = omni.timeline.get_timeline_interface()
151-
if timeline is None:
152-
return False
153-
# Pause is transport state that is neither playing nor stopped.
154-
return (not timeline.is_playing()) and (not timeline.is_stopped())
152+
settings = carb.settings.get_settings()
153+
play_flag = settings.get("/app/player/playSimulations")
154+
return play_flag is not None and not bool(play_flag)
155155
except Exception:
156156
return False
157157

0 commit comments

Comments
 (0)