Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions compass/residual_rl/residual_ppo_trainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def __init__(self,
debug_viz=False,
max_debug_images=2,
debug_image_interval=10,
debug_image_step=0):
debug_image_step=0,
save_debug_viewport_images=False):
# Prepare log directory. exist_ok=True avoids a TOCTOU race when several
# torchrun ranks check + create concurrently.
os.makedirs(output_dir, exist_ok=True)
Expand Down Expand Up @@ -128,6 +129,7 @@ def __init__(self,
# Save one rollout step every `debug_image_interval` iterations.
self.debug_image_interval = debug_image_interval
self.debug_image_step = debug_image_step
self.save_debug_viewport_images = save_debug_viewport_images

self.env.reset()

Expand Down Expand Up @@ -583,9 +585,9 @@ def _upload_video(self, iteration):
# Video generation can be slower than this function call, so add one iteration
# delay for video upload.
target_iteration = iteration - 1
target_video_path = os.path.join(
self.output_dir, 'videos',
f'rl-video-step-{target_iteration*self.num_steps_per_env}.mp4')
video_step = target_iteration * self.num_steps_per_env
target_video_path = os.path.join(self.output_dir, 'videos', 'robot_camera',
f'rl-video-step-{video_step}.mp4')
print(target_video_path)
if os.path.exists(target_video_path):
self.logger.log_video(name="episode_video",
Expand Down Expand Up @@ -726,7 +728,8 @@ def _save_debug_images(self, obs_dict, iteration, step):
image_path=grid_image_path,
step=iteration)

self._save_debug_viewport_image(iteration, step)
if self.save_debug_viewport_images:
self._save_debug_viewport_image(iteration, step)

except (KeyError, IOError, OSError, ValueError, RuntimeError, AttributeError) as e:
print(f"Warning: Failed to save debug images: {e}")
Expand Down
41 changes: 20 additions & 21 deletions compass/rl_env/exts/mobility_es/mobility_es/config/nurec_scenes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import isaaclab.sim as sim_utils
from isaaclab.assets import AssetBaseCfg

from compass.utils.nurec_utils import NUREC_SCENE_NAMES
from mobility_es.config.environments import EnvSceneAssetCfg, OMAP_PATHS, USD_PATHS

_USD_DIR = os.path.join(os.path.dirname(__file__), "../usd")
Expand Down Expand Up @@ -50,23 +49,37 @@ def _make_prim_leaf(scene_name: str) -> str:
"omap_file": "occupancy_map_with_sim_objects.yaml",
},
}
NUREC_SCENES = [
NurecScene(scene_name, _make_prim_leaf(scene_name), **NUREC_SCENE_OVERRIDES.get(scene_name, {}))
for scene_name in NUREC_SCENE_NAMES
]


def _make_nurec_scene_asset_cfg(scene: NurecScene, usd_file: str) -> EnvSceneAssetCfg:
def _make_nurec_scene(scene_name: str, omap_file: str | None = None) -> NurecScene:
"""Build NuRec scene metadata from a scene folder name."""
overrides = dict(NUREC_SCENE_OVERRIDES.get(scene_name, {}))
if omap_file is not None:
overrides["omap_file"] = omap_file
return NurecScene(scene_name, _make_prim_leaf(scene_name), **overrides)


def make_nurec_scene_asset_cfg(scene_name: str,
usd_file: str,
omap_file: str | None = None) -> EnvSceneAssetCfg:
"""Build the shared :class:`EnvSceneAssetCfg` for a NuRec Real2Sim scene."""
scene = _make_nurec_scene(scene_name, omap_file)
usd_dir = os.path.join(_USD_DIR, scene.folder)
usd_path = os.path.join(usd_dir, usd_file)
omap_path = os.path.join(usd_dir, scene.omap_file)
USD_PATHS[scene.prim_leaf] = usd_path
OMAP_PATHS[scene.prim_leaf] = {
"path": omap_path,
"origin_convention": scene.origin_convention,
}
return EnvSceneAssetCfg(
prim_path="{ENV_REGEX_NS}/" + scene.prim_leaf,
init_state=AssetBaseCfg.InitialStateCfg(
pos=(0, 0, 0.01),
rot=(0.0, 0.0, 0.0, 1.0),
),
spawn=sim_utils.UsdFileCfg(
usd_path=os.path.join(usd_dir, usd_file),
usd_path=usd_path,
scale=(1.0, 1.0, 1.0),
rigid_props=sim_utils.RigidBodyPropertiesCfg(
disable_gravity=None,
Expand All @@ -76,17 +89,3 @@ def _make_nurec_scene_asset_cfg(scene: NurecScene, usd_file: str) -> EnvSceneAss
),
env_spacing=scene.env_spacing,
)


def make_nurec_scene_asset_cfg_map(usd_file: str) -> dict[str, EnvSceneAssetCfg]:
"""Register NuRec paths and build scene configs keyed by ``--environment``."""
envs = {}
for scene in NUREC_SCENES:
usd_dir = os.path.join(_USD_DIR, scene.folder)
USD_PATHS[scene.prim_leaf] = os.path.join(usd_dir, usd_file)
OMAP_PATHS[scene.prim_leaf] = {
"path": os.path.join(usd_dir, scene.omap_file),
"origin_convention": scene.origin_convention,
}
envs[scene.folder] = _make_nurec_scene_asset_cfg(scene, usd_file)
return envs
11 changes: 0 additions & 11 deletions compass/rl_env/exts/mobility_es/mobility_es/config/scene_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from isaaclab.sensors import CameraCfg, TiledCameraCfg
from isaaclab.sensors.camera.camera_isp import CameraISPMode
from isaaclab.terrains import TerrainImporterCfg
from isaaclab_physx.renderers import IsaacRtxRendererCfg, IsaacRtxRendererGlobalSettingsCfg

# Terrain
terrain = TerrainImporterCfg(
Expand All @@ -41,16 +40,6 @@
width=512,
data_types=["rgb", "depth"],
isp_cfg=CameraISPMode.AUTO_ANY,
renderer_cfg=IsaacRtxRendererCfg(global_settings=IsaacRtxRendererGlobalSettingsCfg(
enable_dl_denoiser=True,
antialiasing_mode="DLSS",
carb_settings={
"/rtx/rtpt/gaussian/skipTonemapping/enabled": False,
"/rtx/rtpt/gaussian/accumulatedDepth/allHits/enabled": True,
"/rtx/rtpt/gaussian/accumulatedAlbedo/enabled": True,
"/rtx/rtpt/gaussian/maxGaussiansToAccumulate": 360,
},
)),
spawn=sim_utils.PinholeCameraCfg(focal_length=10.0,
focus_distance=400.0,
horizontal_aperture=20.955,
Expand Down
18 changes: 16 additions & 2 deletions compass/utils/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
"""

import os
import re
from typing import Dict, Any, Optional

import wandb
from tensorboardX import SummaryWriter

_ARTIFACT_COMPONENT_PATTERN = re.compile(r"[^A-Za-z0-9_.-]+")


class Logger:
"""
Expand Down Expand Up @@ -70,6 +73,16 @@ def __init__(self,

print(f"Logger initialized with backend: {self.backend}")

@staticmethod
def _sanitize_artifact_component(value: str) -> str:
"""Convert a run name into a W&B artifact-name-safe component."""
sanitized = _ARTIFACT_COMPONENT_PATTERN.sub("-", value).strip("._-")
return sanitized or "run"

def _run_scoped_artifact_name(self, name: str) -> str:
run_name = self._sanitize_artifact_component(self.experiment_name)
return f"{name}_{run_name}"

def log_image(self, name: str, image_path: str, step: Optional[int] = None):
"""
Log an image.
Expand Down Expand Up @@ -136,13 +149,14 @@ def log_artifact(self,
type: Type of the artifact
description: Description of the artifact
"""
artifact_name = self._run_scoped_artifact_name(name)
if self.backend == "wandb":
artifact = wandb.Artifact(name=name, type=type, description=description)
artifact = wandb.Artifact(name=artifact_name, type=type, description=description)
artifact.add_file(artifact_path)
wandb.log_artifact(artifact)
else:
# TensorBoard doesn't support artifacts directly
print(f"Artifacts not supported in TensorBoard. Artifact '{name}' not logged.")
print(f"Artifacts not supported in TensorBoard. Artifact '{artifact_name}' not logged.")

def log_config(self, config: Dict[str, Any]):
"""
Expand Down
Loading
Loading