diff --git a/configs/simbox/de_plan_and_render_template.yaml b/configs/simbox/de_plan_and_render_template.yaml index 645bb54..0ad9873 100644 --- a/configs/simbox/de_plan_and_render_template.yaml +++ b/configs/simbox/de_plan_and_render_template.yaml @@ -10,6 +10,7 @@ load_stage: rendering_dt: 1/30 # Render update rate stage_units_in_meters: 1.0 # Stage unit scale headless: True # Headless mode (no GUI); set false for visual debugging + renderer: "PathTracing" # PathTracing: higher quality, less noise on Blackwell anti_aliasing: 0 # Anti-aliasing level layout_random_generator: # Scene randomization type: env_randomizer diff --git a/launcher.py b/launcher.py index 7c9deb3..600c639 100644 --- a/launcher.py +++ b/launcher.py @@ -5,6 +5,41 @@ from nimbus.utils.utils import init_env init_env() +# Patch scipy.spatial.transform module so that `from_quat` and `as_quat` +# accept `scalar_first=` on older scipy (< 1.11). +try: + from scipy.spatial.transform import Rotation as _R + _R.from_quat([1, 0, 0, 0], scalar_first=True) +except TypeError: + import numpy as _np + import scipy.spatial.transform as _sst + from scipy.spatial.transform import Rotation as _OrigR + + class Rotation(_OrigR): + @classmethod + def from_quat(cls, quat, *args, scalar_first=False, **kwargs): + quat = _np.asarray(quat, dtype=float) + if scalar_first: + if quat.ndim == 1: + quat = _np.array([quat[1], quat[2], quat[3], quat[0]]) + else: + quat = _np.concatenate([quat[..., 1:], quat[..., :1]], axis=-1) + return super().from_quat(quat, *args, **kwargs) + + def as_quat(self, *args, scalar_first=False, **kwargs): + q = super().as_quat(*args, **kwargs) + if scalar_first: + if q.ndim == 1: + q = _np.array([q[3], q[0], q[1], q[2]]) + else: + q = _np.concatenate([q[..., 3:], q[..., :3]], axis=-1) + return q + + _sst.Rotation = Rotation + import sys + sys.modules['scipy.spatial.transform._rotation'].Rotation = Rotation + sys.modules['scipy.spatial.transform'].Rotation = Rotation + import argparse from nimbus import run_data_engine diff --git a/nimbus_extension/components/load/env_loader.py b/nimbus_extension/components/load/env_loader.py index a774232..3531de3 100644 --- a/nimbus_extension/components/load/env_loader.py +++ b/nimbus_extension/components/load/env_loader.py @@ -60,7 +60,10 @@ class EnvLoader(SceneLoader): if isinstance(rendering_dt, str): rendering_dt = float(Fraction(rendering_dt)) - from isaacsim import SimulationApp + try: + from isaacsim import SimulationApp # IS 5.x + except ImportError: + from omni.isaac.kit import SimulationApp # IS 4.x self.simulation_app = SimulationApp( { diff --git a/workflows/simbox/core/tasks/banana.py b/workflows/simbox/core/tasks/banana.py index 805cc4b..97844be 100644 --- a/workflows/simbox/core/tasks/banana.py +++ b/workflows/simbox/core/tasks/banana.py @@ -63,6 +63,17 @@ class BananaBaseTask(BaseTask): self._defaultFluidPath = Sdf.Path("/World/task_0/fulid") def set_up_scene(self, scene: Scene) -> None: + # Skip re-initialization if scene is already set up (repeated reset() calls) + if getattr(self, '_scene_initialized', False): + self._task_objects = {} + self._task_objects |= ( + getattr(self, 'fixtures', {}) | + getattr(self, 'objects', {}) | + getattr(self, 'robots', {}) | + getattr(self, 'cameras', {}) + ) + return + self._scene_initialized = True super().set_up_scene(scene) self._set_envmap() self.cfg = update_scenes(self.cfg) diff --git a/workflows/simbox/core/utils/collision_utils.py b/workflows/simbox/core/utils/collision_utils.py index 432e3dc..333bea6 100644 --- a/workflows/simbox/core/utils/collision_utils.py +++ b/workflows/simbox/core/utils/collision_utils.py @@ -27,6 +27,11 @@ def filter_collisions( # We invert the collision group filters for more efficient collision filtering across environments physx_scene.CreateInvertCollisionGroupFilterAttr().Set(True) + # Clean up existing collision groups before re-creating (handles repeated reset() calls) + collision_prim = stage.GetPrimAtPath(collision_root_path) + if collision_prim.IsValid(): + stage.RemovePrim(collision_root_path) + UsdGeom.Scope.Define(stage, collision_root_path) with Sdf.ChangeBlock(): diff --git a/workflows/simbox_dual_workflow.py b/workflows/simbox_dual_workflow.py index e683107..7b8e9b6 100644 --- a/workflows/simbox_dual_workflow.py +++ b/workflows/simbox_dual_workflow.py @@ -45,6 +45,7 @@ class SimBoxDualWorkFlow(NimbusWorkFlow): self.scene_info = scene_info self.step_replay = False self.random_seed = random_seed + self._arena_file_path = None super().__init__(world, task_cfg_path) def parse_task_cfgs(self, task_cfg_path: str) -> list: @@ -76,7 +77,8 @@ class SimBoxDualWorkFlow(NimbusWorkFlow): set_camera_view(eye=[1.3, 0.7, 2.7], target=[0.0, 0, 1.5], camera_prim_path="/OmniverseKit_Persp") # Modify config - arena_file_path = self.task_cfg.get("arena_file", None) + arena_file_path = self.task_cfg.get("arena_file", None) or self._arena_file_path + self._arena_file_path = arena_file_path with open(arena_file_path, "r", encoding="utf-8") as arena_file: arena = yaml.load(arena_file, Loader=Loader) @@ -113,9 +115,13 @@ class SimBoxDualWorkFlow(NimbusWorkFlow): physx_interface = acquire_physx_interface() physx_interface.overwrite_gpu_setting(1) - self.task = get_task_cls(self.task_cfg["task"])(self.task_cfg) + if not hasattr(self, "task") or self.task is None: + self.task = get_task_cls(self.task_cfg["task"])(self.task_cfg) + else: + self.task.cfg = self.task_cfg self.stage = self.world.stage self.stage.SetDefaultPrim(self.stage.GetPrimAtPath("/World")) + self.world._current_tasks.clear() self.world.add_task(self.task) # # Add hidden ground plane for physics simulation