diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/__init__.py index 8447486636e5..ced84bce9b3d 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/__init__.py @@ -30,6 +30,17 @@ }, ) +gym.register( + id="Isaac-Velocity-Flat-AnymalD-Camera", + entry_point="isaaclab.envs:ManagerBasedRLEnv", + disable_env_checker=True, + kwargs={ + "env_cfg_entry_point": f"{__name__}.camera_env_cfg:AnymalDFlatCameraEnvCfg", + "rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:AnymalDFlatPPORunnerCfg", + "skrl_cfg_entry_point": f"{agents.__name__}:skrl_flat_ppo_cfg.yaml", + }, +) + gym.register( id="Isaac-Velocity-Rough-AnymalD", entry_point="isaaclab.envs:ManagerBasedRLEnv", diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/camera_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/camera_env_cfg.py new file mode 100644 index 000000000000..2cc758470969 --- /dev/null +++ b/source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/anymal_d/camera_env_cfg.py @@ -0,0 +1,121 @@ +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +"""Anymal-D flat locomotion with a per-environment tiled camera. + +This variant is meant for validating RTX per-environment scene partitioning on a +robot with a *moving base*. Enable partitioning with +``ISAAC_LAB_ENABLE_ISAAC_RTX_PER_ENV_SCENE_PARTITION=1`` and, to preview the Kit +feature that keeps every partition visible to the spectator camera, pass +``--kit_args "--/rtx/scenePartitioning/showPartitionsInBackground=true"``. +""" + +import isaaclab.sim as sim_utils +from isaaclab.managers import ObservationGroupCfg as ObsGroup +from isaaclab.managers import ObservationTermCfg as ObsTerm +from isaaclab.managers import SceneEntityCfg +from isaaclab.sensors import CameraCfg +from isaaclab.utils.configclass import configclass + +import isaaclab_tasks.core.velocity.mdp as mdp +from isaaclab_tasks.core.velocity.velocity_env_cfg import MySceneCfg, ObservationsCfg +from isaaclab_tasks.utils import PresetCfg +from isaaclab_tasks.utils.presets import MultiBackendRendererCfg + +from .flat_env_cfg import AnymalDFlatEnvCfg + +## +# Camera presets +## + + +@configclass +class AnymalDTiledCameraCfg(PresetCfg): + """Per-environment tiled-camera presets, selectable via ``presets=``. + + The camera prim lives under each env root (``/World/envs/env_.*/Camera``), so the + env-root ``primvars:omni:scenePartition`` token (authored only when + ``ISAAC_LAB_ENABLE_ISAAC_RTX_PER_ENV_SCENE_PARTITION=1``) propagates to it and the + render is culled to its own environment. + """ + + @configclass + class BaseAnymalDTiledCameraCfg(CameraCfg): + prim_path: str = "/World/envs/env_.*/Camera" + # Placed behind and slightly above each env origin, looking down +x toward the + # robot's spawn. The robot walks around, so the view intentionally shows the base + # moving within (and potentially out of) its own partition volume. + offset: CameraCfg.OffsetCfg = CameraCfg.OffsetCfg( + pos=(-5.0, 0.0, 1.2), rot=(0.0, 0.0, 0.0, 1.0), convention="world" + ) + data_types: list[str] = [] + spawn: sim_utils.PinholeCameraCfg = sim_utils.PinholeCameraCfg( + focal_length=24.0, focus_distance=400.0, horizontal_aperture=20.955, clipping_range=(0.1, 40.0) + ) + width: int = 128 + height: int = 128 + renderer_cfg: MultiBackendRendererCfg = MultiBackendRendererCfg() + + default = BaseAnymalDTiledCameraCfg(data_types=["rgb"]) + rgb64 = BaseAnymalDTiledCameraCfg(data_types=["rgb"], width=64, height=64) + rgb128 = BaseAnymalDTiledCameraCfg(data_types=["rgb"], width=128, height=128) + rgb256 = BaseAnymalDTiledCameraCfg(data_types=["rgb"], width=256, height=256) + depth128 = BaseAnymalDTiledCameraCfg(data_types=["depth"], width=128, height=128) + rgb = default + + +## +# Scene + observations +## + + +@configclass +class AnymalDCameraSceneCfg(MySceneCfg): + """Anymal-D locomotion scene with a selectable per-env tiled camera.""" + + tiled_camera: AnymalDTiledCameraCfg = AnymalDTiledCameraCfg() + + +@configclass +class AnymalDCameraObservationsCfg(ObservationsCfg): + """Adds a camera observation group so the tiled camera renders every step. + + rsl_rl consumes only the ``policy`` group (``obs_groups = {"actor": ["policy"], + "critic": ["policy"]}``), so this extra group does not alter the locomotion policy; + it only forces the sensor to be read (and thus rendered) each step. + """ + + @configclass + class ImageObsCfg(ObsGroup): + image = ObsTerm( + func=mdp.image, + params={"sensor_cfg": SceneEntityCfg("tiled_camera"), "data_type": "rgb", "normalize": False}, + ) + + def __post_init__(self): + self.enable_corruption = False + self.concatenate_terms = True + + camera: ObsGroup = ImageObsCfg() + + +## +# Environment configuration +## + + +@configclass +class AnymalDFlatCameraEnvCfg(AnymalDFlatEnvCfg): + """Anymal-D flat locomotion with a per-environment tiled camera.""" + + scene: AnymalDCameraSceneCfg = AnymalDCameraSceneCfg(num_envs=4096, env_spacing=10.0) + observations: AnymalDCameraObservationsCfg = AnymalDCameraObservationsCfg() + + def __post_init__(self): + super().__post_init__() + # Widen env spacing so each env's partition bounding volume stays clear of its + # neighbours' as the base moves. Lower this (e.g. back to 2.5) to observe the + # limitation when partitions overlap. + self.scene.env_spacing = 10.0 diff --git a/source/isaaclab_visualizers/isaaclab_visualizers/kit/kit_visualizer.py b/source/isaaclab_visualizers/isaaclab_visualizers/kit/kit_visualizer.py index c87e9a3d9423..f59c0d061af0 100644 --- a/source/isaaclab_visualizers/isaaclab_visualizers/kit/kit_visualizer.py +++ b/source/isaaclab_visualizers/isaaclab_visualizers/kit/kit_visualizer.py @@ -620,7 +620,9 @@ def _apply_viewport_camera_scene_partition(self, usd_stage: Usd.Stage, num_envs: This method is a no-op unless ``ISAAC_LAB_ENABLE_ISAAC_RTX_PER_ENV_SCENE_PARTITION=1``, matching the opt-in behaviour of - :meth:`~isaaclab_physx.renderers.IsaacRtxRenderer.prepare_stage`. + :meth:`~isaaclab_physx.renderers.IsaacRtxRenderer.prepare_stage`. It is also a no-op + when no env subset was resolved (all environments visible), so the viewport camera stays + unpartitioned and keeps seeing the whole scene. """ if not isaac_rtx_per_env_scene_partition_enabled(): @@ -629,6 +631,9 @@ def _apply_viewport_camera_scene_partition(self, usd_stage: Usd.Stage, num_envs: if num_envs <= 0 or self._controlled_camera_path is None: return + if not self._resolved_visible_env_ids: + return + logger.debug( "[KitVisualizer] Per-environment Isaac RTX scene partitioning is enabled" " (ISAAC_LAB_ENABLE_ISAAC_RTX_PER_ENV_SCENE_PARTITION=1)." @@ -636,7 +641,7 @@ def _apply_viewport_camera_scene_partition(self, usd_stage: Usd.Stage, num_envs: self._controlled_camera_path, ) - env_id = self._resolved_visible_env_ids[0] if self._resolved_visible_env_ids else 0 + env_id = self._resolved_visible_env_ids[0] camera_prim = usd_stage.GetPrimAtPath(self._controlled_camera_path) if not camera_prim.IsValid() or not camera_prim.IsA(UsdGeom.Camera): logger.debug(