Skip to content

[IsaacLab 3.0.0 Multi-Backend] Visual Logging for Headless Runs#6212

Open
mataylor-nvidia wants to merge 2 commits into
isaac-sim:developfrom
mataylor-nvidia:mt/visual-sensor-logs
Open

[IsaacLab 3.0.0 Multi-Backend] Visual Logging for Headless Runs#6212
mataylor-nvidia wants to merge 2 commits into
isaac-sim:developfrom
mataylor-nvidia:mt/visual-sensor-logs

Conversation

@mataylor-nvidia

@mataylor-nvidia mataylor-nvidia commented Jun 17, 2026

Copy link
Copy Markdown

Description

REQ-12: Support capturing images from the visualizer when running headless such that we can capture the full or subset of environments during training to observe progress through frameworks such as tensorboard or wandb

This feature exports per step frames from simulation from full or subset of the environments.

Fixes # (OMPE-78691)

https://jirasw.nvidia.com/browse/OMPE-78691

Type of change

  • New feature (non-breaking change which adds functionality)

Screenshots

image

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jun 17, 2026
@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces CaptureEnvSensors, a gym.Wrapper that periodically reads image-like sensor outputs from the environment's scene during headless RL training and writes them to TensorBoard or disk. It is wired into all four RL training scripts (rl_games, rsl_rl, sb3, skrl) via a new wrap_sensor_capture helper and exposed through four new CLI arguments.

  • CaptureEnvSensors wrapper (common.py): schedules capture windows via a step % interval < frame_count gate, normalises depth/normals/generic float buffers, and writes NHWC image batches via SummaryWriter.add_images or save_images_to_file.
  • RL training scripts: each adds a single wrap_sensor_capture call between wrap_record_video and the framework-specific vec-env wrapper.
  • Tests (test_reinforcement_learning_common.py): covers scheduling, normalisation, buffer-type handling, and CLI wiring — but the test helper passes "num_envs" instead of the constructor parameter "capture_num_envs", causing the entire test suite to fail with TypeError.

Confidence Score: 3/5

The production wrapper and training-script wiring are correct, but the entire new test file is broken due to a parameter name mismatch and should not be merged as-is.

The core CaptureEnvSensors implementation and its integration into the four training scripts look functionally correct. However, the test helper _make_capture_wrapper passes num_envs to a constructor that expects capture_num_envs, and test_wrap_sensor_capture_uses_training_sensor_frame_directory asserts wrapped_env.num_envs against an attribute stored as wrapped_env.capture_num_envs. Every test that calls this helper will raise a TypeError before any assertion is reached, meaning the stated test coverage does not actually exist at merge time.

source/isaaclab/test/test_reinforcement_learning_common.py — the _make_capture_wrapper helper and one direct assertion use the wrong attribute/parameter name, breaking the full test suite.

Important Files Changed

Filename Overview
scripts/reinforcement_learning/common.py Adds CaptureEnvSensors gym.Wrapper and wrap_sensor_capture helper; logic is sound but _saved_frame_count increments even when no images are written.
source/isaaclab/test/test_reinforcement_learning_common.py Test helper _make_capture_wrapper passes "num_envs" instead of "capture_num_envs", and the assertion on wrapped_env.num_envs also uses the wrong attribute name — every test invoking this helper fails with TypeError/AttributeError.
scripts/reinforcement_learning/rl_games/train_rl_games.py Adds wrap_sensor_capture call after wrap_record_video; wrapper ordering is correct and change is minimal.
scripts/reinforcement_learning/rsl_rl/train_rsl_rl.py Adds wrap_sensor_capture call after wrap_record_video; minimal, correct change.
scripts/reinforcement_learning/sb3/train_sb3.py Adds wrap_sensor_capture call after wrap_record_video; minimal, correct change.
scripts/reinforcement_learning/skrl/train_skrl.py Adds wrap_sensor_capture call after wrap_record_video; minimal, correct change.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant RL as RL Framework
    participant CES as CaptureEnvSensors
    participant RV as RecordVideo
    participant IL as IsaacLab Env

    RL->>CES: step(action)
    CES->>RV: step(action)
    RV->>IL: step(action)
    IL-->>RV: obs, reward, ...
    RV-->>CES: obs, reward, ...
    CES->>CES: "_step_count += 1"
    CES->>CES: _save_frame()
    Note over CES: step_count % interval < frame_count?
    CES->>IL: unwrapped.scene.sensors
    IL-->>CES: sensor dict
    loop each sensor / data_type
        CES->>CES: _to_image_tensor(buffer, data_type)
        alt tensorboard mode
            CES->>CES: writer.add_images(tag, tensor, step)
        else file mode
            CES->>CES: save_images_to_file(tensor, path)
        end
    end
    CES-->>RL: obs, reward, ...
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant RL as RL Framework
    participant CES as CaptureEnvSensors
    participant RV as RecordVideo
    participant IL as IsaacLab Env

    RL->>CES: step(action)
    CES->>RV: step(action)
    RV->>IL: step(action)
    IL-->>RV: obs, reward, ...
    RV-->>CES: obs, reward, ...
    CES->>CES: "_step_count += 1"
    CES->>CES: _save_frame()
    Note over CES: step_count % interval < frame_count?
    CES->>IL: unwrapped.scene.sensors
    IL-->>CES: sensor dict
    loop each sensor / data_type
        CES->>CES: _to_image_tensor(buffer, data_type)
        alt tensorboard mode
            CES->>CES: writer.add_images(tag, tensor, step)
        else file mode
            CES->>CES: save_images_to_file(tensor, path)
        end
    end
    CES-->>RL: obs, reward, ...
Loading

Reviews (1): Last reviewed commit: "visual sensor logs" | Re-trigger Greptile

Comment thread source/isaaclab/test/test_reinforcement_learning_common.py
Comment thread source/isaaclab/test/test_reinforcement_learning_common.py
os.makedirs(os.path.dirname(file_path), exist_ok=True)
save_images_to_file(image_tensor, file_path)

self._saved_frame_count += 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 _saved_frame_count is incremented at the end of every _save_frame call that passes the schedule gate, even when no sensor has image data and nothing was actually written to disk. If an environment has no image sensors, the frame counter still advances on every scheduled step, producing discontinuous frame indices (frame_000000, frame_000002, …) the first time a sensor does become available. Consider incrementing inside the inner loop only when an image is actually written, or resetting the counter to only count real captures.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant