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
71 changes: 71 additions & 0 deletions autodata_examples/envs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Example simulation environments used by AutoData workflows."""

import argparse
from typing import Any


def register_environment_for_run(
*,
env_name: str,
enable_cameras: bool,
num_envs: int,
device: str,
seed: int,
presets: str | None = None,
) -> dict[str, dict[str, Any]]:
"""Register the AutoData-owned environment selected for the current run.

Args:
env_name: Gym ID of the environment selected for this run.
enable_cameras: Whether Arena environments should include their camera sensors.
num_envs: Number of parallel environments in this run.
device: Simulation device for this run.
seed: Environment seed for this run.
presets: Optional Arena physics backend preset; None preserves the environment default.

Returns:
Gym constructor kwargs keyed by registered environment ID.
"""

from .isaac_lab_arena import (
build_and_register_arena_environment,
is_arena_environment,
is_environment_registered_from_callback,
)

if not is_arena_environment(env_name):
return {}
if is_environment_registered_from_callback(env_name):
return {}
return build_and_register_arena_environment(
Comment thread
peterd-NV marked this conversation as resolved.
enable_cameras=enable_cameras,
num_envs=num_envs,
device=device,
seed=seed,
presets=presets,
)


def register_environments() -> list[str]:
"""External callback used by unmodified Isaac Lab scripts.

Isaac Lab invokes this function without arguments after starting Isaac Sim. The
selected ``--task`` determines whether the callback needs to compile an AutoData
Arena environment or only import AutoData's regular Isaac Lab registrations.

Returns:
Command-line arguments not consumed by Arena environment registration.
"""

from .isaac_lab_arena import is_arena_environment, register_environment_from_cli

parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("--task", type=str)
args, _ = parser.parse_known_args()
env_name = args.task.split(":")[-1] if args.task is not None else None
if env_name is not None and not is_arena_environment(env_name):
return []
return register_environment_from_cli()
17 changes: 17 additions & 0 deletions autodata_examples/envs/isaac_lab_arena/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0


from .registration import (
build_and_register_arena_environment,
is_arena_environment,
is_environment_registered_from_callback,
register_environment_from_cli,
)

__all__ = [
"build_and_register_arena_environment",
"is_arena_environment",
"is_environment_registered_from_callback",
"register_environment_from_cli",
]
14 changes: 14 additions & 0 deletions autodata_examples/envs/isaac_lab_arena/franka_rope/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0


from __future__ import annotations

from . import embodiment as _embodiment # noqa: F401
from .environment import FRANKA_ROPE_ARENA_ENV_ID, FrankaRopeArenaEnvironment, FrankaRopeArenaEnvironmentCfg

__all__ = [
"FRANKA_ROPE_ARENA_ENV_ID",
"FrankaRopeArenaEnvironment",
"FrankaRopeArenaEnvironmentCfg",
]
Binary file not shown.
189 changes: 189 additions & 0 deletions autodata_examples/envs/isaac_lab_arena/franka_rope/embodiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0


from __future__ import annotations

from collections.abc import Callable

import isaaclab.envs.mdp as mdp_isaac_lab
import isaaclab.sim as sim_utils
from isaaclab.managers import EventTermCfg as EventTerm
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
from isaaclab_arena.assets.register import register_asset, register_retargeter
from isaaclab_arena.assets.retargeter_library import RetargetterBase
from isaaclab_arena.embodiments.common.arm_mode import ArmMode
from isaaclab_arena.embodiments.franka.franka import FrankaIKEmbodiment
from isaaclab_arena.utils.cameras import ArenaCameraCfg
from isaaclab_arena.utils.pose import Pose
from isaaclab_physx.renderers import IsaacRtxRendererCfg, IsaacRtxRendererGlobalSettingsCfg

from . import mdp

_FRANKA_ROPE_INIT_JOINT_POS: dict[str, float] = {
"panda_joint1": 0.0444,
"panda_joint2": -0.1894,
"panda_joint3": -0.1107,
"panda_joint4": -2.5148,
"panda_joint5": 0.0044,
"panda_joint6": 2.3775,
"panda_joint7": 2.43,
"panda_finger_joint.*": 0.04,
}

_FRANKA_ROPE_INIT_JOINT_POSE = [
0.0444,
-0.1894,
-0.1107,
-2.5148,
0.0044,
2.3775,
2.43,
0.04,
0.04,
]


@configclass
class FrankaRopeCameraCfg(ArenaCameraCfg):
"""Wrist and fixed-view cameras matching the Isaac Lab rope environment."""

robot0_eye_in_hand_image = CameraCfg(
prim_path="{ENV_REGEX_NS}/Robot/panda_hand/robot0_eye_in_hand_image",
update_period=0.0,
height=128,
width=128,
data_types=["rgb"],
renderer_cfg=IsaacRtxRendererCfg(global_settings=IsaacRtxRendererGlobalSettingsCfg(antialiasing_mode="DLSS")),
spawn=sim_utils.PinholeCameraCfg(
focal_length=24.0,
focus_distance=400.0,
horizontal_aperture=20.955,
clipping_range=(0.1, 2.0),
),
offset=CameraCfg.OffsetCfg(
pos=(0.13, 0.0, -0.15),
rot=(0.03701, 0.03701, -0.70614, -0.70614),
convention="ros",
),
)

agentview_image = CameraCfg(
prim_path="{ENV_REGEX_NS}/agentview_image",
update_period=0.0,
height=128,
width=128,
data_types=["rgb"],
renderer_cfg=IsaacRtxRendererCfg(global_settings=IsaacRtxRendererGlobalSettingsCfg(antialiasing_mode="DLSS")),
spawn=sim_utils.PinholeCameraCfg(
focal_length=14.0,
focus_distance=400.0,
horizontal_aperture=20.955,
clipping_range=(0.1, 2.0),
),
offset=CameraCfg.OffsetCfg(
pos=(0.5, 0.5, 0.4),
rot=(0.0, 0.38268, 0.92388, 0.0),
convention="opengl",
),
)


@configclass
class FrankaRopeObservationsCfg:
"""Arena-standard Franka observations plus deformable rope nodal state."""

@configclass
class PolicyCfg(ObsGroup):
"""Policy observations recorded into demonstration datasets."""

actions = ObsTerm(func=mdp_isaac_lab.last_action)
joint_pos = ObsTerm(func=mdp_isaac_lab.joint_pos_rel)
joint_vel = ObsTerm(func=mdp_isaac_lab.joint_vel_rel)
eef_pos = ObsTerm(func=mdp.ee_frame_pos)
eef_quat = ObsTerm(func=mdp.ee_frame_quat)
gripper_pos = ObsTerm(
func=mdp.gripper_pos,
params={"robot_cfg": SceneEntityCfg("robot", joint_names=["panda_finger_joint.*"])},
)
object_nodal_pos = ObsTerm(func=mdp.object_nodal_pos)

def __post_init__(self) -> None:
self.enable_corruption = False
self.concatenate_terms = False

policy: PolicyCfg = PolicyCfg()


@configclass
class FrankaRopeEventsCfg:
"""Reset the Franka exactly as the equivalent Isaac Lab rope environment."""

reset_all = EventTerm(func=mdp_isaac_lab.reset_scene_to_default, mode="reset")
randomize_franka_joint_state = EventTerm(
func=mdp_isaac_lab.reset_joints_by_offset,
mode="reset",
params={
"position_range": (-0.02, 0.02),
"velocity_range": (0.0, 0.0),
"asset_cfg": SceneEntityCfg("robot", joint_names=["panda_joint.*"]),
},
)


@register_asset
class FrankaRopeIKEmbodiment(FrankaIKEmbodiment):
"""Arena Franka IK embodiment with rope-specific pose, observations, and cameras."""

name = "franka_rope_ik"

def __init__(
self,
enable_cameras: bool = False,
initial_pose: Pose | None = None,
concatenate_observation_terms: bool = False,
arm_mode: ArmMode | None = None,
) -> None:
super().__init__(
enable_cameras=enable_cameras,
initial_pose=initial_pose,
initial_joint_pose=list(_FRANKA_ROPE_INIT_JOINT_POSE),
concatenate_observation_terms=concatenate_observation_terms,
arm_mode=arm_mode,
)
self.scene_config.robot.init_state.joint_pos = dict(_FRANKA_ROPE_INIT_JOINT_POS)
self.observation_config = FrankaRopeObservationsCfg()
self.observation_config.policy.concatenate_terms = concatenate_observation_terms
self.camera_config = FrankaRopeCameraCfg()
self.event_config = FrankaRopeEventsCfg()
self.reward_config = None


@register_retargeter
class FrankaRopeKeyboardRetargeter(RetargetterBase):
"""Use the standard relative-pose keyboard pipeline for the rope embodiment."""

device = "keyboard"
embodiment = FrankaRopeIKEmbodiment.name

def get_pipeline_builder(self, embodiment: object) -> Callable | None:
"""Return no custom pipeline; Isaac Lab handles relative-pose keyboard input."""

del embodiment


@register_retargeter
class FrankaRopeSpaceMouseRetargeter(RetargetterBase):
"""Use the standard relative-pose SpaceMouse pipeline for the rope embodiment."""

device = "spacemouse"
embodiment = FrankaRopeIKEmbodiment.name

def get_pipeline_builder(self, embodiment: object) -> Callable | None:
"""Return no custom pipeline; Isaac Lab handles relative-pose SpaceMouse input."""

del embodiment
Loading
Loading