Skip to content
Open
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
21 changes: 20 additions & 1 deletion source/isaaclab_contrib/isaaclab_contrib/rl/rlinf/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,26 @@ def make_env_isaaclab() -> tuple:
isaac_env_cfg.scene.num_envs = self.cfg.init_params.num_envs

env = gym.make(self.isaaclab_env_id, cfg=isaac_env_cfg, render_mode="rgb_array").unwrapped

_original_reset = env.reset

import omni.kit.app

_app = omni.kit.app.get_app()

def _patched_reset(*args, **kwargs):
obs, extras = _original_reset(*args, **kwargs)
env.sim.set_setting("/app/player/playSimulations", False)
_app.update()
env.sim.set_setting("/app/player/playSimulations", True)
for sensor in env.scene.sensors.values():
sensor.update(dt=0.0, force_recompute=True)
obs = env.observation_manager.compute(update_history=True)
env.obs_buf = obs
return obs, extras

env.reset = _patched_reset

return env, sim_app

return make_env_isaaclab
Expand All @@ -481,7 +501,6 @@ def _wrap_obs(self, obs: dict) -> dict:
- ``"extra_view_images"``: ``(B, N, H, W, C)`` — stacked extra cameras.
- ``"states"``: ``(B, D)`` — concatenated state vector.
- ``"task_descriptions"``: ``list[str]`` — task descriptions.

Config is read from the YAML file via :func:`_get_isaaclab_cfg`.

Args:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 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

"""Configuration for Install Trocar task with G129 + Dex3 robot.

This module registers the Install Trocar task in IsaacLab's gymnasium registry,
allowing it to be discovered and used through IsaacLab's standard task interfaces.
"""

import gymnasium as gym

##
# Register Gym environments.
##


gym.register(
id="Isaac-Assemble-Trocar-G129-Dex3-v0",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
kwargs={
"env_cfg_entry_point": f"{__name__}.g129_dex3_env_cfg:G1AssembleTrocarEnvCfg",
},
disable_env_checker=True,
)

gym.register(
id="Isaac-Assemble-Trocar-G129-Dex3-Eval-v0",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
kwargs={
"env_cfg_entry_point": f"{__name__}.g129_dex3_env_cfg:G1AssembleTrocarEvalEnvCfg",
},
disable_env_checker=True,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 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

from .camera_config import CameraBaseCfg, CameraPresets
from .robot_config import G1RobotPresets

__all__ = ["G1RobotPresets", "CameraBaseCfg", "CameraPresets"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# 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

"""
public camera configuration
include the basic configuration for different types of cameras, support scene-specific parameter customization
"""

from collections.abc import Sequence

import isaaclab.sim as sim_utils
from isaaclab.sensors import CameraCfg, TiledCameraCfg
from isaaclab.utils import configclass


@configclass
class CameraBaseCfg:
"""camera base configuration class

provide the default configuration for different types of cameras, support scene-specific parameter customization
"""

@classmethod
def get_camera_config(
cls,
prim_path: str = "/World/envs/env_.*/Robot/d435_link/front_cam",
update_period: float = 0.02,
height: int = 480,
width: int = 640,
focal_length: float = 7.6,
focus_distance: float = 400.0,
horizontal_aperture: float = 20.0,
clipping_range: tuple[float, float] = (0.1, 1.0e5),
pos_offset: tuple[float, float, float] = (0.0, 0.0, 0.0),
rot_offset: tuple[float, float, float, float] = (0.5, -0.5, 0.5, -0.5),
data_types: Sequence[str] | None = None,
) -> CameraCfg:
"""Get a pinhole camera configuration.

Args:
prim_path: the path of the camera in the scene
update_period: update period (seconds)
height: image height (pixels)
width: image width (pixels)
focal_length: focal length
focus_distance: focus distance
horizontal_aperture: horizontal aperture
clipping_range: clipping range (near clipping plane, far clipping plane)
pos_offset: position offset (x, y, z)
rot_offset: rotation offset quaternion
data_types: data type list

Returns:
CameraCfg: camera configuration
"""
if data_types is None:
data_types = ("rgb",)

return TiledCameraCfg(
prim_path=prim_path,
update_period=update_period,
height=height,
width=width,
data_types=list(data_types),
spawn=sim_utils.PinholeCameraCfg(
focal_length=focal_length,
focus_distance=focus_distance,
horizontal_aperture=horizontal_aperture,
clipping_range=clipping_range,
),
offset=TiledCameraCfg.OffsetCfg(pos=pos_offset, rot=rot_offset, convention="ros"),
)


@configclass
class CameraPresets:
"""camera preset configuration collection

include the common camera configuration preset for different scenes
"""

@classmethod
def g1_front_camera(cls, **overrides) -> CameraCfg:
params = {
"height": 224,
"width": 224,
"focal_length": 10.5,
"horizontal_aperture": 14.25, # Match original vertical FOV after crop
}
params.update(overrides)
return CameraBaseCfg.get_camera_config(**params)

@classmethod
def left_dex3_wrist_camera(cls, **overrides) -> CameraCfg:
"""left wrist camera configuration"""
params = {
"prim_path": "/World/envs/env_.*/Robot/left_hand_camera_base_link/left_wrist_camera",
"height": 224,
"width": 224,
"update_period": 0.02,
"data_types": ["rgb"],
"focal_length": 12.0,
"focus_distance": 400.0,
"horizontal_aperture": 14.25, # Match original vertical FOV after crop
"clipping_range": (0.1, 1.0e5),
"pos_offset": (-0.04012, -0.07441, 0.15711),
"rot_offset": (0.00539, 0.86024, 0.0424, 0.50809),
}
params.update(overrides)
return CameraBaseCfg.get_camera_config(**params)

@classmethod
def right_dex3_wrist_camera(cls, **overrides) -> CameraCfg:
"""right wrist camera configuration"""
params = {
"prim_path": "/World/envs/env_.*/Robot/right_hand_camera_base_link/right_wrist_camera",
"height": 224,
"width": 224,
"update_period": 0.02,
"data_types": ["rgb"],
"focal_length": 12.0,
"focus_distance": 400.0,
"horizontal_aperture": 14.25, # Match original vertical FOV after crop
"clipping_range": (0.1, 1.0e5),
"pos_offset": (-0.04012, 0.07441, 0.15711),
"rot_offset": (0.00539, 0.86024, 0.0424, 0.50809),
}
params.update(overrides)
return CameraBaseCfg.get_camera_config(**params)
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# 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

"""GR00T data configuration for IsaacLab tasks.

This module defines customizable GR00T data configurations for different
embodiments. Users can create their own data config classes by subclassing
BaseDataConfig or copying/modifying the examples here.

Example usage in run.sh:
export RLINF_DATA_CONFIG="policy.gr00t_config"
export RLINF_DATA_CONFIG_CLASS="policy.gr00t_config:IsaacLabDataConfig"
"""

from gr00t.data.dataset import ModalityConfig
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.

will these imports get picked up as well if we are not running this task? we want to make sure users are not forced to install gr00t if they don't need to run this particular task

Copy link
Copy Markdown
Contributor Author

@mingxueg-nv mingxueg-nv Mar 30, 2026

Choose a reason for hiding this comment

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

Hi, @kellyguo11 , the config/__init__.py only imports camera_config and robot_config, gr00t_config.py is not reachable through any import chain. This module is only loaded at runtime when RLinf resolves the string gr00t_config:IsaacLabDataConfig from the YAML config, so users who don't run this task will not trigger the gr00t import. For users running this task, we provide required installation step in the RLinf setup docs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the explanation! Confirmed — config/__init__.py only imports camera_config and robot_config, so gr00t_config.py is indeed not reachable through any static import chain. The lazy-loading via RLinf string resolution (gr00t_config:IsaacLabDataConfig) keeps the gr00t dependency isolated to users who actually run this task. LGTM on this point.

from gr00t.data.transform.base import ComposedModalityTransform
from gr00t.data.transform.concat import ConcatTransform
from gr00t.data.transform.state_action import StateActionSinCosTransform, StateActionToTensor, StateActionTransform
from gr00t.data.transform.video import VideoColorJitter, VideoToNumpy, VideoToTensor
from gr00t.experiment.data_config import DATA_CONFIG_MAP, BaseDataConfig
from gr00t.model.transforms import GR00TTransform


class IsaacLabDataConfig(BaseDataConfig):
"""Generic GR00T data config for IsaacLab tasks with G1 + Dex3."""

# Video modality keys (from gr00t_mapping.video in RLINF_OBS_MAP_JSON)
video_keys = [
"video.left_wrist_view",
"video.right_wrist_view",
"video.room_view",
]

# State modality keys (from gr00t_mapping.state in RLINF_OBS_MAP_JSON)
state_keys = [
"state.left_arm",
"state.right_arm",
"state.left_hand",
"state.right_hand",
]

# Action modality keys (output from GR00T model)
action_keys = [
"action.left_arm",
"action.right_arm",
"action.left_hand",
"action.right_hand",
]

# Language annotation key
language_keys = ["annotation.human.task_description"]

# Observation and action indices
observation_indices = [0]
action_indices = list(range(16))

def modality_config(self) -> dict[str, ModalityConfig]:
"""Define modality configurations for video, state, action, and language."""
video_modality = ModalityConfig(
delta_indices=self.observation_indices,
modality_keys=self.video_keys,
)

state_modality = ModalityConfig(
delta_indices=self.observation_indices,
modality_keys=self.state_keys,
)

action_modality = ModalityConfig(
delta_indices=self.action_indices,
modality_keys=self.action_keys,
)

language_modality = ModalityConfig(
delta_indices=self.observation_indices,
modality_keys=self.language_keys,
)

return {
"video": video_modality,
"state": state_modality,
"action": action_modality,
"language": language_modality,
}

def transform(self):
"""Define the transform pipeline for processing observations and actions."""
transforms = [
# Video transforms
VideoToTensor(apply_to=self.video_keys),
# Disabled: camera already outputs 224×224 via TiledCameraCfg.
# To avoid VideoToTensor size-check errors, either:
# 1. Disable input size validation in VideoToTensor, OR
# 2. Set modality meta height/width to 224 to match actual input.
# Re-enable VideoCrop/VideoResize if camera resolution changes.
# VideoCrop(apply_to=self.video_keys, scale=0.95),
# VideoResize(
# apply_to=self.video_keys,
# height=224,
# width=224,
# interpolation="linear",
# ),
VideoColorJitter(
apply_to=self.video_keys,
brightness=0.3,
contrast=0.4,
saturation=0.5,
hue=0.08,
),
VideoToNumpy(apply_to=self.video_keys),
# State transforms
StateActionToTensor(apply_to=self.state_keys),
StateActionSinCosTransform(apply_to=self.state_keys),
# Action transforms
StateActionToTensor(apply_to=self.action_keys),
StateActionTransform(
apply_to=self.action_keys,
normalization_modes={key: "min_max" for key in self.action_keys},
),
# Concat transforms
ConcatTransform(
video_concat_order=self.video_keys,
state_concat_order=self.state_keys,
action_concat_order=self.action_keys,
),
# Model-specific transform
GR00TTransform(
state_horizon=len(self.observation_indices),
action_horizon=len(self.action_indices),
max_state_dim=64,
max_action_dim=32,
),
]
return ComposedModalityTransform(transforms=transforms)


# --------------------------------------------------------------------------
# Register data configs into GR00T's DATA_CONFIG_MAP
# --------------------------------------------------------------------------

# This allows load_data_config("policy.gr00t_config:IsaacLabDataConfig") to work
DATA_CONFIG_MAP["isaaclab_g1_dex3"] = IsaacLabDataConfig()
Loading
Loading