├── .dockerignore ├── mypy.ini ├── pytest.ini ├── .editorconfig ├── docs ├── images │ ├── franka_kitchen.png │ ├── kitchen_gr1_arena.gif │ ├── simulation_view.png │ ├── task_duplications.png │ ├── variation_axis.png │ ├── franka_kitchen_pickup.gif │ ├── gr1_open_microwave_task_view.png │ ├── isaac_lab_arena_arch_overview.png │ ├── isaaclab_arena_core_framework.png │ ├── cloud_xr_sessions_control_panel.png │ ├── g1_galileo_arena_box_pnp_locomanip.gif │ └── g1_locomanip_pick_and_place_task_view.png ├── requirements.txt ├── _redirect │ └── index.html ├── _static │ └── custom.css ├── README.md ├── Makefile ├── _templates │ └── versioning.html ├── helpers.py └── pages │ ├── advanced │ └── private_omniverse.rst │ ├── references │ └── release_notes.rst │ ├── quickstart │ ├── installation.rst │ └── docker_containers.rst │ └── concepts │ ├── concept_environment_design.rst │ ├── concept_overview.rst │ └── concept_teleop_devices_design.rst ├── isaaclab_arena ├── tests │ ├── test_data │ │ ├── test_demo_gr1_open_microwave.hdf5 │ │ ├── test_g1_hdf5_to_lerobot.hdf5 │ │ ├── test_g1_locomanip_lerobot │ │ │ ├── meta │ │ │ │ ├── tasks.jsonl │ │ │ │ └── episodes.jsonl │ │ │ ├── data │ │ │ │ └── chunk-000 │ │ │ │ │ └── episode_000000.parquet │ │ │ ├── videos │ │ │ │ └── chunk-000 │ │ │ │ │ └── observation.images.ego_view │ │ │ │ │ └── episode_000000.mp4 │ │ │ ├── test_g1_locomanip_replay_action_config.yaml │ │ │ ├── test_g1_locomanip_gr00t_closedloop_config.yaml │ │ │ └── test_g1_locomanip_config.yaml │ │ └── test_gr1_manip_lerobot │ │ │ ├── data │ │ │ └── chunk-000 │ │ │ │ └── episode_000000.parquet │ │ │ ├── meta │ │ │ ├── tasks.jsonl │ │ │ ├── episodes.jsonl │ │ │ └── modality.json │ │ │ ├── videos │ │ │ └── chunk-000 │ │ │ │ └── observation.images.ego_view │ │ │ │ └── episode_000000.mp4 │ │ │ └── test_gr1_manip_replay_action_config.yaml │ ├── __init__.py │ ├── utils │ │ ├── __init__.py │ │ ├── simulation.py │ │ └── constants.py │ ├── test_pose.py │ ├── test_simulation_app_context.py │ ├── test_object_configuration.py │ ├── test_affordance_base.py │ ├── test_usd_pose_helpers.py │ ├── policy │ │ ├── test_replay_lerobot_action_policy.py │ │ └── test_convert_hdf5_to_lerobot.py │ ├── test_configclass.py │ ├── test_device_registry.py │ └── test_camera_observation.py ├── __init__.py ├── cli │ ├── __init__.py │ └── isaaclab_arena_cli.py ├── assets │ ├── __init__.py │ ├── asset.py │ ├── register.py │ ├── background.py │ └── object_utils.py ├── examples │ ├── __init__.py │ ├── README.md │ ├── example_env_notebook.py │ └── compile_env_notebook.py ├── metrics │ ├── __init__.py │ ├── metric_base.py │ ├── recorder_manager_utils.py │ └── success_rate.py ├── policy │ ├── __init__.py │ ├── zero_action_policy.py │ ├── policy_base.py │ └── replay_action_policy.py ├── scene │ └── __init__.py ├── scripts │ └── __init__.py ├── tasks │ ├── __init__.py │ ├── dummy_task.py │ └── task_base.py ├── terms │ ├── __init__.py │ ├── articulations.py │ └── events.py ├── utils │ ├── __init__.py │ ├── isaaclab_utils │ │ ├── __init__.py │ │ └── resets.py │ ├── math.py │ ├── phyx_utils.py │ ├── singleton.py │ ├── reload_modules.py │ ├── usd_pose_helpers.py │ ├── pose.py │ └── joint_utils.py ├── affordances │ ├── __init__.py │ ├── affordance_base.py │ └── pressable.py ├── environments │ ├── __init__.py │ ├── isaaclab_arena_environment.py │ └── isaaclab_arena_manager_based_env.py ├── orchestrator │ ├── __init__.py │ └── orchestrator_base.py ├── embodiments │ ├── common │ │ ├── __init__.py │ │ ├── mimic_arm_mode.py │ │ └── mimic_utils.py │ ├── franka │ │ ├── __init__.py │ │ └── observations.py │ ├── g1 │ │ └── __init__.py │ ├── gr1t2 │ │ └── __init__.py │ └── __init__.py └── teleop_devices │ ├── __init__.py │ ├── teleop_device_base.py │ ├── keyboard.py │ ├── spacemouse.py │ └── avp_handtracking.py ├── .github ├── LICENSE_HEADER.txt ├── pull_request_template.md └── workflows │ └── gh-pages.yml ├── isaaclab_arena_g1 ├── __init__.py ├── g1_env │ ├── __init__.py │ ├── mdp │ │ ├── __init__.py │ │ ├── actions │ │ │ ├── __init__.py │ │ │ ├── g1_decoupled_wbc_joint_action_cfg.py │ │ │ └── g1_decoupled_wbc_pink_action_cfg.py │ │ └── g1_events.py │ └── config │ │ ├── __init__.py │ │ ├── lab_g1_joints_order_43dof.yaml │ │ └── loco_manip_g1_joints_order_43dof.yaml └── g1_whole_body_controller │ ├── __init__.py │ └── wbc_policy │ ├── __init__.py │ ├── config │ ├── __init__.py │ ├── g1_homie_v2.yaml │ └── configs.py │ ├── policy │ ├── __init__.py │ ├── policy_constants.py │ ├── identity_policy.py │ ├── action_constants.py │ ├── base.py │ └── wbc_policy_factory.py │ ├── utils │ ├── __init__.py │ ├── homie_utils.py │ └── g1.py │ └── g1_wbc_upperbody_ik │ ├── __init__.py │ └── solver.py ├── isaaclab_arena_gr00t ├── __init__.py ├── config │ ├── __init__.py │ ├── g1 │ │ ├── __init__.py │ │ ├── info.json │ │ ├── 43dof_joint_space.yaml │ │ └── gr00t_43dof_joint_space.yaml │ ├── gr1 │ │ ├── __init__.py │ │ ├── info.json │ │ ├── modality.json │ │ ├── gr00t_26dof_joint_space.yaml │ │ ├── 36dof_joint_space.yaml │ │ └── 54dof_joint_space.yaml │ ├── gr1_manip_config.yaml │ └── g1_locomanip_config.yaml ├── data_utils │ ├── __init__.py │ ├── robot_joints.py │ ├── image_conversion.py │ └── robot_eef_pose.py ├── g1_locomanip_replay_action_config.yaml ├── gr1_manip_replay_action_config.yaml ├── g1_locomanip_gr00t_closedloop_config.yaml └── gr1_manip_gr00t_closedloop_config.yaml ├── isaaclab_arena_environments ├── __init__.py ├── example_environment_base.py └── press_button_environment.py ├── .gitmodules ├── .gitattributes ├── .vscode ├── launch.json └── settings.json ├── extension.toml ├── setup.py ├── README.md ├── .flake8 ├── .gitignore ├── docker └── setup │ ├── install_gr00t_deps.sh │ ├── install_cuda.sh │ └── entrypoint.sh ├── CONTRIBUTING.md ├── pyproject.toml └── .pre-commit-config.yaml /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.mypy_cache 2 | **/__pycache__ 3 | /.git 4 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | mypy_path=submodules/IsaacLab/source/isaaclab 3 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | markers = 3 | with_cameras: test requires enable_cameras=True 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | tab_width = 4 7 | -------------------------------------------------------------------------------- /docs/images/franka_kitchen.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6069f2aa9f1f4b27c7cca3dbd7725666a03b05c4fdc41300481006ad7477f809 3 | size 820756 4 | -------------------------------------------------------------------------------- /docs/images/kitchen_gr1_arena.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:070bbaec8a0a75729e0858e29e68554fe98d01375dfca00bcddd445c4a9b2b54 3 | size 7578923 4 | -------------------------------------------------------------------------------- /docs/images/simulation_view.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:19046ff6500f2881f07e5a9fd4bb18b9f6212ca66f5eaa2b126a2aa402dcabdf 3 | size 138641 4 | -------------------------------------------------------------------------------- /docs/images/task_duplications.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:b124f4925ba6eb62789fa4258b459b6e8d38d6391ee3e9d1238f0d43a1abf653 3 | size 120697 4 | -------------------------------------------------------------------------------- /docs/images/variation_axis.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:41ab7d764b9cc90e3a81e6d1ec8e9610519e8ca963d2d27163bef0a52ee37ea5 3 | size 4278762 4 | -------------------------------------------------------------------------------- /docs/images/franka_kitchen_pickup.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d5f7d411ad844e89103e88243eeb1ca53ff70ed0c3cea6605b81ab0aeecb0663 3 | size 16802526 4 | -------------------------------------------------------------------------------- /docs/images/gr1_open_microwave_task_view.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:27f20922006d1c6083d21f09d09c379102f90b15d7e88026e72fece6f076ef41 3 | size 514226 4 | -------------------------------------------------------------------------------- /docs/images/isaac_lab_arena_arch_overview.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2f6e30e1fe551d975590abcebb8288341dc363c35f29c50f6bffe2f73a0f0b9e 3 | size 177376 4 | -------------------------------------------------------------------------------- /docs/images/isaaclab_arena_core_framework.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:af1cbbc800899851ecd0cc13a80f4c6be3fcf0eed0f72fbbc9b4f2e5e689aac9 3 | size 155129 4 | -------------------------------------------------------------------------------- /docs/images/cloud_xr_sessions_control_panel.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d55507ad476da7aaf70649a92c6bc23942f5ab4033b5c6aff78ddc7becdfe4b6 3 | size 61319 4 | -------------------------------------------------------------------------------- /docs/images/g1_galileo_arena_box_pnp_locomanip.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c4f51be5a3d37810bba5728271f2083c5fb82d7140faa82cf985aa42d7de7c75 3 | size 26572037 4 | -------------------------------------------------------------------------------- /docs/images/g1_locomanip_pick_and_place_task_view.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:b12dc7bb795a468293be5baa71c86ce5c67075d19f1bebde17975ebf9c35891b 3 | size 784531 4 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_demo_gr1_open_microwave.hdf5: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:154ebea7839ec53e6ac441e18f1404b3fe140c3f004ad7e309519ba37274fa50 3 | size 365180 4 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_hdf5_to_lerobot.hdf5: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:96f57fd12f334c93e834975a1095aa8fdbfd1313a190dc9a5441dabee342ebe9 3 | size 230249655 4 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==8.2.3 2 | sphinx-multiversion==0.2.4 3 | sphinx_copybutton==0.5.2 4 | sphinx_tabs==3.4.7 5 | nvidia-sphinx-theme==0.0.8 6 | snowballstemmer==2.2.0 7 | setuptools 8 | sphinx_design==0.6.1 9 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/meta/tasks.jsonl: -------------------------------------------------------------------------------- 1 | {"task_index": 2, "task": "Pick up the brown box from the shelf, and place it into the blue bin on the table located at the right of the shelf."} 2 | -------------------------------------------------------------------------------- /.github/LICENSE_HEADER.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | All rights reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | Short description of the change (max 50 chars) 3 | 4 | ## Detailed description 5 | - What was the reason for the change? 6 | - What has been changed? 7 | - What is the impact of this change? 8 | -------------------------------------------------------------------------------- /isaaclab_arena/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/cli/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/data/chunk-000/episode_000000.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacLab-Arena/HEAD/isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/data/chunk-000/episode_000000.parquet -------------------------------------------------------------------------------- /isaaclab_arena_g1/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/assets/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/examples/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/metrics/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/policy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/scene/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tasks/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/terms/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/data/chunk-000/episode_000000.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacLab-Arena/HEAD/isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/data/chunk-000/episode_000000.parquet -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/meta/episodes.jsonl: -------------------------------------------------------------------------------- 1 | {"episode_index": 0, "tasks": ["Pick up the brown box from the shelf, and place it into the blue bin on the table located at the right of the shelf."], "length": 852} 2 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/affordances/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/environments/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/orchestrator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_environments/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/mdp/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/IsaacLab"] 2 | path = submodules/IsaacLab 3 | url = git@github.com:isaac-sim/IsaacLab.git 4 | [submodule "submodules/Isaac-GR00T"] 5 | path = submodules/Isaac-GR00T 6 | url = git@github.com:NVIDIA/Isaac-GR00T.git 7 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/common/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/franka/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/g1/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/gr1t2/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/config/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/g1/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/data_utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/isaaclab_utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/mdp/actions/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/meta/tasks.jsonl: -------------------------------------------------------------------------------- 1 | {"task_index": 0, "task": "Pick up the red beaker and pour the contents into the yellow bowl. Then, drop the red beaker into the blue bin. Lastly, place the yellow bowl onto the white scale."} 2 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /docs/_redirect/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirecting to the latest Isaac Lab Arena documentation 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/config/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/policy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/meta/episodes.jsonl: -------------------------------------------------------------------------------- 1 | {"episode_index": 0, "tasks": ["Pick up the red beaker and pour the contents into the yellow bowl. Then, drop the red beaker into the blue bin. Lastly, place the yellow bowl onto the white scale."], "length": 152} 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.hdf5 filter=lfs diff=lfs merge=lfs -text 2 | *.png filter=lfs diff=lfs merge=lfs -text 3 | *.tar filter=lfs diff=lfs merge=lfs -text 4 | *.zst filter=lfs diff=lfs merge=lfs -text 5 | *.gif filter=lfs diff=lfs merge=lfs -text 6 | docs/images/ filter=lfs diff=lfs merge=lfs -text 7 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/videos/chunk-000/observation.images.ego_view/episode_000000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacLab-Arena/HEAD/isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/videos/chunk-000/observation.images.ego_view/episode_000000.mp4 -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/g1_wbc_upperbody_ik/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/videos/chunk-000/observation.images.ego_view/episode_000000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacLab-Arena/HEAD/isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/videos/chunk-000/observation.images.ego_view/episode_000000.mp4 -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from .franka.franka import * 7 | from .g1.g1 import * 8 | from .gr1t2.gr1t2 import * 9 | -------------------------------------------------------------------------------- /isaaclab_arena/teleop_devices/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from .avp_handtracking import * 7 | from .keyboard import * 8 | from .spacemouse import * 9 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/policy/policy_constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | """Constants for the WBC policy.""" 7 | 8 | G1_NUM_JOINTS = 43 9 | NUM_NAVIGATE_CMD = 3 10 | NUM_BASE_HEIGHT_CMD = 1 11 | NUM_TORSO_ORIENTATION_RPY_CMD = 3 12 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/math.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | 8 | 9 | def normalize_value(value: torch.Tensor, min_value: float, max_value: float): 10 | return (value - min_value) / (max_value - min_value) 11 | 12 | 13 | def unnormalize_value(value: float, min_value: float, max_value: float): 14 | return min_value + (max_value - min_value) * value 15 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/g1/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "codebase_version": "v2.1", 3 | "robot_type": null, 4 | "total_episodes": null, 5 | "total_frames": null, 6 | "total_tasks": null, 7 | "total_videos": null, 8 | "total_chunks": null, 9 | "chunks_size": 1000, 10 | "fps": null, 11 | "splits": { 12 | "train": "0:100" 13 | }, 14 | "data_path": "data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet", 15 | "video_path": "videos/chunk-{episode_chunk:03d}/{video_key}/episode_{episode_index:06d}.mp4", 16 | "features": null 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | 5 | { 6 | "name": "Attach to debugpy session", 7 | "type": "debugpy", 8 | "request": "attach", 9 | "connect": { 10 | "host": "localhost", 11 | "port": 5678 12 | }, 13 | "pathMappings": [ 14 | { 15 | "localRoot": "${workspaceFolder}", 16 | "remoteRoot": "/workspaces/isaac_arena" 17 | } 18 | ] 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/phyx_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from pxr import PhysxSchema, Usd 7 | 8 | 9 | def add_contact_report(prim: Usd.Prim) -> None: 10 | """Add a contact report API to a prim. 11 | 12 | Args: 13 | prim: The prim to add the contact report API to. 14 | """ 15 | cr_api = PhysxSchema.PhysxContactReportAPI.Apply(prim) 16 | cr_api.CreateThresholdAttr().Set(0) 17 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "codebase_version": "v2.1", 3 | "robot_type": null, 4 | "total_episodes": null, 5 | "total_frames": null, 6 | "total_tasks": null, 7 | "total_videos": null, 8 | "total_chunks": null, 9 | "chunks_size": 1000, 10 | "fps": null, 11 | "splits": { 12 | "train": "0:100" 13 | }, 14 | "data_path": "data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet", 15 | "video_path": "videos/chunk-{episode_chunk:03d}/{video_key}/episode_{episode_index:06d}.mp4", 16 | "features": null 17 | } 18 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* Force white background for gallery table cells */ 2 | table.gallery td { 3 | background-color: inherit !important; 4 | border: none !important; /* optional: removes table cell borders */ 5 | } 6 | 7 | /* Make images look clean inside the gallery */ 8 | table.gallery img { 9 | background-color: inherit !important; 10 | padding: 4px; 11 | border-radius: 4px; 12 | } 13 | 14 | /* Remove border and box-shadow from gallery table */ 15 | table.gallery, 16 | table.gallery td, 17 | table.gallery th { 18 | border: none !important; 19 | box-shadow: none !important; 20 | } 21 | -------------------------------------------------------------------------------- /extension.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | # Note: Semantic Versioning is used: https://semver.org/ 4 | version = "0.1.0" 5 | 6 | # Description 7 | title = "IsaacLab Arena" 8 | description="Evaluation framework for Isaac Lab" 9 | readme = "README.md" 10 | repository = "" 11 | category = "robotics" 12 | keywords = ["robotics", "rl", "il", "learning"] 13 | 14 | [dependencies] 15 | "omni.isaac.lab" = {} 16 | "omni.isaac.lab_assets" = {} 17 | 18 | [python.pipapi] 19 | requirements = [ 20 | "h5py", 21 | ] 22 | 23 | modules = [ 24 | "h5py", 25 | ] 26 | 27 | use_online_index=true 28 | 29 | [[python.module]] 30 | name = "isaaclab_arena" 31 | -------------------------------------------------------------------------------- /isaaclab_arena/teleop_devices/teleop_device_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class TeleopDeviceBase(ABC): 10 | 11 | name: str | None = None 12 | 13 | def __init__(self, sim_device: str | None = None): 14 | self.sim_device = sim_device 15 | 16 | @abstractmethod 17 | def get_teleop_device_cfg(self, embodiment: object | None = None): 18 | raise NotImplementedError 19 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/g1_wbc_upperbody_ik/solver.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from abc import ABC, abstractmethod 7 | from typing import Any 8 | 9 | 10 | class Solver(ABC): 11 | def __init__(self): 12 | pass 13 | 14 | def register_robot(self, robot): 15 | pass 16 | 17 | def calibrate(self, data): 18 | pass 19 | 20 | @abstractmethod 21 | def __call__(self, target) -> Any: 22 | pass 23 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_pose.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab_arena.utils.pose import Pose 7 | 8 | 9 | def test_pose_composition(): 10 | T_B_A = Pose(position_xyz=(1.0, 0.0, 0.0), rotation_wxyz=(1.0, 0.0, 0.0, 0.0)) 11 | T_C_B = Pose(position_xyz=(2.0, 0.0, 0.0), rotation_wxyz=(1.0, 0.0, 0.0, 0.0)) 12 | 13 | T_C_A = T_C_B.multiply(T_B_A) 14 | 15 | assert T_C_A.position_xyz == (3.0, 0.0, 0.0) 16 | assert T_C_A.rotation_wxyz == (1.0, 0.0, 0.0, 0.0) 17 | -------------------------------------------------------------------------------- /isaaclab_arena/affordances/affordance_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class AffordanceBase(ABC): 10 | """Base class for affordances.""" 11 | 12 | @property 13 | @abstractmethod 14 | def name(self) -> str: 15 | # NOTE(alexmillane, 2025.09.19) Affordances always have be combined with 16 | # an Asset which has a "name" property. By declaring this property 17 | # abstract here, we enforce this. 18 | pass 19 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/singleton.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | 7 | class SingletonMeta(type): 8 | """ 9 | Metaclass that overrides __call__ so that only one instance 10 | of any class using it is ever created. 11 | """ 12 | 13 | _instances = {} 14 | 15 | def __call__(cls, *args, **kwargs): 16 | if cls not in cls._instances: 17 | # first time: actually create the instance 18 | cls._instances[cls] = super().__call__(*args, **kwargs) 19 | # afterwards: always return the same object 20 | return cls._instances[cls] 21 | -------------------------------------------------------------------------------- /isaaclab_arena/orchestrator/orchestrator_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from abc import ABC, abstractmethod 7 | 8 | from isaaclab_arena.embodiments.embodiment_base import EmbodimentBase 9 | from isaaclab_arena.scene.scene import Scene 10 | from isaaclab_arena.tasks.task_base import TaskBase 11 | 12 | 13 | class OrchestratorBase(ABC): 14 | """Base class for orchestrators.""" 15 | 16 | @abstractmethod 17 | def orchestrate(self, embodiment: EmbodimentBase, scene: Scene, task: TaskBase) -> None: 18 | """Orchestrate the environment member interaction.""" 19 | pass 20 | -------------------------------------------------------------------------------- /isaaclab_arena/policy/zero_action_policy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import gymnasium as gym 7 | import torch 8 | from gymnasium.spaces.dict import Dict as GymSpacesDict 9 | 10 | from isaaclab_arena.policy.policy_base import PolicyBase 11 | 12 | 13 | class ZeroActionPolicy(PolicyBase): 14 | def __init__(self): 15 | super().__init__() 16 | 17 | def get_action(self, env: gym.Env, observation: GymSpacesDict) -> torch.Tensor: 18 | """ 19 | Always returns a zero action. 20 | """ 21 | return torch.zeros(env.action_space.shape, device=torch.device(env.unwrapped.device)) 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | """Installation script for the 'isaaclab_arena' python package.""" 6 | 7 | from setuptools import find_packages, setup 8 | 9 | ISAACLAB_ARENA_VERSION_NUMBER = "1.0.0" 10 | 11 | setup( 12 | name="isaaclab_arena", 13 | version=ISAACLAB_ARENA_VERSION_NUMBER, 14 | description="Isaac Lab - Arena. An Isaac Lab extension for robotic policy evaluation. ", 15 | packages=find_packages( 16 | include=["isaaclab_arena*", "isaaclab_arena_environments*", "isaaclab_arena_g1*", "isaaclab_arena_gr00t*"] 17 | ), 18 | python_requires=">=3.10", 19 | zip_safe=False, 20 | ) 21 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/franka/observations.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | 8 | from isaaclab.assets import Articulation 9 | from isaaclab.envs import ManagerBasedRLEnv 10 | from isaaclab.managers import SceneEntityCfg 11 | 12 | 13 | def gripper_pos(env: ManagerBasedRLEnv, robot_cfg: SceneEntityCfg = SceneEntityCfg("robot")) -> torch.Tensor: 14 | robot: Articulation = env.scene[robot_cfg.name] 15 | finger_joint_1 = robot.data.joint_pos[:, -1].clone().unsqueeze(1) 16 | finger_joint_2 = -1 * robot.data.joint_pos[:, -2].clone().unsqueeze(1) 17 | 18 | return torch.cat((finger_joint_1, finger_joint_2), dim=1) 19 | -------------------------------------------------------------------------------- /isaaclab_arena/metrics/metric_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | from abc import ABC, abstractmethod 8 | 9 | from isaaclab.managers.recorder_manager import RecorderTermCfg 10 | 11 | 12 | class MetricBase(ABC): 13 | 14 | name: str 15 | recorder_term_name: str 16 | 17 | @abstractmethod 18 | def get_recorder_term_cfg(self) -> RecorderTermCfg: 19 | raise NotImplementedError("Function not implemented yet.") 20 | 21 | @abstractmethod 22 | def compute_metric_from_recording(self, recorded_metric_data: list[np.ndarray]) -> float: 23 | raise NotImplementedError("Function not implemented yet.") 24 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/test_g1_locomanip_replay_action_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the ReplayLerobotActionPolicy class for G1 locomanipulation task 7 | dataset_path: isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/ 8 | action_horizon: 16 9 | embodiment_tag: new_embodiment 10 | video_backend: decord 11 | data_config: unitree_g1_sim_wbc 12 | 13 | policy_joints_config_path: isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml 14 | action_joints_config_path: isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml 15 | action_chunk_length: 1 16 | task_mode_name: g1_locomanipulation 17 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/policy/identity_policy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | 8 | from isaaclab_arena_g1.g1_whole_body_controller.wbc_policy.policy.base import WBCPolicy 9 | 10 | 11 | class IdentityPolicy(WBCPolicy): 12 | """Identity policy that passes through the target pose.""" 13 | 14 | def __init__(self): 15 | """Initialize the identity policy.""" 16 | self.reset() 17 | 18 | def get_action(self, target_pose: np.ndarray) -> dict[str, np.ndarray]: 19 | """Get the action for the identity policy.""" 20 | return {"q": target_pose} 21 | 22 | def reset(self): 23 | pass 24 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/g1_locomanip_replay_action_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the ReplayLerobotActionPolicy class for G1 locomanipulation task 7 | dataset_path: /datasets/isaaclab_arena/locomanipulation_tutorial/arena_g1_loco_manipulation_dataset_generated/lerobot/ 8 | action_horizon: 16 9 | embodiment_tag: new_embodiment 10 | video_backend: decord 11 | data_config: unitree_g1_sim_wbc 12 | 13 | policy_joints_config_path: isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml 14 | action_joints_config_path: isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml 15 | action_chunk_length: 1 16 | task_mode_name: g1_locomanipulation 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Isaac-Lab Arena 2 | 3 | **A scalable environment creation and evaluation framework for robotics simulations built on top of NVIDIA Isaac Lab** 4 | 5 | 6 | 7 | Isaac-Lab Arena is a comprehensive robotics simulation framework that enhances NVIDIA Isaac Lab by providing a composable, scalable system for creating diverse simulation environments and evaluating robot learning policies. The framework enables researchers and developers to rapidly prototype and test robotic tasks with various robot embodiments, objects, and environments. 8 | 9 | To get started with Isaac-Lab Arena, see our [documentation site](https://isaac-sim.github.io/IsaacLab-Arena/main/index.html). 10 | 11 |
12 | 13 | **Isaac-Lab Arena** - Scaling robotic simulation and evaluation for the future 14 | 15 | Made with ❤️ by the NVIDIA Robotics Team 16 | 17 |
18 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/gr1_manip_replay_action_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the Gr00tClosedloopPolicy class for GR1 tabletop manipulation task 7 | dataset_path: "/datasets/isaaclab_arena/static_manipulation_tutorial/arena_gr1_manipulation_dataset_generated/lerobot/" 8 | 9 | action_horizon: 16 10 | embodiment_tag: gr1 11 | video_backend: decord 12 | data_config: fourier_gr1_arms_only 13 | 14 | policy_joints_config_path: isaaclab_arena_gr00t/config/gr1/gr00t_26dof_joint_space.yaml 15 | action_joints_config_path: isaaclab_arena_gr00t/config/gr1/36dof_joint_space.yaml 16 | 17 | action_chunk_length: 1 18 | 19 | task_mode_name: gr1_tabletop_manipulation 20 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/config/g1_homie_v2.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Default joint angles for legs 7 | default_angles: [-0.1, 0.0, 0.0, 0.3, -0.2, 0.0, 8 | -0.1, 0.0, 0.0, 0.3, -0.2, 0.0, 9 | 0.0, 0.0, 0.0] 10 | # Scaling factors 11 | ang_vel_scale: 0.5 12 | dof_pos_scale: 1.0 13 | dof_vel_scale: 0.05 14 | action_scale: 0.25 15 | cmd_scale: [2.0, 2.0, 0.5] 16 | 17 | # Number of actions and observations 18 | num_actions: 15 19 | num_obs: 516 # 516 # 86 * 6 (observation dimension * history length) 20 | obs_history_len: 6 21 | 22 | # Initial commands 23 | cmd_init: [0.0, 0.0, 0.0] 24 | height_cmd: 0.74 25 | rpy_cmd: [0.0, 0.0, 0.0] 26 | freq_cmd: 0.75 27 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # `isaaclab_arena` Dox - Developer Guide 2 | 3 | To build the `isaaclab_arena` docs locally follow the following instructions. 4 | 5 | Enter the `isaaclab_arena` docker. 6 | 7 | ``` 8 | ./docker/run_docker.sh 9 | ``` 10 | 11 | The version of sphinx that we use requires a newer version of python. 12 | Install a newer version of `python` and `venv`: 13 | 14 | ``` 15 | sudo apt-get install python3.11 python3.11-venv 16 | ``` 17 | 18 | > It looks like this actually overwrites the currently installed version of python 19 | > inside. 20 | 21 | Create a `venv` and install the dependencies 22 | 23 | ``` 24 | python3.11 -m venv venv_docs 25 | source venv_docs/bin/activate 26 | cd ./docs 27 | python3.11 -m pip install -r requirements.txt 28 | ``` 29 | 30 | Make the docs 31 | 32 | ``` 33 | make html 34 | ``` 35 | 36 | To view the docs, navigationl to `isaaclab_arena/docs/_build/html/index.html`, and double-click. 37 | -------------------------------------------------------------------------------- /isaaclab_arena/assets/asset.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | 7 | class Asset: 8 | """ 9 | Base class for all assets. 10 | """ 11 | 12 | def __init__(self, name: str, tags: list[str] | None = None, **kwargs): 13 | # NOTE: Cooperative Multiple Inheritance Pattern. 14 | # Calling super even though this is a base class to support 15 | # multiple inheritance of inheriting classes. 16 | super().__init__(**kwargs) 17 | # self.name = name 18 | assert name is not None, "Name is required for all assets" 19 | self._name = name 20 | self.tags = tags 21 | 22 | # name is a read-only property 23 | @property 24 | def name(self) -> str: 25 | return self._name 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | 12 | # Put it first so that "make" without argument is like "make help". 13 | .PHONY: help Makefile 14 | help: 15 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 16 | 17 | 18 | .PHONY: multi-docs 19 | multi-docs: 20 | @sphinx-multiversion --verbose "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) 21 | @cp _redirect/index.html $(BUILDDIR)/index.html 22 | 23 | 24 | # Catch-all target: route all unknown targets to Sphinx using the new 25 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 26 | %: Makefile 27 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)/current" $(SPHINXOPTS) $(O) 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.extraPaths": [ 3 | "${workspaceFolder}", 4 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab", 5 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_assets", 6 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_rl", 7 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_mimic", 8 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_tasks", 9 | ], 10 | "cursorpyright.analysis.extraPaths": [ 11 | "${workspaceFolder}", 12 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab", 13 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_assets", 14 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_rl", 15 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_mimic", 16 | "${workspaceFolder}/submodules/IsaacLab/source/isaaclab_tasks", 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/mdp/actions/g1_decoupled_wbc_joint_action_cfg.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from dataclasses import MISSING 7 | 8 | from isaaclab.managers.action_manager import ActionTerm, ActionTermCfg 9 | from isaaclab.utils import configclass 10 | 11 | from isaaclab_arena_g1.g1_env.mdp.actions.g1_decoupled_wbc_joint_action import G1DecoupledWBCJointAction 12 | 13 | 14 | @configclass 15 | class G1DecoupledWBCJointActionCfg(ActionTermCfg): 16 | class_type: type[ActionTerm] = G1DecoupledWBCJointAction 17 | """Specifies the action term class type for G1 WBC with upper body direct joint position control.""" 18 | 19 | preserve_order: bool = False 20 | joint_names: list[str] = MISSING 21 | 22 | wbc_version: str = "homie_v2" 23 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | show-source=True 3 | statistics=True 4 | per-file-ignores=*/__init__.py:F401 5 | # E402: Module level import not at top of file 6 | # E501: Line too long 7 | # W503: Line break before binary operator 8 | # E203: Whitespace before ':' -> conflicts with black 9 | # D401: First line should be in imperative mood 10 | # R504: Unnecessary variable assignment before return statement. 11 | # R505: Unnecessary elif after return statement 12 | # SIM102: Use a single if-statement instead of nested if-statements 13 | # SIM117: Merge with statements for context managers that have same scope. 14 | # SIM118: Checks for key-existence checks against dict.keys() calls. 15 | ignore=E402,E501,W503,E203,D401,R504,R505,SIM102,SIM117,SIM118 16 | max-line-length = 120 17 | max-complexity = 30 18 | exclude=_*,.vscode,.git,docs/** 19 | # docstrings 20 | docstring-convention=google 21 | # annotations 22 | suppress-none-returning=True 23 | allow-star-arg-any=True 24 | -------------------------------------------------------------------------------- /isaaclab_arena/assets/register.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab_arena.assets.asset_registry import AssetRegistry, DeviceRegistry 7 | 8 | 9 | # Decorator to register an asset with the AssetRegistry. 10 | def register_asset(cls): 11 | if AssetRegistry().is_registered(cls.name): 12 | print(f"WARNING: Asset {cls.name} is already registered. Doing nothing.") 13 | else: 14 | AssetRegistry().register(cls) 15 | return cls 16 | 17 | 18 | # Decorator to register an device with the DeviceRegistry. 19 | def register_device(cls): 20 | if DeviceRegistry().is_registered(cls.name): 21 | print(f"WARNING: Device {cls.name} is already registered. Doing nothing.") 22 | else: 23 | DeviceRegistry().register(cls) 24 | return cls 25 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/utils/simulation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | import tqdm 8 | from collections.abc import Callable 9 | 10 | from isaaclab.envs.manager_based_env import ManagerBasedEnv 11 | 12 | 13 | def step_zeros_and_call( 14 | env: ManagerBasedEnv, num_steps: int, function: Callable[[ManagerBasedEnv, torch.Tensor], None] | None = None 15 | ) -> None: 16 | """Step through the environment with zero actions for a specified number of steps.""" 17 | for _ in tqdm.tqdm(range(num_steps)): 18 | with torch.inference_mode(): 19 | actions = torch.zeros(env.action_space.shape, device=env.device) 20 | _, _, terminated, _, _ = env.step(actions) 21 | if function is not None: 22 | function(env, terminated) 23 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/test_g1_locomanip_gr00t_closedloop_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the Gr00tClosedloopPolicy class for G1 locomanipulation task 7 | model_path: /checkpoints/gn1_5_g1_galileo_box_npnp/checkpoint-20000 8 | action_horizon: 16 9 | embodiment_tag: new_embodiment 10 | video_backend: decord 11 | data_config: unitree_g1_sim_wbc 12 | 13 | policy_joints_config_path: isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml 14 | action_joints_config_path: isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml 15 | state_joints_config_path: isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml 16 | action_chunk_length: 16 17 | task_mode_name: g1_locomanipulation 18 | 19 | pov_cam_name_sim: "robot_head_cam_rgb" 20 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/test_gr1_manip_replay_action_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the ReplayLerobotActionPolicy class for G1 locomanipulation task 7 | # TODO(xinjie.yao, 2025-09-30): change Hardcoded dataset_path to some releasable path 8 | dataset_path: isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/ 9 | action_horizon: 16 10 | embodiment_tag: gr1 11 | video_backend: decord 12 | data_config: fourier_gr1_arms_only 13 | 14 | policy_joints_config_path: isaaclab_arena_gr00t/config/gr1/gr00t_26dof_joint_space.yaml 15 | action_joints_config_path: isaaclab_arena_gr00t/config/gr1/36dof_joint_space.yaml 16 | action_chunk_length: 1 17 | task_mode_name: gr1_tabletop_manipulation 18 | 19 | pov_cam_name_sim: "robot_pov_cam_rgb" 20 | -------------------------------------------------------------------------------- /isaaclab_arena/terms/articulations.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from __future__ import annotations 7 | 8 | import torch 9 | from typing import TYPE_CHECKING 10 | 11 | from isaaclab.managers import SceneEntityCfg 12 | 13 | if TYPE_CHECKING: 14 | from isaaclab.assets import Articulation 15 | from isaaclab.envs import ManagerBasedEnv 16 | 17 | 18 | def joint_acc(env: ManagerBasedEnv, asset_cfg: SceneEntityCfg = SceneEntityCfg("robot")) -> torch.Tensor: 19 | """The joint accelerations of the asset. 20 | 21 | Note: Only the joints configured in :attr:`asset_cfg.joint_ids` will have their accelerations returned. 22 | """ 23 | # extract the used quantities (to enable type-hinting) 24 | asset: Articulation = env.scene[asset_cfg.name] 25 | return asset.data.joint_acc[:, asset_cfg.joint_ids] 26 | -------------------------------------------------------------------------------- /isaaclab_arena/tasks/dummy_task.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab.envs.common import ViewerCfg 7 | 8 | from isaaclab_arena.embodiments.common.mimic_arm_mode import MimicArmMode 9 | from isaaclab_arena.tasks.task_base import TaskBase 10 | 11 | 12 | class DummyTask(TaskBase): 13 | def __init__(self): 14 | super().__init__() 15 | 16 | def get_scene_cfg(self): 17 | pass 18 | 19 | def get_termination_cfg(self): 20 | pass 21 | 22 | def get_events_cfg(self): 23 | pass 24 | 25 | def get_prompt(self): 26 | pass 27 | 28 | def get_mimic_env_cfg(self, arm_mode: MimicArmMode): 29 | pass 30 | 31 | def get_metrics(self): 32 | pass 33 | 34 | def get_viewer_cfg(self) -> ViewerCfg: 35 | return ViewerCfg(eye=(-1.5, -1.5, 1.5), lookat=(0.0, 0.0, 0.5)) 36 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/utils/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import os 7 | 8 | 9 | class _TestConstants: 10 | """Class for storing test data paths""" 11 | 12 | def __init__(self): 13 | script_dir = os.path.dirname(os.path.abspath(__file__)) 14 | 15 | # The root directory of the repo 16 | self.repo_root = os.path.realpath(os.path.join(script_dir, *([".."] * 3))) 17 | 18 | self.examples_dir = f"{self.repo_root}/isaaclab_arena/examples" 19 | 20 | self.test_dir = f"{self.repo_root}/isaaclab_arena/tests" 21 | 22 | self.python_path = f"{self.repo_root}/submodules/IsaacLab/_isaac_sim/python.sh" 23 | 24 | self.test_data_dir = f"{self.test_dir}/test_data" 25 | 26 | self.submodules_dir = f"{self.repo_root}/submodules" 27 | 28 | 29 | TestConstants = _TestConstants() 30 | -------------------------------------------------------------------------------- /docs/_templates/versioning.html: -------------------------------------------------------------------------------- 1 | {% if versions %} 2 | 21 | {% endif %} 22 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/common/mimic_arm_mode.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from enum import Enum 7 | 8 | 9 | class MimicArmMode(str, Enum): 10 | """ 11 | The arm mode for the mimic environment configuration. 12 | 13 | Attributes: 14 | SINGLE_ARM: Single arm mode (the robot has only one arm). 15 | DUAL_ARM: Dual arm mode (bimanual robot, task is performed with both arms in the demonstration). 16 | LEFT: Left arm mode (bimanual robot, task is performed with the left arm in the demonstration, right arm is idle). 17 | RIGHT: Right arm mode (bimanual robot, task is performed with the right arm in the demonstration, left arm is idle). 18 | """ 19 | 20 | SINGLE_ARM = "single_arm" 21 | DUAL_ARM = "dual_arm" 22 | LEFT = "left" 23 | RIGHT = "right" 24 | 25 | def get_other_arm(self) -> str: 26 | assert self in [MimicArmMode.LEFT, MimicArmMode.RIGHT], f"Arm mode {self} is not a bimanual arm mode" 27 | return MimicArmMode.RIGHT if self == MimicArmMode.LEFT else MimicArmMode.LEFT 28 | -------------------------------------------------------------------------------- /isaaclab_arena_environments/example_environment_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import argparse 7 | from abc import ABC, abstractmethod 8 | 9 | # NOTE(alexmillane, 2025.09.04): There is an issue with type annotation in this file. 10 | # We cannot annotate types which require the simulation app to be started in order to 11 | # import, because this file is used to retrieve CLI arguments, so it must be imported 12 | # before the simulation app is started. 13 | # TODO(alexmillane, 2025.09.04): Fix this. 14 | 15 | 16 | class ExampleEnvironmentBase(ABC): 17 | 18 | name: str | None = None 19 | 20 | def __init__(self): 21 | from isaaclab_arena.assets.asset_registry import AssetRegistry, DeviceRegistry 22 | 23 | self.asset_registry = AssetRegistry() 24 | self.device_registry = DeviceRegistry() 25 | 26 | @abstractmethod 27 | def get_env(self, args_cli: argparse.Namespace): # -> IsaacLabArenaEnvironment: 28 | pass 29 | 30 | @abstractmethod 31 | def add_cli_args(parser: argparse.ArgumentParser) -> None: 32 | pass 33 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_simulation_app_context.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function 7 | 8 | TEST_ARG = 123 9 | 10 | 11 | def simulation_app_running(simulation_app) -> bool: 12 | print("Hello, simulation app test!") 13 | return simulation_app.is_running() 14 | 15 | 16 | def test_simulation_app_context(): 17 | # Run a function which returns True if the simulation app is running. 18 | test_passed = run_simulation_app_function( 19 | simulation_app_running, 20 | ) 21 | assert test_passed, "Tested function returned False" 22 | 23 | 24 | def got_argument(_, test_arg: int) -> bool: 25 | print(f"Got argument: {test_arg}") 26 | return test_arg == TEST_ARG 27 | 28 | 29 | def test_run_simulation_app_function_with_arg(): 30 | # Run a function which returns True if the simulation app is running. 31 | test_passed = run_simulation_app_function( 32 | got_argument, 33 | test_arg=TEST_ARG, 34 | ) 35 | assert test_passed, "Tested function returned False" 36 | -------------------------------------------------------------------------------- /docs/helpers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # 7 | # Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 8 | # 9 | # NVIDIA CORPORATION, its affiliates and licensors retain all intellectual 10 | # property and proprietary rights in and to this material, related 11 | # documentation and any modifications thereto. Any use, reproduction, 12 | # disclosure or distribution of this material and related documentation 13 | # without an express license agreement from NVIDIA CORPORATION or 14 | # its affiliates is strictly prohibited. 15 | # 16 | import dataclasses 17 | import datetime 18 | 19 | 20 | def to_datetime(date_str: str) -> datetime.datetime: 21 | return datetime.datetime.strptime(date_str, "%d.%m.%Y") 22 | 23 | 24 | def is_expired(start_date: datetime.datetime, days: int) -> bool: 25 | today = datetime.datetime.now() 26 | delta = datetime.timedelta(days=days) 27 | return today > (start_date + delta) 28 | 29 | 30 | @dataclasses.dataclass 31 | class TemporaryLinkcheckIgnore: 32 | url: str 33 | start_date: datetime.datetime 34 | days: int 35 | -------------------------------------------------------------------------------- /isaaclab_arena/embodiments/common/mimic_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | from collections.abc import Sequence 8 | 9 | import isaaclab.utils.math as PoseUtils 10 | 11 | 12 | def get_rigid_and_articulated_object_poses(state: dict, env_ids: Sequence[int] | None = None): 13 | """ 14 | Gets the pose of each object(rigid and articulated) in the current scene. 15 | Args: 16 | state: The state of the scene. 17 | Returns: 18 | A dictionary that maps object names to object pose matrix (4x4 torch.Tensor) 19 | """ 20 | 21 | def pose_from(obj_state) -> "torch.Tensor": 22 | rp = obj_state["root_pose"][env_ids] # (..., 7): [x,y,z, qx,qy,qz,qw] 23 | pos, quat = rp[..., :3], rp[..., 3:7] 24 | return PoseUtils.make_pose(pos, PoseUtils.matrix_from_quat(quat)) # (..., 4, 4) 25 | 26 | groups = ["rigid_object", "articulation"] 27 | 28 | object_pose_matrix = { 29 | name: pose_from(obj_state) for group in groups for name, obj_state in state.get(group, {}).items() 30 | } 31 | 32 | return object_pose_matrix 33 | -------------------------------------------------------------------------------- /docs/pages/advanced/private_omniverse.rst: -------------------------------------------------------------------------------- 1 | Omniverse Authentication 2 | ======================== 3 | 4 | .. note:: 5 | 6 | These steps are only required if you are extending Isaac Lab Arena with your own 7 | internal assets. Assets and files that are used by Isaac Lab Arena by default are 8 | publicly available without additional authentication (i.e. without performing the 9 | steps detailed on this page). 10 | 11 | To allow the project to access Nvidia Omniverse assets or services 12 | e.g., stored scenes, USD files, or extensions on a **private** Nucleus server, 13 | you must authenticate using an Omniverse API token. 14 | 15 | Isaac Sim and other Nvidia Omniverse applications use two environment variables 16 | ``OMNI_USER`` and ``OMNI_PASS`` to authenticate automatically. 17 | 18 | To generate those, follow the instructions on the 19 | `Omniverse Authentication documentation `_. 20 | 21 | .. code-block:: bash 22 | 23 | export OMNI_USER='$omni-api-token' 24 | export OMNI_PASS= 25 | 26 | Where: 27 | 28 | * ``OMNI_USER`` should be set to the literal string ``$omni-api-token`` (including the leading dollar sign) 29 | 30 | * ``OMNI_PASS`` should be the actual token value you generated. 31 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/policy/action_constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | """Constants for the WBC PINK action.""" 7 | 8 | # Action dimensions 9 | LEFT_WRIST_POS_DIM = 3 10 | LEFT_WRIST_QUAT_DIM = 4 11 | RIGHT_WRIST_POS_DIM = 3 12 | RIGHT_WRIST_QUAT_DIM = 4 13 | LEFT_HAND_STATE_DIM = 1 14 | RIGHT_HAND_STATE_DIM = 1 15 | 16 | # Action indices 17 | LEFT_HAND_STATE_IDX = 0 18 | RIGHT_HAND_STATE_IDX = 1 19 | LEFT_WRIST_POS_START_IDX = 2 20 | LEFT_WRIST_POS_END_IDX = 5 21 | LEFT_WRIST_QUAT_START_IDX = 5 22 | LEFT_WRIST_QUAT_END_IDX = 9 23 | RIGHT_WRIST_POS_START_IDX = 9 24 | RIGHT_WRIST_POS_END_IDX = 12 25 | RIGHT_WRIST_QUAT_START_IDX = 12 26 | RIGHT_WRIST_QUAT_END_IDX = 16 27 | NAVIGATE_CMD_START_IDX = 16 28 | NAVIGATE_CMD_END_IDX = 19 29 | BASE_HEIGHT_CMD_START_IDX = 19 30 | BASE_HEIGHT_CMD_END_IDX = 20 31 | TORSO_ORIENTATION_RPY_CMD_START_IDX = 20 32 | TORSO_ORIENTATION_RPY_CMD_END_IDX = 23 33 | 34 | # Navigation p-controller params 35 | NAVIGATE_THRESHOLD = 1e-4 36 | 37 | # Robot model link names 38 | LEFT_WRIST_LINK_NAME = "left_wrist_yaw_link" 39 | RIGHT_WRIST_LINK_NAME = "right_wrist_yaw_link" 40 | -------------------------------------------------------------------------------- /isaaclab_arena/examples/README.md: -------------------------------------------------------------------------------- 1 | # IsaacLab Arena Examples 2 | 3 | IsaacLab Arena includes some pre-configured example environments to demonstrate its use. 4 | 5 | Right now these environments are 6 | - `KitchenPickAndPlaceEnvironment`: A task requiring picking and placing a object in the drawer in a kitchen scene. 7 | - `GalileoPickAndPlaceEnvironment`: A task requiring picking and placing a object in the drawer in a galileo scene. 8 | - `Gr1OpenMicrowaveEnvironment`: A task requiring opening a microwave door. 9 | 10 | Please check the relevant environment files to see what CLI arguments are supported. 11 | 12 | Examples are launched with a zero action runner (with some example arguments) like: 13 | 14 | ```bash 15 | python isaaclab_arena/examples/policy_runner.py --policy_type zero_action kitchen_pick_and_place --object cracker_box --embodiment gr1_joint 16 | ``` 17 | 18 | or 19 | 20 | ```bash 21 | python isaaclab_arena/examples/policy_runner.py --policy_type zero_action gr1_open_microwave --object tomato_soup_can 22 | ``` 23 | 24 | **NOTE:** CLI arguments are sensitive to order. They must appear in the following order: 25 | 26 | ``` 27 | python isaaclab_arena/examples/policy_runner.py <--global flags> <--app specific flags> 28 | ``` 29 | 30 | App specific flags must appear after the first argument with `--` which must be the example app name. 31 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1/modality.json: -------------------------------------------------------------------------------- 1 | { 2 | "state": { 3 | "left_arm": { 4 | "original_key": "observation.state", 5 | "start": 0, 6 | "end": 7 7 | }, 8 | "right_arm": { 9 | "original_key": "observation.state", 10 | "start": 7, 11 | "end": 14 12 | }, 13 | "left_hand": { 14 | "original_key": "observation.state", 15 | "start": 14, 16 | "end": 20 17 | }, 18 | "right_hand": { 19 | "original_key": "observation.state", 20 | "start": 20, 21 | "end": 26 22 | } 23 | }, 24 | "action": { 25 | "left_arm": { 26 | "start": 0, 27 | "end": 7 28 | }, 29 | "right_arm": { 30 | "start": 7, 31 | "end": 14 32 | }, 33 | "left_hand": { 34 | "start": 14, 35 | "end": 20 36 | }, 37 | "right_hand": { 38 | "start": 20, 39 | "end": 26 40 | } 41 | }, 42 | "video": { 43 | "ego_view": { 44 | "original_key": "observation.images.ego_view" 45 | } 46 | }, 47 | "annotation": { 48 | "human.action.task_description": { 49 | "original_key": "task_index" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_gr1_manip_lerobot/meta/modality.json: -------------------------------------------------------------------------------- 1 | { 2 | "state": { 3 | "left_arm": { 4 | "original_key": "observation.state", 5 | "start": 0, 6 | "end": 7 7 | }, 8 | "right_arm": { 9 | "original_key": "observation.state", 10 | "start": 7, 11 | "end": 14 12 | }, 13 | "left_hand": { 14 | "original_key": "observation.state", 15 | "start": 14, 16 | "end": 20 17 | }, 18 | "right_hand": { 19 | "original_key": "observation.state", 20 | "start": 20, 21 | "end": 26 22 | } 23 | }, 24 | "action": { 25 | "left_arm": { 26 | "start": 0, 27 | "end": 7 28 | }, 29 | "right_arm": { 30 | "start": 7, 31 | "end": 14 32 | }, 33 | "left_hand": { 34 | "start": 14, 35 | "end": 20 36 | }, 37 | "right_hand": { 38 | "start": 20, 39 | "end": 26 40 | } 41 | }, 42 | "video": { 43 | "ego_view": { 44 | "original_key": "observation.images.ego_view" 45 | } 46 | }, 47 | "annotation": { 48 | "human.action.task_description": { 49 | "original_key": "task_index" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/isaaclab_utils/resets.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | 8 | from isaaclab.envs import ManagerBasedEnv 9 | 10 | 11 | def reset_all_articulation_joints(env: ManagerBasedEnv, env_ids: torch.Tensor): 12 | """Reset the articulation joints to the initial state.""" 13 | for articulation_asset in env.scene.articulations.values(): 14 | # obtain default and deal with the offset for env origins 15 | default_root_state = articulation_asset.data.default_root_state[env_ids].clone() 16 | default_root_state[:, 0:3] += env.scene.env_origins[env_ids] 17 | # set into the physics simulation 18 | articulation_asset.write_root_pose_to_sim(default_root_state[:, :7], env_ids=env_ids) 19 | articulation_asset.write_root_velocity_to_sim(default_root_state[:, 7:], env_ids=env_ids) 20 | # obtain default joint positions 21 | default_joint_pos = articulation_asset.data.default_joint_pos[env_ids].clone() 22 | default_joint_vel = articulation_asset.data.default_joint_vel[env_ids].clone() 23 | # set into the physics simulation 24 | articulation_asset.write_joint_state_to_sim(default_joint_pos, default_joint_vel, env_ids=env_ids) 25 | -------------------------------------------------------------------------------- /isaaclab_arena/policy/policy_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import gymnasium as gym 7 | import torch 8 | from abc import ABC, abstractmethod 9 | from gymnasium.spaces.dict import Dict as GymSpacesDict 10 | 11 | 12 | class PolicyBase(ABC): 13 | def __init__(self): 14 | """ 15 | Base class for policies. 16 | """ 17 | 18 | @abstractmethod 19 | def get_action(self, env: gym.Env, observation: GymSpacesDict) -> torch.Tensor: 20 | """ 21 | Compute an action given the environment and observation. 22 | 23 | Args: 24 | env: The environment instance. 25 | observation: Observation dictionary from the environment. 26 | 27 | Returns: 28 | torch.Tensor: The action to take. 29 | """ 30 | raise NotImplementedError("Function not implemented yet.") 31 | 32 | def reset(self, env_ids: torch.Tensor | None = None) -> None: 33 | """ 34 | Reset the policy. 35 | """ 36 | pass 37 | 38 | def set_task_description(self, task_description: str | None) -> str: 39 | """Set the task description of the task being evaluated.""" 40 | self.task_description = task_description 41 | return self.task_description 42 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/mdp/g1_events.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from __future__ import annotations 7 | 8 | import torch 9 | from typing import TYPE_CHECKING 10 | 11 | if TYPE_CHECKING: 12 | from isaaclab.envs import ManagerBasedEnv 13 | 14 | 15 | def reset_decoupled_wbc_joint_policy(env: ManagerBasedEnv, env_ids: torch.Tensor): 16 | # Reset lower body RL-based policy 17 | policy = env.action_manager.get_term("g1_action").get_wbc_policy 18 | policy.lower_body_policy.reset(env_ids) 19 | 20 | 21 | def reset_decoupled_wbc_pink_policy(env: ManagerBasedEnv, env_ids: torch.Tensor): 22 | # Reset upper body IK solver 23 | env.action_manager.get_term("g1_action").upperbody_controller.body_ik_solver.initialize() 24 | env.action_manager.get_term("g1_action").upperbody_controller.in_warmup = True 25 | 26 | # Reset lower body RL-based policy 27 | policy = env.action_manager.get_term("g1_action").get_wbc_policy 28 | policy.lower_body_policy.reset(env_ids) 29 | 30 | # Reset P-controller 31 | env.action_manager.get_term("g1_action")._is_navigating = False 32 | env.action_manager.get_term("g1_action")._navigation_goal_reached = False 33 | env.action_manager.get_term("g1_action")._num_navigation_subgoals_reached = -1 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/build 2 | 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | # Note that .so files are not ignored since the repo contains symlinks to such files 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | *.smod 25 | 26 | # Compiled Static libraries 27 | *.lai 28 | *.la 29 | *.a 30 | *.lib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | 37 | # IDE stuff 38 | *.vscode 39 | *.*~ 40 | TAGS 41 | 42 | # Build files 43 | *build 44 | *install 45 | 46 | # Python 47 | *.pyc 48 | **/*.egg-info 49 | **/__pycache__ 50 | **/.hypothesis/* 51 | 52 | # Documentation 53 | *docs/_build 54 | *docs/doxyoutput 55 | *docs/api 56 | 57 | # Logs 58 | *logs/ 59 | 60 | # outputs 61 | *outputs/ 62 | 63 | # Training images 64 | *training_images/ 65 | 66 | # Self Training logs and outputs 67 | *self_supervision_logs/ 68 | *self_supervision_outputs/ 69 | 70 | # Models 71 | *models/ 72 | *isaaclab_arena/embodiments/g1/wbc_policy/models/ 73 | *isaaclab_arena/embodiments/g1/wbc_policy/robot_model/ 74 | 75 | # Datasets 76 | *datasets/ 77 | 78 | # Training logs and outputs 79 | *wandb/ 80 | 81 | # Ignore plots 82 | isaaclab_arena/tests/**.png 83 | 84 | # Ignore core dumps produced by debugpy 85 | core 86 | core.* 87 | 88 | # venvs 89 | **venv_docs/ 90 | 91 | # Development and cache folders 92 | /__* 93 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/g1_locomanip_gr00t_closedloop_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the Gr00tClosedloopPolicy class for G1 locomanipulation task 7 | # NOTE(alexmillane, 2025-10-31): The model path here aligns with the model used in the static manipulation tutorial. 8 | model_path: /models/isaaclab_arena/locomanipulation_tutorial/checkpoint-20000 9 | language_instruction: "Pick up the brown box from the shelf, and place it into the blue bin on the table located at the right of the shelf." 10 | # Action horizon is the number of actions predicted by the policy per inference rollout, defined in the GN1.5 policy data_config 'unitree_g1_sim_wbc'. 11 | action_horizon: 16 12 | embodiment_tag: new_embodiment 13 | video_backend: decord 14 | data_config: unitree_g1_sim_wbc 15 | 16 | policy_joints_config_path: isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml 17 | action_joints_config_path: isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml 18 | state_joints_config_path: isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml 19 | 20 | # Action chunk length is the number of actions executed per inference rollout, could be less than action_horizon. 21 | action_chunk_length: 16 22 | pov_cam_name_sim: "robot_head_cam_rgb" 23 | 24 | task_mode_name: g1_locomanipulation 25 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/gr1_manip_gr00t_closedloop_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # This file shows how to configure the Gr00tClosedloopPolicy class for GR1 tabletop manipulation task 7 | # NOTE(alexmillane, 2025-10-31): The model path here aligns with the model used in the static manipulation tutorial. 8 | model_path: /models/isaaclab_arena/static_manipulation_tutorial/checkpoint-20000 9 | language_instruction: "Reach out to the microwave and open it." 10 | # Action horizon is the number of actions predicted by the policy per inference rollout, defined in the GN1.5 policy data_config 'fourier_gr1_arms_only'. 11 | action_horizon: 16 12 | embodiment_tag: gr1 13 | video_backend: decord 14 | data_config: fourier_gr1_arms_only 15 | 16 | policy_joints_config_path: isaaclab_arena_gr00t/config/gr1/gr00t_26dof_joint_space.yaml 17 | action_joints_config_path: isaaclab_arena_gr00t/config/gr1/36dof_joint_space.yaml 18 | state_joints_config_path: isaaclab_arena_gr00t/config/gr1/54dof_joint_space.yaml 19 | 20 | # Action chunk length is the number of actions executed per inference rollout, could be less than action_horizon. 21 | action_chunk_length: 16 22 | task_mode_name: gr1_tabletop_manipulation 23 | 24 | pov_cam_name_sim: "robot_pov_cam_rgb" 25 | 26 | original_image_size: [512, 512, 3] 27 | target_image_size: [512, 512, 3] 28 | -------------------------------------------------------------------------------- /isaaclab_arena/assets/background.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab_arena.assets.object import Object 7 | from isaaclab_arena.assets.object_base import ObjectType 8 | from isaaclab_arena.utils.pose import Pose 9 | 10 | 11 | class Background(Object): 12 | """ 13 | Encapsulates the background scene for a environment. 14 | """ 15 | 16 | def __init__( 17 | self, 18 | name: str, 19 | usd_path: str, 20 | object_min_z: float, 21 | prim_path: str | None = None, 22 | initial_pose: Pose | None = None, 23 | **kwargs 24 | ): 25 | super().__init__( 26 | name=name, 27 | usd_path=usd_path, 28 | initial_pose=initial_pose, 29 | prim_path=prim_path, 30 | # Backgrounds don't have physics (at the moment) 31 | object_type=ObjectType.BASE, 32 | **kwargs, 33 | ) 34 | # We use this to define reset terms for when objects are dropped. 35 | # NOTE(alexmillane, 2025.09.19): This is a global z height. If you shift the 36 | # background, by using initial_pose, this height doesn't shift with it. 37 | # TODO(alexmillane, 2025.09.19): Make this value relative to the background 38 | # prim origin. 39 | self.object_min_z = object_min_z 40 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/data_utils/robot_joints.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | import torch 8 | from dataclasses import dataclass 9 | 10 | 11 | @dataclass 12 | class JointsAbsPosition: 13 | joints_pos: torch.Tensor 14 | """Joint positions in radians""" 15 | 16 | joints_order_config: dict[str, int] 17 | """Joints order configuration""" 18 | 19 | @staticmethod 20 | def zero(joint_order_config: dict[str, int], device: torch.device): 21 | return JointsAbsPosition( 22 | joints_pos=torch.zeros((len(joint_order_config)), device=device), joints_order_config=joint_order_config 23 | ) 24 | 25 | def to_array(self) -> torch.Tensor: 26 | return self.joints_pos.cpu().numpy() 27 | 28 | @staticmethod 29 | def from_array(array: np.ndarray, joint_order_config: dict[str, int], device: torch.device) -> "JointsAbsPosition": 30 | return JointsAbsPosition(joints_pos=torch.from_numpy(array).to(device), joints_order_config=joint_order_config) 31 | 32 | def set_joints_pos(self, joints_pos: torch.Tensor): 33 | self.joints_pos = joints_pos.to(self.device) 34 | 35 | def get_joints_pos(self, device: torch.device = None) -> torch.Tensor: 36 | if device is None: 37 | return self.joints_pos 38 | else: 39 | return self.joints_pos.to(device) 40 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_object_configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function 7 | 8 | HEADLESS = True 9 | 10 | 11 | def _test_object_initial_pose_update(simulation_app): 12 | 13 | from isaaclab_arena.assets.asset_registry import AssetRegistry 14 | from isaaclab_arena.utils.pose import Pose 15 | 16 | asset_registry = AssetRegistry() 17 | # Get a rigid object 18 | rigid_object = asset_registry.get_asset_by_name("cracker_box")() 19 | # Disable debug visualization, this is True by default. 20 | rigid_object.object_cfg.debug_vis = False 21 | 22 | # Now lets add an initial pose to the object. 23 | new_initial_pose = Pose(position_xyz=(5.0, 0.0, 0.0), rotation_wxyz=(1.0, 0.0, 0.0, 0.0)) 24 | rigid_object.set_initial_pose(new_initial_pose) 25 | 26 | # Now lets check that the initial pose has been updated and that the debug visualization is still disabled. 27 | assert rigid_object.get_initial_pose() == new_initial_pose 28 | assert rigid_object.object_cfg.debug_vis is False 29 | 30 | return True 31 | 32 | 33 | def test_object_configuration(): 34 | result = run_simulation_app_function( 35 | _test_object_initial_pose_update, 36 | headless=HEADLESS, 37 | ) 38 | assert result, "Test failed" 39 | 40 | 41 | if __name__ == "__main__": 42 | test_object_configuration() 43 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/mdp/actions/g1_decoupled_wbc_pink_action_cfg.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab.managers.action_manager import ActionTerm 7 | from isaaclab.utils import configclass 8 | 9 | from isaaclab_arena_g1.g1_env.mdp.actions.g1_decoupled_wbc_joint_action_cfg import G1DecoupledWBCJointActionCfg 10 | from isaaclab_arena_g1.g1_env.mdp.actions.g1_decoupled_wbc_pink_action import G1DecoupledWBCPinkAction 11 | 12 | 13 | @configclass 14 | class G1DecoupledWBCPinkActionCfg(G1DecoupledWBCJointActionCfg): 15 | class_type: type[ActionTerm] = G1DecoupledWBCPinkAction 16 | """Specifies the action term class type for G1 WBC with upper body PINK IK controller.""" 17 | 18 | # Navigation Segment: Use P-controller 19 | use_p_control: bool = False 20 | 21 | # Navigation Segment: P-controller parameters 22 | distance_error_threshold: float = 0.1 23 | heading_diff_threshold: float = 0.2 24 | kp_angular_turning_only: float = 0.4 25 | kp_linear_x: float = 2.0 26 | kp_linear_y: float = 2.0 27 | kp_angular: float = 0.05 28 | min_vel: float = -0.4 29 | max_vel: float = 0.4 30 | 31 | # Navigation Segment: Target x, y, heading, and turning_in_place flag subgoals 32 | navigation_subgoals: list[tuple[list[float], bool]] | None = None 33 | 34 | # Navigation Segment: Turning first 35 | turning_first: bool = False 36 | 37 | # Navigation Segment: Max navigation steps 38 | max_navigation_steps: int = 700 39 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/config/lab_g1_joints_order_43dof.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | "left_hip_pitch_joint": 0 7 | "right_hip_pitch_joint": 1 8 | "waist_yaw_joint": 2 9 | "left_hip_roll_joint": 3 10 | "right_hip_roll_joint": 4 11 | "waist_roll_joint": 5 12 | "left_hip_yaw_joint": 6 13 | "right_hip_yaw_joint": 7 14 | "waist_pitch_joint": 8 15 | "left_knee_joint": 9 16 | "right_knee_joint": 10 17 | "left_shoulder_pitch_joint": 11 18 | "right_shoulder_pitch_joint": 12 19 | "left_ankle_pitch_joint": 13 20 | "right_ankle_pitch_joint": 14 21 | "left_shoulder_roll_joint": 15 22 | "right_shoulder_roll_joint": 16 23 | "left_ankle_roll_joint": 17 24 | "right_ankle_roll_joint": 18 25 | "left_shoulder_yaw_joint": 19 26 | "right_shoulder_yaw_joint": 20 27 | "left_elbow_joint": 21 28 | "right_elbow_joint": 22 29 | "left_wrist_roll_joint": 23 30 | "right_wrist_roll_joint": 24 31 | "left_wrist_pitch_joint": 25 32 | "right_wrist_pitch_joint": 26 33 | "left_wrist_yaw_joint": 27 34 | "right_wrist_yaw_joint": 28 35 | "left_hand_index_0_joint": 29 36 | "left_hand_middle_0_joint": 30 37 | "left_hand_thumb_0_joint": 31 38 | "right_hand_index_0_joint": 32 39 | "right_hand_middle_0_joint": 33 40 | "right_hand_thumb_0_joint": 34 41 | "left_hand_index_1_joint": 35 42 | "left_hand_middle_1_joint": 36 43 | "left_hand_thumb_1_joint": 37 44 | "right_hand_index_1_joint": 38 45 | "right_hand_middle_1_joint": 39 46 | "right_hand_thumb_1_joint": 40 47 | "left_hand_thumb_2_joint": 41 48 | "right_hand_thumb_2_joint": 42 49 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_env/config/loco_manip_g1_joints_order_43dof.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | 'left_hip_pitch_joint': 0 7 | 'left_hip_roll_joint': 1 8 | 'left_hip_yaw_joint': 2 9 | 'left_knee_joint': 3 10 | 'left_ankle_pitch_joint': 4 11 | 'left_ankle_roll_joint': 5 12 | 'right_hip_pitch_joint': 6 13 | 'right_hip_roll_joint': 7 14 | 'right_hip_yaw_joint': 8 15 | 'right_knee_joint': 9 16 | 'right_ankle_pitch_joint': 10 17 | 'right_ankle_roll_joint': 11 18 | 'waist_yaw_joint': 12 19 | 'waist_roll_joint': 13 20 | 'waist_pitch_joint': 14 21 | 'left_shoulder_pitch_joint': 15 22 | 'left_shoulder_roll_joint': 16 23 | 'left_shoulder_yaw_joint': 17 24 | 'left_elbow_joint': 18 25 | 'left_wrist_roll_joint': 19 26 | 'left_wrist_pitch_joint': 20 27 | 'left_wrist_yaw_joint': 21 28 | 'left_hand_index_0_joint': 22 29 | 'left_hand_index_1_joint': 23 30 | 'left_hand_middle_0_joint': 24 31 | 'left_hand_middle_1_joint': 25 32 | 'left_hand_thumb_0_joint': 26 33 | 'left_hand_thumb_1_joint': 27 34 | 'left_hand_thumb_2_joint': 28 35 | 'right_shoulder_pitch_joint': 29 36 | 'right_shoulder_roll_joint': 30 37 | 'right_shoulder_yaw_joint': 31 38 | 'right_elbow_joint': 32 39 | 'right_wrist_roll_joint': 33 40 | 'right_wrist_pitch_joint': 34 41 | 'right_wrist_yaw_joint': 35 42 | 'right_hand_index_0_joint': 36 43 | 'right_hand_index_1_joint': 37 44 | 'right_hand_middle_0_joint': 38 45 | 'right_hand_middle_1_joint': 39 46 | 'right_hand_thumb_0_joint': 40 47 | 'right_hand_thumb_1_joint': 41 48 | 'right_hand_thumb_2_joint': 42 49 | -------------------------------------------------------------------------------- /docs/pages/references/release_notes.rst: -------------------------------------------------------------------------------- 1 | Release Notes 2 | ============= 3 | 4 | v0.1.0 5 | ------ 6 | 7 | This initial release of Isaac Lab Arena delivers the first version of the 8 | composable task definition API. 9 | Also included are example workflows for static manipulation tasks and loco-manipulation 10 | tasks including GR00T GN1.5 finetuning and evaluation. 11 | 12 | Key features of this release include: 13 | 14 | - **Composable Task Definition:** Base-class definition for ``Task``, ``Embodiment``, and ``Scene`` 15 | that can be subclassed to create new tasks, embodiments, and scenes. 16 | ``ArenaEnvBuilder`` for converting ``Scene``, ``Embodiment``, and ``Task`` into an 17 | Isaac Lab runnable environment. 18 | - **Metrics:** Mechanism for adding task-specific metrics which are reported during evaluation. 19 | - **Isaac Lab Mimic Integration:** Integration with Isaac Lab Mimic to automatically generate Mimic definitions for 20 | available tasks. 21 | - **Example Workflows:** Two example workflows for static manipulation tasks and loco-manipulation tasks. 22 | - **GR00T GN1.5 Integration:** Integration with GR00T GN1.5 including a example workflows for finetuning and evaluating 23 | the model on the static and loco-manipulation workflows. 24 | 25 | Known limitations: 26 | 27 | - **Number of Environments/Tasks:** This initial is intended to validation the composable task 28 | definition API, and comes with a limited set of tasks and workflows. 29 | - **Loco-manipulation GR00T GN1.5 finetuning:** GR00T GN1.5 finetuning for loco-manipulation 30 | requires a large amount of GPU resources. (Note that static manipulation finetuning can be 31 | performed on a single GPU.) 32 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/reload_modules.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | 7 | def reload_arena_modules(): 8 | """Reload all isaaclab_arena modules.""" 9 | import importlib 10 | import os 11 | import sys 12 | 13 | # Clear Python's bytecode cache 14 | if hasattr(importlib, "invalidate_caches"): 15 | importlib.invalidate_caches() 16 | 17 | # Get all isaaclab_arena modules currently loaded 18 | isaaclab_arena_modules = [ 19 | (name, module) 20 | for name, module in sys.modules.items() 21 | if name.startswith("isaaclab_arena") and module is not None 22 | ] 23 | 24 | if len(isaaclab_arena_modules) == 0: 25 | print("No isaaclab_arena modules found") 26 | return 27 | 28 | # We skip this step due to import issues in our asset registry 29 | # # Reload modules from bottom to top (deepest/leaf modules first) 30 | # isaaclab_arena_modules.sort(key=lambda x: x[0].count('.'), reverse=True) 31 | 32 | for module_name, module in isaaclab_arena_modules: 33 | try: 34 | # Delete the .pyc cache file to force recompilation from source 35 | module_cached = getattr(module, "__cached__", None) 36 | if module_cached and os.path.exists(module_cached): 37 | os.remove(module_cached) 38 | 39 | print(f"Reloading {module_name}") 40 | importlib.reload(module) 41 | 42 | except Exception as e: 43 | print(f"[WARNING] Failed to reload {module_name}: {e}") 44 | -------------------------------------------------------------------------------- /isaaclab_arena/metrics/recorder_manager_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab.managers import DatasetExportMode 7 | from isaaclab.managers.recorder_manager import RecorderManagerBaseCfg 8 | 9 | from isaaclab_arena.metrics.metric_base import MetricBase 10 | from isaaclab_arena.utils.configclass import make_configclass 11 | 12 | 13 | def metrics_to_recorder_manager_cfg(metrics: list[MetricBase] | None) -> RecorderManagerBaseCfg | None: 14 | """Converts a list of metrics to a recorder manager configuration. 15 | 16 | Args: 17 | metrics(list[MetricBase] | None): The list of metrics to convert to a 18 | recorder manager configuration. 19 | 20 | Returns: 21 | The recorder manager configuration. None if no metrics are provided. 22 | """ 23 | if metrics is None: 24 | return None 25 | # For each metric, grad it's RecorderTermCfg and add it to the output configclass fields list. 26 | configclass_fields: list[tuple[str, type, object]] = [] 27 | for metric in metrics: 28 | configclass_fields.append((metric.name, type(metric.get_recorder_term_cfg()), metric.get_recorder_term_cfg())) 29 | # Make a configclass for the recorder manager configuration. 30 | recorder_cfg_cls = make_configclass("RecorderManagerCfg", configclass_fields, bases=(RecorderManagerBaseCfg,)) 31 | recorder_cfg = recorder_cfg_cls() 32 | # Export all episodes to file. 33 | recorder_cfg.dataset_export_mode = DatasetExportMode.EXPORT_ALL 34 | return recorder_cfg 35 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_affordance_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import pytest 7 | 8 | from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function 9 | 10 | HEADLESS = True 11 | 12 | 13 | def _test_affordance_base(simulation_app): 14 | 15 | from isaaclab_arena.affordances.openable import Openable 16 | from isaaclab_arena.assets.asset import Asset 17 | 18 | class NotAnAsset: 19 | 20 | def __init__(self, blah: str, **kwargs): 21 | super().__init__(**kwargs) 22 | self.blah = blah 23 | 24 | class OpenableAsset(Asset, Openable): 25 | 26 | def __init__(self, **kwargs): 27 | super().__init__(**kwargs) 28 | 29 | class OpenableNotAnAsset(NotAnAsset, Openable): 30 | 31 | def __init__(self, **kwargs): 32 | super().__init__(**kwargs) 33 | 34 | _ = OpenableAsset(name="test_name", openable_joint_name="test_joint_name", openable_open_threshold=0.5) 35 | 36 | with pytest.raises(TypeError) as exception_info: 37 | _ = OpenableNotAnAsset(blah="test_name", openable_joint_name="test_joint_name", openable_open_threshold=0.5) 38 | assert "Can't instantiate abstract class" in str(exception_info.value) 39 | 40 | return True 41 | 42 | 43 | def test_affordance_base(): 44 | result = run_simulation_app_function( 45 | _test_affordance_base, 46 | headless=HEADLESS, 47 | ) 48 | assert result, "Test failed" 49 | 50 | 51 | if __name__ == "__main__": 52 | test_affordance_base() 53 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1/gr00t_26dof_joint_space.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Expected input & output joint names following listed order for groot state/action space 7 | joints: 8 | left_arm: 9 | - left_shoulder_pitch_joint 10 | - left_shoulder_roll_joint 11 | - left_shoulder_yaw_joint 12 | - left_elbow_pitch_joint 13 | - left_wrist_yaw_joint 14 | - left_wrist_roll_joint 15 | - left_wrist_pitch_joint 16 | right_arm: 17 | - right_shoulder_pitch_joint 18 | - right_shoulder_roll_joint 19 | - right_shoulder_yaw_joint 20 | - right_elbow_pitch_joint 21 | - right_wrist_yaw_joint 22 | - right_wrist_roll_joint 23 | - right_wrist_pitch_joint 24 | left_hand: 25 | - L_pinky_proximal_joint 26 | - L_ring_proximal_joint 27 | - L_middle_proximal_joint 28 | - L_index_proximal_joint 29 | - L_thumb_proximal_yaw_joint 30 | - L_thumb_proximal_pitch_joint 31 | # Mimic joints 32 | # - L_index_intermediate_joint 33 | # - L_middle_intermediate_joint 34 | # - L_ring_intermediate_joint 35 | # - L_pinky_intermediate_joint 36 | # - L_thumb_distal_joint 37 | right_hand: 38 | - R_pinky_proximal_joint 39 | - R_ring_proximal_joint 40 | - R_middle_proximal_joint 41 | - R_index_proximal_joint 42 | - R_thumb_proximal_yaw_joint 43 | - R_thumb_proximal_pitch_joint 44 | # Mimic joints 45 | # - R_index_intermediate_joint 46 | # - R_middle_intermediate_joint 47 | # - R_ring_intermediate_joint 48 | # - R_pinky_intermediate_joint 49 | # - R_thumb_distal_joint 50 | -------------------------------------------------------------------------------- /isaaclab_arena/examples/example_env_notebook.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # %% 7 | 8 | import torch 9 | import tqdm 10 | 11 | import pinocchio # noqa: F401 12 | from isaaclab.app import AppLauncher 13 | 14 | print("Launching simulation app once in notebook") 15 | simulation_app = AppLauncher() 16 | 17 | 18 | # %% 19 | from isaaclab_arena.utils.reload_modules import reload_arena_modules 20 | 21 | reload_arena_modules() 22 | from isaaclab_arena_environments.cli import get_arena_builder_from_cli, get_isaaclab_arena_environments_cli_parser 23 | 24 | args_parser = get_isaaclab_arena_environments_cli_parser() 25 | 26 | # GR1 Open Microwave 27 | args_cli = args_parser.parse_args([ 28 | "gr1_open_microwave", 29 | "--object", 30 | "cracker_box", 31 | ]) 32 | 33 | # Pick and Place 34 | # args_cli = args_parser.parse_args([ 35 | # "kitchen_pick_and_place", 36 | # "--object", 37 | # "cracker_box", 38 | # "--background", 39 | # "kitchen", 40 | # "--embodiment", 41 | # "franka", 42 | # ]) 43 | 44 | arena_builder = get_arena_builder_from_cli(args_cli) 45 | env = arena_builder.make_registered() 46 | env.reset() 47 | 48 | # %% 49 | 50 | # Run some zero actions. 51 | NUM_STEPS = 100 52 | for _ in tqdm.tqdm(range(NUM_STEPS)): 53 | with torch.inference_mode(): 54 | actions = torch.zeros(env.action_space.shape, device=env.unwrapped.device) 55 | env.step(actions) 56 | 57 | # %% 58 | from isaaclab_arena.utils.isaaclab_utils.simulation_app import teardown_simulation_app 59 | 60 | teardown_simulation_app(suppress_exceptions=False, make_new_stage=True) 61 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | joints: 7 | "left_hip_pitch_joint": 0 8 | "right_hip_pitch_joint": 1 9 | "waist_yaw_joint": 2 10 | "left_hip_roll_joint": 3 11 | "right_hip_roll_joint": 4 12 | "waist_roll_joint": 5 13 | "left_hip_yaw_joint": 6 14 | "right_hip_yaw_joint": 7 15 | "waist_pitch_joint": 8 16 | "left_knee_joint": 9 17 | "right_knee_joint": 10 18 | "left_shoulder_pitch_joint": 11 19 | "right_shoulder_pitch_joint": 12 20 | "left_ankle_pitch_joint": 13 21 | "right_ankle_pitch_joint": 14 22 | "left_shoulder_roll_joint": 15 23 | "right_shoulder_roll_joint": 16 24 | "left_ankle_roll_joint": 17 25 | "right_ankle_roll_joint": 18 26 | "left_shoulder_yaw_joint": 19 27 | "right_shoulder_yaw_joint": 20 28 | "left_elbow_joint": 21 29 | "right_elbow_joint": 22 30 | "left_wrist_roll_joint": 23 31 | "right_wrist_roll_joint": 24 32 | "left_wrist_pitch_joint": 25 33 | "right_wrist_pitch_joint": 26 34 | "left_wrist_yaw_joint": 27 35 | "right_wrist_yaw_joint": 28 36 | "left_hand_index_0_joint": 29 37 | "left_hand_middle_0_joint": 30 38 | "left_hand_thumb_0_joint": 31 39 | "right_hand_index_0_joint": 32 40 | "right_hand_middle_0_joint": 33 41 | "right_hand_thumb_0_joint": 34 42 | "left_hand_index_1_joint": 35 43 | "left_hand_middle_1_joint": 36 44 | "left_hand_thumb_1_joint": 37 45 | "right_hand_index_1_joint": 38 46 | "right_hand_middle_1_joint": 39 47 | "right_hand_thumb_1_joint": 40 48 | "left_hand_thumb_2_joint": 41 49 | "right_hand_thumb_2_joint": 42 50 | 51 | total_joints: 43 52 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1/36dof_joint_space.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # GR1 Robot Joint Configuration used in the action joint space 7 | # Maps joint names to joint indices for easy reference 8 | joints: 9 | # arm joints 10 | "left_shoulder_pitch_joint": 0 11 | "right_shoulder_pitch_joint": 1 12 | "left_shoulder_roll_joint": 2 13 | "right_shoulder_roll_joint": 3 14 | "left_shoulder_yaw_joint": 4 15 | "right_shoulder_yaw_joint": 5 16 | "left_elbow_pitch_joint": 6 17 | "right_elbow_pitch_joint": 7 18 | "left_wrist_yaw_joint": 8 19 | "right_wrist_yaw_joint": 9 20 | "left_wrist_roll_joint": 10 21 | "right_wrist_roll_joint": 11 22 | "left_wrist_pitch_joint": 12 23 | "right_wrist_pitch_joint": 13 24 | 25 | # hand joints 26 | "L_index_proximal_joint": 14 27 | "L_middle_proximal_joint": 15 28 | "L_pinky_proximal_joint": 16 29 | "L_ring_proximal_joint": 17 30 | "L_thumb_proximal_yaw_joint": 18 31 | "R_index_proximal_joint": 19 32 | "R_middle_proximal_joint": 20 33 | "R_pinky_proximal_joint": 21 34 | "R_ring_proximal_joint": 22 35 | "R_thumb_proximal_yaw_joint": 23 36 | "L_index_intermediate_joint": 24 37 | "L_middle_intermediate_joint": 25 38 | "L_pinky_intermediate_joint": 26 39 | "L_ring_intermediate_joint": 27 40 | "L_thumb_proximal_pitch_joint": 28 41 | "R_index_intermediate_joint": 29 42 | "R_middle_intermediate_joint": 30 43 | "R_pinky_intermediate_joint": 31 44 | "R_ring_intermediate_joint": 32 45 | "R_thumb_proximal_pitch_joint": 33 46 | "L_thumb_distal_joint": 34 47 | "R_thumb_distal_joint": 35 48 | 49 | # Additional metadata 50 | total_joints: 36 51 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/policy/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class WBCPolicy(ABC): 10 | """Base class for implementing control policies in the Gear'WBC framework. 11 | 12 | A Policy defines how an agent should behave in an environment by mapping observations 13 | to actions. This abstract base class provides the interface that all concrete policy 14 | implementations must follow. 15 | """ 16 | 17 | def set_goal(self, goal: dict[str, any]): 18 | """Set the command from the planner that the policy should follow. 19 | 20 | Args: 21 | goal: Dictionary containing high-level commands or goals from the planner 22 | """ 23 | pass 24 | 25 | def set_observation(self, observation: dict[str, any]): 26 | """Update the policy's current observation of the environment. 27 | 28 | Args: 29 | observation: Dictionary containing the current state/observation of the environment 30 | """ 31 | self.observation = observation 32 | 33 | @abstractmethod 34 | def get_action(self, time: float | None = None) -> dict[str, any]: 35 | """Compute and return the next action at the specified time, based on current observation 36 | and planner command. 37 | 38 | Args: 39 | time: Optional "monotonic time" for time-dependent policies 40 | 41 | Returns: 42 | Dictionary containing the action to be executed 43 | """ 44 | 45 | def close(self): 46 | """Clean up any resources used by the policy.""" 47 | pass 48 | -------------------------------------------------------------------------------- /docker/setup/install_gr00t_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Script to install GR00T policy dependencies 5 | # This script is called from the Dockerfile when INSTALL_GROOT is true 6 | 7 | echo "Installing GR00T with dependency group: $GROOT_DEPS_GROUP" 8 | 9 | # Set CUDA environment variables for GR00T installation 10 | export CUDA_HOME=/usr/local/cuda-12.8 11 | export PATH=/usr/local/cuda-12.8/bin:${PATH} 12 | export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-} 13 | export TORCH_CUDA_ARCH_LIST=8.0+PTX 14 | 15 | echo "CUDA environment variables set:" 16 | echo "CUDA_HOME=$CUDA_HOME" 17 | echo "PATH=$PATH" 18 | echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" 19 | echo "TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST" 20 | 21 | # Installing dependencies for system-level media libraries 22 | echo "Installing system-level media libraries..." 23 | sudo apt-get update && sudo apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/* 24 | 25 | # Upgrade packaging tools to avoid setuptools issues 26 | echo "Upgrading packaging tools..." 27 | /isaac-sim/python.sh -m pip install --upgrade setuptools packaging wheel 28 | 29 | # Install GR00T with the specified dependency group 30 | echo "Installing Isaac-GR00T with dependency group: $GROOT_DEPS_GROUP" 31 | /isaac-sim/python.sh -m pip install --no-build-isolation --use-pep517 -e ${WORKDIR}/submodules/Isaac-GR00T/[$GROOT_DEPS_GROUP] 32 | 33 | # Install flash-attn (specific version for compatibility) 34 | echo "Installing flash-attn..." 35 | /isaac-sim/python.sh -m pip install --no-build-isolation --use-pep517 flash-attn==2.7.1.post4 36 | 37 | # Ensure pytorch torchrun script is in PATH 38 | echo "Ensuring pytorch torchrun script is in PATH..." 39 | echo "export PATH=/isaac-sim/kit/python/bin:\$PATH" >> /etc/bash.bashrc 40 | 41 | echo "GR00T dependencies installation completed successfully" 42 | -------------------------------------------------------------------------------- /isaaclab_arena/environments/isaaclab_arena_environment.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from __future__ import annotations 7 | 8 | from collections.abc import Callable 9 | from dataclasses import MISSING 10 | from typing import TYPE_CHECKING 11 | 12 | from isaaclab.utils import configclass 13 | 14 | if TYPE_CHECKING: 15 | from isaaclab_arena.embodiments.embodiment_base import EmbodimentBase 16 | from isaaclab_arena.environments.isaaclab_arena_manager_based_env import IsaacLabArenaManagerBasedRLEnvCfg 17 | from isaaclab_arena.orchestrator.orchestrator_base import OrchestratorBase 18 | from isaaclab_arena.scene.scene import Scene 19 | from isaaclab_arena.tasks.task_base import TaskBase 20 | from isaaclab_arena.teleop_devices.teleop_device_base import TeleopDeviceBase 21 | 22 | 23 | @configclass 24 | class IsaacLabArenaEnvironment: 25 | """Describes an environment in IsaacLab Arena.""" 26 | 27 | name: str = MISSING 28 | """The name of the environment.""" 29 | 30 | embodiment: EmbodimentBase = MISSING 31 | """The embodiment to use in the environment.""" 32 | 33 | scene: Scene = MISSING 34 | """The scene to use in the environment.""" 35 | 36 | task: TaskBase = MISSING 37 | """The task to use in the environment.""" 38 | 39 | teleop_device: TeleopDeviceBase | None = None 40 | """The teleop device to use in the environment.""" 41 | 42 | orchestrator: OrchestratorBase | None = None 43 | """The orchestrator to use in the environment.""" 44 | 45 | env_cfg_callback: Callable[IsaacLabArenaManagerBasedRLEnvCfg] | None = None 46 | """A callback function that modifies the environment configuration.""" 47 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Expected input & output joint names following listed order for groot state/action space 7 | joints: 8 | left_leg: 9 | - left_hip_pitch_joint 10 | - left_hip_roll_joint 11 | - left_hip_yaw_joint 12 | - left_knee_joint 13 | - left_ankle_pitch_joint 14 | - left_ankle_roll_joint 15 | right_leg: 16 | - right_hip_pitch_joint 17 | - right_hip_roll_joint 18 | - right_hip_yaw_joint 19 | - right_knee_joint 20 | - right_ankle_pitch_joint 21 | - right_ankle_roll_joint 22 | waist: 23 | - waist_yaw_joint 24 | - waist_roll_joint 25 | - waist_pitch_joint 26 | left_arm: 27 | - left_shoulder_pitch_joint 28 | - left_shoulder_roll_joint 29 | - left_shoulder_yaw_joint 30 | - left_elbow_joint 31 | - left_wrist_roll_joint 32 | - left_wrist_pitch_joint 33 | - left_wrist_yaw_joint 34 | left_hand: 35 | - left_hand_index_0_joint 36 | - left_hand_index_1_joint 37 | - left_hand_middle_0_joint 38 | - left_hand_middle_1_joint 39 | - left_hand_thumb_0_joint 40 | - left_hand_thumb_1_joint 41 | - left_hand_thumb_2_joint 42 | right_arm: 43 | - right_shoulder_pitch_joint 44 | - right_shoulder_roll_joint 45 | - right_shoulder_yaw_joint 46 | - right_elbow_joint 47 | - right_wrist_roll_joint 48 | - right_wrist_pitch_joint 49 | - right_wrist_yaw_joint 50 | right_hand: 51 | - right_hand_index_0_joint 52 | - right_hand_index_1_joint 53 | - right_hand_middle_0_joint 54 | - right_hand_middle_1_joint 55 | - right_hand_thumb_0_joint 56 | - right_hand_thumb_1_joint 57 | - right_hand_thumb_2_joint 58 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/usd_pose_helpers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from pxr import Usd, UsdGeom, UsdSkel 7 | 8 | from isaaclab_arena.utils.pose import Pose 9 | 10 | 11 | def get_prim_pose_in_default_prim_frame(prim: Usd.Prim, stage: Usd.Stage) -> Pose: 12 | """Get the pose of a prim in the default prim's local frame. 13 | 14 | Args: 15 | prim: The prim to get the pose of. 16 | stage: The stage to get the default prim from. 17 | 18 | Returns: 19 | The pose of the prim in the default prim's local frame. 20 | """ 21 | # Get the default prim of the stage 22 | default_prim = stage.GetDefaultPrim() 23 | if not default_prim: 24 | raise RuntimeError("Stage does not have a default prim set.") 25 | 26 | # Compute prim's transform in default prim's local frame 27 | xformable_prim = UsdGeom.Xformable(prim) 28 | xformable_default = UsdGeom.Xformable(default_prim) 29 | 30 | prim_T_world = xformable_prim.ComputeLocalToWorldTransform(Usd.TimeCode.Default()) 31 | default_T_world = xformable_default.ComputeLocalToWorldTransform(Usd.TimeCode.Default()) 32 | 33 | # matrix_default_to_world may be singular if default prim is the pseudo-root. Warn user. 34 | if default_T_world.GetDeterminant() == 0: 35 | raise RuntimeError("Default prim's world transform is singular.") 36 | 37 | default_T_world = default_T_world.GetInverse() 38 | prim_T_default = prim_T_world * default_T_world 39 | 40 | pos, rot, _ = UsdSkel.DecomposeTransform(prim_T_default) 41 | rot_tuple = (rot.GetReal(), rot.GetImaginary()[0], rot.GetImaginary()[1], rot.GetImaginary()[2]) 42 | pos_tuple = (pos[0], pos[1], pos[2]) 43 | return Pose(position_xyz=pos_tuple, rotation_wxyz=rot_tuple) 44 | -------------------------------------------------------------------------------- /isaaclab_arena/teleop_devices/keyboard.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | from isaaclab.devices.device_base import DevicesCfg 20 | from isaaclab.devices.keyboard import Se3KeyboardCfg 21 | 22 | from isaaclab_arena.assets.register import register_device 23 | from isaaclab_arena.teleop_devices.teleop_device_base import TeleopDeviceBase 24 | 25 | 26 | @register_device 27 | class KeyboardTeleopDevice(TeleopDeviceBase): 28 | """ 29 | Teleop device for keyboard. 30 | """ 31 | 32 | name = "keyboard" 33 | 34 | def __init__(self, sim_device: str | None = None, pos_sensitivity: float = 0.05, rot_sensitivity: float = 0.05): 35 | super().__init__(sim_device=sim_device) 36 | self.pos_sensitivity = pos_sensitivity 37 | self.rot_sensitivity = rot_sensitivity 38 | 39 | def get_teleop_device_cfg(self, embodiment: object | None = None): 40 | return DevicesCfg( 41 | devices={ 42 | "keyboard": Se3KeyboardCfg( 43 | pos_sensitivity=self.pos_sensitivity, 44 | rot_sensitivity=self.rot_sensitivity, 45 | sim_device=self.sim_device, 46 | ), 47 | } 48 | ) 49 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/data_utils/image_conversion.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | import torch 8 | 9 | import cv2 10 | 11 | 12 | def resize_frames_with_padding( 13 | frames: torch.Tensor | np.ndarray, target_image_size: tuple, bgr_conversion: bool = False, pad_img: bool = True 14 | ) -> np.ndarray: 15 | """Process batch of frames with padding and resizing vectorized 16 | Args: 17 | frames: np.ndarray of shape [N, 256, 160, 3] 18 | target_image_size: target size (height, width) 19 | bgr_conversion: whether to convert BGR to RGB 20 | pad_img: whether to resize images 21 | """ 22 | if isinstance(frames, torch.Tensor): 23 | frames = frames.cpu().numpy() 24 | elif not isinstance(frames, np.ndarray): 25 | raise ValueError(f"Invalid frame type: {type(frames)}") 26 | 27 | if bgr_conversion: 28 | frames = cv2.cvtColor(frames, cv2.COLOR_BGR2RGB) 29 | 30 | if pad_img: 31 | top_padding = (frames.shape[2] - frames.shape[1]) // 2 32 | bottom_padding = top_padding 33 | 34 | # Add padding to all frames at once 35 | frames = np.pad( 36 | frames, 37 | pad_width=((0, 0), (top_padding, bottom_padding), (0, 0), (0, 0)), 38 | mode="constant", 39 | constant_values=0, 40 | ) 41 | 42 | # Resize all frames at once 43 | # frames.shape is (N, height, width, channels) 44 | # target_image_size is (height, width) 45 | # cv2.resize expects (width, height) 46 | if frames.shape[1:3] != target_image_size: 47 | target_size_cv2 = (target_image_size[1], target_image_size[0]) # Convert to (width, height) 48 | frames = np.stack([cv2.resize(f, target_size_cv2) for f in frames]) 49 | 50 | return frames 51 | -------------------------------------------------------------------------------- /isaaclab_arena/teleop_devices/spacemouse.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | from isaaclab.devices.device_base import DevicesCfg 20 | from isaaclab.devices.spacemouse import Se3SpaceMouseCfg 21 | 22 | from isaaclab_arena.assets.register import register_device 23 | from isaaclab_arena.teleop_devices.teleop_device_base import TeleopDeviceBase 24 | 25 | 26 | @register_device 27 | class SpacemouseTeleopDevice(TeleopDeviceBase): 28 | """ 29 | Teleop device for spacemouse. 30 | """ 31 | 32 | name = "spacemouse" 33 | 34 | def __init__(self, sim_device: str | None = None, pos_sensitivity: float = 0.05, rot_sensitivity: float = 0.05): 35 | super().__init__(sim_device=sim_device) 36 | self.pos_sensitivity = pos_sensitivity 37 | self.rot_sensitivity = rot_sensitivity 38 | 39 | def get_teleop_device_cfg(self, embodiment: object | None = None): 40 | return DevicesCfg( 41 | devices={ 42 | "spacemouse": Se3SpaceMouseCfg( 43 | pos_sensitivity=self.pos_sensitivity, 44 | rot_sensitivity=self.rot_sensitivity, 45 | sim_device=self.sim_device, 46 | ), 47 | } 48 | ) 49 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/data_utils/robot_eef_pose.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | import torch 8 | from dataclasses import dataclass 9 | 10 | 11 | @dataclass 12 | class EefPose: 13 | eef_pos: torch.Tensor 14 | """Eef position in meters""" 15 | 16 | eef_quat: torch.Tensor 17 | """Eef orientation in quaternions w, x, y, z""" 18 | 19 | device: torch.device 20 | """Device to store the tensor on""" 21 | 22 | @staticmethod 23 | def identity(device: torch.device, batch_size: int = 1): 24 | return EefPose( 25 | eef_pos=torch.zeros((batch_size, 3), device=device), 26 | eef_quat=torch.tensor([1, 0, 0, 0], device=device).repeat(batch_size, 1), 27 | device=device, 28 | ) 29 | 30 | def to_array(self) -> np.ndarray: 31 | return self.eef_pose.cpu().numpy() 32 | 33 | @staticmethod 34 | def from_array(pos_array: np.ndarray, quat_array: np.ndarray, device: torch.device) -> "EefPose": 35 | return EefPose( 36 | eef_pos=torch.from_numpy(pos_array).to(device), 37 | eef_quat=torch.from_numpy(quat_array).to(device), 38 | device=device, 39 | ) 40 | 41 | def set_eef_pose(self, eef_pos: torch.Tensor, eef_quat: torch.Tensor): 42 | self.eef_pos = eef_pos.to(self.device) 43 | self.eef_quat = eef_quat.to(self.device) 44 | 45 | def get_eef_pose(self, device: torch.device = None) -> torch.Tensor: 46 | # NOTE(xinjieyao, 2025-09-26): compose it on the fly to avoid invariance issues where eef_pos could be modified after eef_pose has been set 47 | eef_pose = torch.cat([self.eef_pos, self.eef_quat], dim=1) 48 | if device is None: 49 | return eef_pose 50 | else: 51 | return eef_pose.to(device) 52 | -------------------------------------------------------------------------------- /docs/pages/quickstart/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | This page describes how to install Isaac Lab Arena from source inside a Docker container. 5 | 6 | Supported Systems 7 | ----------------- 8 | 9 | Isaac Lab Arena runs on Isaac Sim ``5.1.0`` and Isaac Lab ``2.3.0``. 10 | The dependencies are installed automatically during the Docker build process. 11 | Hardware requirements for Isaac Lab Arena are shared with Isaac Sim, and are detailed in 12 | `Isaac Sim Requirements `_. 13 | 14 | **GR00T fine-tuning:** Our example workflows include (optional) fine-tuning 15 | of the `GR00T model `_. 16 | These workflows have additional requirements, notably that they do not support Blackwell GPUs, and 17 | require large amounts of GPU memory. 18 | Specific additional requirements for GR00T fine-tuning are detailed in the respective workflow pages. 19 | 20 | 21 | Installation via Docker 22 | ----------------------- 23 | 24 | 25 | Isaac Lab Arena supports installation from source inside a Docker container. 26 | Future versions of Isaac Lab Arena, we will support a larger range of 27 | installation options. 28 | 29 | 30 | 1. **Clone the repository and initialize submodules:** 31 | 32 | :isaaclab_arena_git_clone_code_block: 33 | 34 | .. code-block:: bash 35 | 36 | git submodule update --init --recursive 37 | 38 | 2. **Launch the docker container:** 39 | 40 | 41 | :docker_run_default: 42 | 43 | 44 | for more details see :doc:`docker_containers`. 45 | 46 | 3. **Optionally verify installation by running tests:** 47 | 48 | .. code-block:: bash 49 | 50 | pytest -sv -m with_cameras isaaclab_arena/tests/ --ignore=isaaclab_arena/tests/policy/ 51 | pytest -sv -m "not with_cameras" isaaclab_arena/tests/ --ignore=isaaclab_arena/tests/policy/ 52 | 53 | With ``isaaclab_arena`` installed and the docker running, you're ready to build your first IsaacLab-Arena Environment. See :doc:`first_arena_env` to get started. 54 | -------------------------------------------------------------------------------- /isaaclab_arena/examples/compile_env_notebook.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # %% 7 | 8 | import torch 9 | import tqdm 10 | 11 | import pinocchio # noqa: F401 12 | from isaaclab.app import AppLauncher 13 | 14 | print("Launching simulation app once in notebook") 15 | simulation_app = AppLauncher() 16 | 17 | from isaaclab_arena.assets.asset_registry import AssetRegistry 18 | from isaaclab_arena.cli.isaaclab_arena_cli import get_isaaclab_arena_cli_parser 19 | from isaaclab_arena.environments.arena_env_builder import ArenaEnvBuilder 20 | from isaaclab_arena.environments.isaaclab_arena_environment import IsaacLabArenaEnvironment 21 | from isaaclab_arena.scene.scene import Scene 22 | from isaaclab_arena.tasks.dummy_task import DummyTask 23 | from isaaclab_arena.utils.pose import Pose 24 | 25 | asset_registry = AssetRegistry() 26 | 27 | background = asset_registry.get_asset_by_name("kitchen")() 28 | embodiment = asset_registry.get_asset_by_name("franka")() 29 | cracker_box = asset_registry.get_asset_by_name("cracker_box")() 30 | 31 | cracker_box.set_initial_pose(Pose(position_xyz=(0.4, 0.0, 0.1), rotation_wxyz=(1.0, 0.0, 0.0, 0.0))) 32 | 33 | scene = Scene(assets=[background, cracker_box]) 34 | isaaclab_arena_environment = IsaacLabArenaEnvironment( 35 | name="reference_object_test", 36 | embodiment=embodiment, 37 | scene=scene, 38 | task=DummyTask(), 39 | teleop_device=None, 40 | ) 41 | 42 | args_cli = get_isaaclab_arena_cli_parser().parse_args([]) 43 | env_builder = ArenaEnvBuilder(isaaclab_arena_environment, args_cli) 44 | env = env_builder.make_registered() 45 | env.reset() 46 | 47 | # %% 48 | 49 | # Run some zero actions. 50 | NUM_STEPS = 1000 51 | for _ in tqdm.tqdm(range(NUM_STEPS)): 52 | with torch.inference_mode(): 53 | actions = torch.zeros(env.action_space.shape, device=env.unwrapped.device) 54 | env.step(actions) 55 | 56 | # %% 57 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/utils/homie_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | import yaml 8 | from typing import Any 9 | 10 | 11 | def load_config(config_path: str) -> dict[str, Any]: 12 | """Load and process the YAML configuration file""" 13 | with open(config_path) as f: 14 | config = yaml.safe_load(f) 15 | 16 | # Convert lists to numpy arrays where needed 17 | array_keys = ["default_angles", "cmd_scale", "cmd_init"] 18 | for key in array_keys: 19 | if key in config: 20 | config[key] = np.array(config[key], dtype=np.float32) 21 | 22 | return config 23 | 24 | 25 | def quat_rotate_inverse(q: np.ndarray, v: np.ndarray) -> np.ndarray: 26 | """Rotate vector v by the inverse of quaternion q""" 27 | w = q[..., 0] 28 | x = q[..., 1] 29 | y = q[..., 2] 30 | z = q[..., 3] 31 | 32 | q_conj = np.array([w, -x, -y, -z]) 33 | 34 | return np.array([ 35 | v[0] * (q_conj[0] ** 2 + q_conj[1] ** 2 - q_conj[2] ** 2 - q_conj[3] ** 2) 36 | + v[1] * 2 * (q_conj[1] * q_conj[2] - q_conj[0] * q_conj[3]) 37 | + v[2] * 2 * (q_conj[1] * q_conj[3] + q_conj[0] * q_conj[2]), 38 | v[0] * 2 * (q_conj[1] * q_conj[2] + q_conj[0] * q_conj[3]) 39 | + v[1] * (q_conj[0] ** 2 - q_conj[1] ** 2 + q_conj[2] ** 2 - q_conj[3] ** 2) 40 | + v[2] * 2 * (q_conj[2] * q_conj[3] - q_conj[0] * q_conj[1]), 41 | v[0] * 2 * (q_conj[1] * q_conj[3] - q_conj[0] * q_conj[2]) 42 | + v[1] * 2 * (q_conj[2] * q_conj[3] + q_conj[0] * q_conj[1]) 43 | + v[2] * (q_conj[0] ** 2 - q_conj[1] ** 2 - q_conj[2] ** 2 + q_conj[3] ** 2), 44 | ]) 45 | 46 | 47 | def get_gravity_orientation(quat: np.ndarray) -> np.ndarray: 48 | """Get gravity vector in body frame""" 49 | gravity_vec = np.array([0.0, 0.0, -1.0]) 50 | return quat_rotate_inverse(quat, gravity_vec) 51 | -------------------------------------------------------------------------------- /isaaclab_arena/terms/events.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | 8 | from isaaclab.envs import ManagerBasedEnv 9 | from isaaclab.managers import SceneEntityCfg 10 | 11 | from isaaclab_arena.utils.pose import Pose 12 | 13 | 14 | def set_object_pose( 15 | env: ManagerBasedEnv, 16 | env_ids: torch.Tensor, 17 | asset_cfg: SceneEntityCfg, 18 | pose: Pose, 19 | ) -> None: 20 | if env_ids is None: 21 | return 22 | # Grab the object 23 | asset = env.scene[asset_cfg.name] 24 | num_envs = len(env_ids) 25 | # Convert the pose to the env frame 26 | pose_t_xyz_q_wxyz = pose.to_tensor(device=env.device).repeat(num_envs, 1) 27 | pose_t_xyz_q_wxyz[:, :3] += env.scene.env_origins[env_ids] 28 | # Set the pose and velocity 29 | asset.write_root_pose_to_sim(pose_t_xyz_q_wxyz, env_ids=env_ids) 30 | asset.write_root_velocity_to_sim(torch.zeros(1, 6, device=env.device), env_ids=env_ids) 31 | 32 | 33 | def set_object_pose_per_env( 34 | env: ManagerBasedEnv, 35 | env_ids: torch.Tensor, 36 | asset_cfg: SceneEntityCfg, 37 | pose_list: list[Pose], 38 | ) -> None: 39 | if env_ids is None: 40 | return 41 | 42 | # Grab the object 43 | asset = env.scene[asset_cfg.name] 44 | 45 | # Set the objects pose in each environment independently 46 | assert env_ids.ndim == 1 47 | for cur_env in env_ids.tolist(): 48 | # Convert the pose to the env frame 49 | pose = pose_list[cur_env] 50 | pose_t_xyz_q_wxyz = pose.to_tensor(device=env.device) 51 | pose_t_xyz_q_wxyz[:3] += env.scene.env_origins[cur_env, :].squeeze() 52 | # Set the pose and velocity 53 | asset.write_root_pose_to_sim(pose_t_xyz_q_wxyz, env_ids=torch.tensor([cur_env], device=env.device)) 54 | asset.write_root_velocity_to_sim( 55 | torch.zeros(1, 6, device=env.device), env_ids=torch.tensor([cur_env], device=env.device) 56 | ) 57 | -------------------------------------------------------------------------------- /docker/setup/install_cuda.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Script to install CUDA 12.8 for GR00T dependencies 5 | # This script is called from the Dockerfile when INSTALL_GROOT is true 6 | 7 | echo "Installing CUDA 12.8 for GR00T dependencies" 8 | 9 | # Source OS release information 10 | . /etc/os-release 11 | 12 | # Detect Ubuntu version and set appropriate CUDA repository 13 | case "$ID" in 14 | ubuntu) 15 | case "$VERSION_ID" in 16 | "20.04") cuda_repo="ubuntu2004";; 17 | "22.04") cuda_repo="ubuntu2204";; 18 | "24.04") cuda_repo="ubuntu2404";; 19 | *) echo "Unsupported Ubuntu $VERSION_ID"; exit 1;; 20 | esac ;; 21 | *) echo "Unsupported base OS: $ID"; exit 1 ;; 22 | esac 23 | 24 | echo "Detected Ubuntu $VERSION_ID, using repository: $cuda_repo" 25 | 26 | # Update package lists and install prerequisites 27 | apt-get update 28 | apt-get install -y --no-install-recommends wget gnupg ca-certificates 29 | 30 | # Download and install CUDA keyring 31 | wget -q https://developer.download.nvidia.com/compute/cuda/repos/${cuda_repo}/x86_64/cuda-keyring_1.1-1_all.deb 32 | dpkg -i cuda-keyring_1.1-1_all.deb 33 | rm -f cuda-keyring_1.1-1_all.deb 34 | 35 | # Download and install CUDA repository pin 36 | wget -q https://developer.download.nvidia.com/compute/cuda/repos/${cuda_repo}/x86_64/cuda-${cuda_repo}.pin 37 | mv cuda-${cuda_repo}.pin /etc/apt/preferences.d/cuda-repository-pin-600 38 | 39 | # Update package lists with new CUDA repository 40 | apt-get update 41 | 42 | # Install CUDA toolkit 12.8 43 | apt-get install -y --no-install-recommends cuda-toolkit-12-8 44 | 45 | # Clean up package cache 46 | apt-get -y autoremove 47 | apt-get clean 48 | rm -rf /var/lib/apt/lists/* 49 | 50 | # Set CUDA environment variables 51 | echo "export CUDA_HOME=/usr/local/cuda-12.8" >> /etc/environment 52 | echo "export PATH=/usr/local/cuda-12.8/bin:${PATH}" >> /etc/environment 53 | echo "export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-}" >> /etc/environment 54 | echo "export TORCH_CUDA_ARCH_LIST=8.0+PTX" >> /etc/environment 55 | 56 | echo "CUDA 12.8 installation completed successfully" 57 | -------------------------------------------------------------------------------- /isaaclab_arena/environments/isaaclab_arena_manager_based_env.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab.envs import ManagerBasedRLEnvCfg 7 | from isaaclab.envs.mimic_env_cfg import MimicEnvCfg 8 | from isaaclab.sim import SimulationCfg 9 | from isaaclab.utils import configclass 10 | 11 | from isaaclab_arena.environments.isaaclab_arena_environment import IsaacLabArenaEnvironment 12 | from isaaclab_arena.metrics.metric_base import MetricBase 13 | 14 | 15 | @configclass 16 | class IsaacLabArenaManagerBasedRLEnvCfg(ManagerBasedRLEnvCfg): 17 | """Configuration for an IsaacLab Arena environment.""" 18 | 19 | # NOTE(alexmillane, 2025-07-29): The following definitions are taken from the base class. 20 | # scene: InteractiveSceneCfg 21 | # observations: object 22 | # actions: object 23 | # events: object 24 | # terminations: object 25 | # recorders: object 26 | 27 | # Kill the unused managers 28 | commands = None 29 | rewards = None 30 | curriculum = None 31 | 32 | # Metrics 33 | metrics: list[MetricBase] | None = None 34 | 35 | # Isaaclab Arena Env. Held as a member to allow use of internal functions 36 | isaaclab_arena_env: IsaacLabArenaEnvironment | None = None 37 | 38 | # Overriding defaults from base class 39 | sim: SimulationCfg = SimulationCfg(dt=1 / 200, render_interval=2) 40 | decimation: int = 4 41 | episode_length_s: float = 50.0 42 | wait_for_textures: bool = False 43 | 44 | 45 | @configclass 46 | class IsaacArenaManagerBasedMimicEnvCfg(IsaacLabArenaManagerBasedRLEnvCfg, MimicEnvCfg): 47 | """Configuration for an IsaacLab Arena environment.""" 48 | 49 | # NOTE(alexmillane, 2025-09-10): The following members are defined in the MimicEnvCfg class. 50 | # Restated here for clarity. 51 | # datagen_config: DataGenConfig = DataGenConfig() 52 | # subtask_configs: dict[str, list[SubTaskConfig]] = {} 53 | # task_constraint_configs: list[SubTaskConstraintConfig] = [] 54 | pass 55 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | name: GitHub Pages 7 | 8 | on: 9 | push: 10 | branches: [ "main" ] 11 | 12 | # Concurrency control to prevent parallel runs on the same PR 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | permissions: 18 | contents: write 19 | pull-requests: write 20 | checks: write 21 | issues: read 22 | 23 | env: 24 | NGC_API_KEY: ${{ secrets.ARENA_NGC_API_KEY }} 25 | OMNI_PASS: ${{ secrets.OMNI_PASS }} 26 | OMNI_USER: ${{ secrets.OMNI_USER }} 27 | 28 | jobs: 29 | deploy_docs: 30 | name: Deploy the docs 31 | runs-on: [self-hosted, gpu] 32 | timeout-minutes: 30 33 | 34 | container: 35 | image: python:3.11-slim 36 | 37 | steps: 38 | - name: Install git (and tools needed by hooks) 39 | run: | 40 | apt-get update 41 | apt-get install -y --no-install-recommends git git-lfs clang-format ca-certificates make 42 | git --version 43 | git lfs version 44 | 45 | # Checkout Code 46 | - name: Checkout Code 47 | uses: actions/checkout@v4 48 | with: 49 | clean: true 50 | fetch-depth: 0 51 | fetch-tags: true 52 | 53 | # Fix "detected dubious ownership in repository" inside containers 54 | - name: Mark repo as safe for git 55 | run: git config --global --add safe.directory "$PWD" 56 | 57 | # Build docs 58 | - name: Build docs 59 | run: | 60 | cd docs 61 | pip3 install -r requirements.txt 62 | make SPHINXOPTS=-W multi-docs 63 | touch ./_build/.nojekyll 64 | 65 | - name: Copy redirect file 66 | run: | 67 | cp ./docs/_redirect/index.html ./docs/_build/index.html 68 | 69 | # Deploy to gh-pages 70 | - name: Deploy to gh-pages 71 | uses: peaceiris/actions-gh-pages@v3 72 | with: 73 | github_token: ${{ secrets.GITHUB_TOKEN }} 74 | publish_dir: ./docs/_build 75 | -------------------------------------------------------------------------------- /docs/pages/quickstart/docker_containers.rst: -------------------------------------------------------------------------------- 1 | Docker Containers 2 | ================= 3 | 4 | This first version of Isaac Lab Arena is designed to run inside a Docker container. 5 | 6 | 7 | We provide two docker containers for Isaac Lab Arena: 8 | 9 | - **Base**: Contains the Isaac Lab Arena code and all its dependencies. 10 | - **Base + GR00T**: Additionally includes GR00T and its dependencies. 11 | 12 | We include the two containers such that the user can choose between container with minimal 13 | dependencies (**Base**) or container with all dependencies (**Base + GR00T**). 14 | 15 | In order to start the containers run: 16 | 17 | .. tabs:: 18 | 19 | .. tab:: Base 20 | 21 | :docker_run_default: 22 | 23 | .. tab:: Base + GR00T 24 | 25 | :docker_run_gr00t: 26 | 27 | 28 | 29 | The run docker will build the container and then enter in interactive mode. 30 | 31 | .. note:: 32 | The container with all dependencies (**Base + GR00T**) is significantly larger than the container with minimal dependencies (**Base**), 33 | so it is recommended to use the **Base** container for development and the **Base + GR00T** container for GR00T policy post-training and evaluation. 34 | If you are not sure which container to use, we recommend using the **Base** container. 35 | If you want to use the **Base + GR00T** container for development, currently it is not supported to run on Blackwell GPUs, and DGX Spark. 36 | 37 | Mounted Directories 38 | ------------------- 39 | 40 | The run docker script will mount the following directories on the host machine to the container: 41 | 42 | - **Datasets**: from host: ``$HOME/datasets`` to container: ``/datasets`` 43 | - **Models**: from host: ``$HOME/models`` to container: ``/models`` 44 | - **Evaluation**: from host: ``$HOME/eval`` to container: ``/eval`` 45 | 46 | In our examples, we download input datasets and pre-trained models. 47 | It is useful to download these to a folder mapped on the host machine to avoid re-downloading 48 | between restarts of the container. 49 | These directories are configurable through argument to the run docker script. 50 | 51 | For a full list of arguments see the ``run_docker.sh`` script at 52 | ``isaac_arena/docker/run_docker.sh``. 53 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Isaac Lab Arena Contribution Rules 2 | 3 | This document describes the rules for contributing to Isaac Lab Arena 4 | 5 | 6 | #### Signing Your Work 7 | 8 | * We require that all contributors "sign-off" on their commits. 9 | This certifies that the contribution is your original work, or you have rights to submit 10 | it under the same license, or a compatible license. 11 | 12 | * Any contribution which contains commits that are not Signed-Off will not be accepted. 13 | 14 | * To sign off on a commit you simply use the `--signoff` (or `-s`) option when committing your changes: 15 | ```bash 16 | $ git commit -s -m "Add cool feature." 17 | ``` 18 | This will append the following to your commit message: 19 | ``` 20 | Signed-off-by: Your Name 21 | ``` 22 | 23 | * Full text of the DCO: 24 | 25 | ``` 26 | Developer Certificate of Origin Version 1.1 27 | 28 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 29 | 30 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 31 | ``` 32 | 33 | ``` 34 | Developer's Certificate of Origin 1.1 35 | 36 | By making a contribution to this project, I certify that: 37 | 38 | (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or 39 | 40 | (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or 41 | 42 | (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. 43 | 44 | (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/pages/concepts/concept_environment_design.rst: -------------------------------------------------------------------------------- 1 | Environment Design 2 | ================== 3 | 4 | IsaacLab Arena environment contains the main components used to create a manager-based RL environment. 5 | This includes the embodiment, scene, task and teleop device. 6 | 7 | Core Architecture 8 | ----------------- 9 | 10 | .. code-block:: python 11 | 12 | @configclass 13 | class IsaacLabArenaEnvironment: 14 | name: str = MISSING 15 | embodiment: EmbodimentBase = MISSING 16 | scene: Scene = MISSING 17 | task: TaskBase = MISSING 18 | teleop_device: TeleopDeviceBase | None = None 19 | 20 | class ArenaEnvBuilder: 21 | """Compose IsaacLab Arena → Isaac Lab configs.""" 22 | def compose_manager_cfg(self) -> IsaacLabArenaManagerBasedRLEnvCfg: 23 | # Combine configurations from all components 24 | scene_cfg = combine_configclass_instances(...) 25 | observation_cfg = self.arena_env.embodiment.get_observation_cfg() 26 | actions_cfg = self.arena_env.embodiment.get_action_cfg() 27 | 28 | Each component contributes to the final environment configuration, with automatic integration handled by the environment builder. 29 | 30 | Creating an Environment Example 31 | -------------------------------- 32 | 33 | .. code-block:: python 34 | 35 | # Component creation 36 | embodiment = asset_registry.get_asset_by_name("franka")() 37 | background = asset_registry.get_asset_by_name("kitchen")() 38 | pick_object = asset_registry.get_asset_by_name("cracker_box")() 39 | pick_object.set_initial_pose(Pose(position_xyz=(0.4, 0.0, 0.1))) 40 | 41 | # Environment composition 42 | scene = Scene(assets=[background, pick_object]) 43 | task = PickAndPlaceTask(pick_object, destination, background) 44 | 45 | arena_environment = IsaacLabArenaEnvironment( 46 | name="manipulation_task", 47 | embodiment=embodiment, 48 | scene=scene, 49 | task=task, 50 | teleop_device=None 51 | ) 52 | 53 | # Build and execute 54 | env_builder = ArenaEnvBuilder(arena_environment, args) 55 | env = env_builder.make_registered() 56 | 57 | To see how the manager-based RL environment configuration is compiled, please refer to the :doc:`./concept_environment_compilation` page. 58 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_usd_pose_helpers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | 8 | from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function 9 | 10 | HEADLESS = True 11 | EPS = 1e-6 12 | 13 | 14 | def _test_get_prim_pose_in_default_prim_frame(simulation_app): 15 | # Import the necessary classes. 16 | 17 | from pxr import Usd 18 | 19 | from isaaclab_arena.assets.asset_registry import AssetRegistry 20 | from isaaclab_arena.utils.usd_pose_helpers import get_prim_pose_in_default_prim_frame 21 | 22 | asset_registry = AssetRegistry() 23 | kitchen = asset_registry.get_asset_by_name("kitchen")() 24 | 25 | print(f"Opening USD at: {kitchen.usd_path}") 26 | stage = Usd.Stage.Open(kitchen.usd_path) 27 | prim = stage.GetPrimAtPath("/kitchen/food_packages") 28 | 29 | pose = get_prim_pose_in_default_prim_frame(prim, stage) 30 | print(f"Position relative to default prim: {pose.position_xyz}") 31 | print(f"Orientation (quaternion wxyz) relative to default prim: {pose.rotation_wxyz}") 32 | 33 | # This number is read out of the GUI from the test scene. 34 | pos_np_gt = np.array((2.899114282976978, -0.3971232408755399, 1.0062618326241144)) 35 | 36 | # Here we compare the result with the number read out from the GUI. 37 | pos_np = np.array(pose.position_xyz) 38 | pos_np_diff = pos_np - pos_np_gt 39 | print(f"Position difference: {pos_np_diff}") 40 | 41 | assert np.all(pos_np_diff < EPS), "Position difference is too large" 42 | 43 | # NOTE(alexmillane): I haven't checked the rotation because the GUI gives 44 | # it in euler angles. 45 | 46 | return True 47 | 48 | 49 | def test_get_prim_pose_in_default_prim_frame(): 50 | # Basic test that just adds all our pick-up objects to the scene and checks that nothing crashes. 51 | result = run_simulation_app_function( 52 | _test_get_prim_pose_in_default_prim_frame, 53 | headless=HEADLESS, 54 | ) 55 | assert result, "Test failed" 56 | 57 | 58 | if __name__ == "__main__": 59 | test_get_prim_pose_in_default_prim_frame() 60 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1/54dof_joint_space.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # GR1 Robot Joint Configuration used in the action joint space 7 | # Maps joint names to joint indices for easy reference 8 | joints: 9 | 'left_hip_roll_joint': 0 10 | 'right_hip_roll_joint': 1 11 | 'waist_yaw_joint': 2 12 | 'left_hip_yaw_joint': 3 13 | 'right_hip_yaw_joint': 4 14 | 'waist_pitch_joint': 5 15 | 'left_hip_pitch_joint': 6 16 | 'right_hip_pitch_joint': 7 17 | 'waist_roll_joint': 8 18 | 'left_knee_pitch_joint': 9 19 | 'right_knee_pitch_joint': 10 20 | 'head_roll_joint': 11 21 | 'left_shoulder_pitch_joint': 12 22 | 'right_shoulder_pitch_joint': 13 23 | 'left_ankle_pitch_joint': 14 24 | 'right_ankle_pitch_joint': 15 25 | 'head_pitch_joint': 16 26 | 'left_shoulder_roll_joint': 17 27 | 'right_shoulder_roll_joint': 18 28 | 'left_ankle_roll_joint': 19 29 | 'right_ankle_roll_joint': 20 30 | 'head_yaw_joint': 21 31 | 'left_shoulder_yaw_joint': 22 32 | 'right_shoulder_yaw_joint': 23 33 | 'left_elbow_pitch_joint': 24 34 | 'right_elbow_pitch_joint': 25 35 | 'left_wrist_yaw_joint': 26 36 | 'right_wrist_yaw_joint': 27 37 | 'left_wrist_roll_joint': 28 38 | 'right_wrist_roll_joint': 29 39 | 'left_wrist_pitch_joint': 30 40 | 'right_wrist_pitch_joint': 31 41 | 'L_index_proximal_joint': 32 42 | 'L_middle_proximal_joint': 33 43 | 'L_pinky_proximal_joint': 34 44 | 'L_ring_proximal_joint': 35 45 | 'L_thumb_proximal_yaw_joint': 36 46 | 'R_index_proximal_joint': 37 47 | 'R_middle_proximal_joint': 38 48 | 'R_pinky_proximal_joint': 39 49 | 'R_ring_proximal_joint': 40 50 | 'R_thumb_proximal_yaw_joint': 41 51 | 'L_index_intermediate_joint': 42 52 | 'L_middle_intermediate_joint': 43 53 | 'L_pinky_intermediate_joint': 44 54 | 'L_ring_intermediate_joint': 45 55 | 'L_thumb_proximal_pitch_joint': 46 56 | 'R_index_intermediate_joint': 47 57 | 'R_middle_intermediate_joint': 48 58 | 'R_pinky_intermediate_joint': 49 59 | 'R_ring_intermediate_joint': 50 60 | 'R_thumb_proximal_pitch_joint': 51 61 | 'L_thumb_distal_joint': 52 62 | 'R_thumb_distal_joint': 53 63 | 64 | total_joints: 54 65 | -------------------------------------------------------------------------------- /docker/setup/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is used as entrypoint for the docker container. 4 | # It will setup an user account for the host user inside the docker 5 | # s.t. created files will have correct ownership. 6 | 7 | # Exit on error 8 | set -euo pipefail 9 | 10 | # Make sure that all shared libs are found. This should normally not be needed, but resolves a 11 | # problem with the opencv installation. For unknown reasons, the command doesn't bite if placed 12 | # at the end of the dockerfile 13 | ldconfig 14 | 15 | # Add the group of the user. User/group ID of the host user are set through env variables when calling docker run further down. 16 | groupadd --force --gid "$DOCKER_RUN_GROUP_ID" "$DOCKER_RUN_GROUP_NAME" 17 | 18 | # Re-add the user 19 | userdel "$DOCKER_RUN_USER_NAME" 2>/dev/null || true 20 | userdel ubuntu || true 21 | useradd --no-log-init \ 22 | --uid "$DOCKER_RUN_USER_ID" \ 23 | --gid "$DOCKER_RUN_GROUP_NAME" \ 24 | --groups sudo \ 25 | --shell /bin/bash \ 26 | $DOCKER_RUN_USER_NAME 27 | chown $DOCKER_RUN_USER_NAME:$DOCKER_RUN_GROUP_NAME /home/$DOCKER_RUN_USER_NAME 28 | chown $DOCKER_RUN_USER_NAME:$DOCKER_RUN_GROUP_NAME $WORKDIR 29 | 30 | # Change the root user password (so we can su root) 31 | echo 'root:root' | chpasswd 32 | echo "$DOCKER_RUN_USER_NAME:root" | chpasswd 33 | 34 | # Allow sudo without password 35 | echo "$DOCKER_RUN_USER_NAME ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 36 | 37 | # Suppress sudo hint message 38 | touch /home/$DOCKER_RUN_USER_NAME/.sudo_as_admin_successful 39 | 40 | cp /etc/bash.bashrc /home/$DOCKER_RUN_USER_NAME/.bashrc 41 | chown $DOCKER_RUN_USER_NAME:$DOCKER_RUN_GROUP_NAME /home/$DOCKER_RUN_USER_NAME/.bashrc 42 | 43 | # Add the models, datasets, and eval folders if they don't exist 44 | mkdir -p /datasets /models /eval 45 | chown $DOCKER_RUN_USER_NAME:$DOCKER_RUN_GROUP_NAME /datasets /models /eval 46 | 47 | # Run the passed command or just start the shell as the created user 48 | if [ $# -ge 1 ]; then 49 | echo "alias pytest='/isaac-sim/python.sh -m pytest'" >> /etc/aliasess.bashrc 50 | # -i makes bash to expand aliases 51 | # -c makes bash to run a command 52 | exec sudo --preserve-env -u $DOCKER_RUN_USER_NAME \ 53 | -- env HOME=/home/$DOCKER_RUN_USER_NAME bash -ic "$@" 54 | else 55 | su $DOCKER_RUN_USER_NAME 56 | fi 57 | 58 | exit 59 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/gr1_manip_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Gr00tDatasetConfig Example Configuration 7 | # This file shows how to configure the Gr00tDatasetConfig dataclass using YAML 8 | # Example for GR1 tabletop manipulation task 9 | 10 | # Root directory for all data storage 11 | data_root: "/datasets/isaaclab_arena/static_manipulation_tutorial" 12 | 13 | # Instruction given to the policy in natural language 14 | language_instruction: "Reach out to the microwave and open it." 15 | task_index: 0 16 | 17 | # Name of the HDF5 file to use for the dataset 18 | hdf5_name: "arena_gr1_manipulation_dataset_generated.hdf5" 19 | 20 | # Mimic-generated HDF5 datafield names 21 | state_name_sim: "robot_joint_pos" 22 | action_name_sim: "processed_actions" 23 | pov_cam_name_sim: "robot_pov_cam_rgb" 24 | 25 | # Gr00t-LeRobot datafield names 26 | state_name_lerobot: "observation.state" 27 | action_name_lerobot: "action" 28 | video_name_lerobot: "observation.images.ego_view" 29 | task_description_lerobot: "annotation.human.action.task_description" 30 | 31 | # Parquet configuration 32 | chunks_size: 1000 33 | 34 | # Video configuration 35 | fps: 50 36 | 37 | # File path templates 38 | data_path: "data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet" 39 | video_path: "videos/chunk-{episode_chunk:03d}/{video_key}/episode_{episode_index:06d}.mp4" 40 | 41 | # Configuration file paths 42 | modality_template_path: "isaaclab_arena_gr00t/config/gr1/modality.json" 43 | modality_fname: "modality.json" 44 | episodes_fname: "episodes.jsonl" 45 | tasks_fname: "tasks.jsonl" 46 | info_template_path: "isaaclab_arena_gr00t/config/gr1/info.json" 47 | info_fname: "info.json" 48 | 49 | # policy specific parameters (gr00t demonstration data stored in lerobot format) 50 | policy_joints_config_path: "isaaclab_arena_gr00t/config/gr1/gr00t_26dof_joint_space.yaml" 51 | robot_type: "gr1" 52 | 53 | # Robot simulation specific parameters 54 | action_joints_config_path: "isaaclab_arena_gr00t/config/gr1/36dof_joint_space.yaml" 55 | state_joints_config_path: "isaaclab_arena_gr00t/config/gr1/54dof_joint_space.yaml" 56 | 57 | # Image configuration (height, width, channels) 58 | original_image_size: [512, 512, 3] 59 | target_image_size: [512, 512, 3] 60 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.isort] 2 | 3 | py_version = 310 4 | line_length = 120 5 | group_by_package = true 6 | 7 | # Files to skip 8 | skip_glob = ["docs/*", "logs/*", "_isaac_sim/*", ".vscode/*"] 9 | 10 | # Order of imports 11 | sections = [ 12 | "FUTURE", 13 | "STDLIB", 14 | "THIRDPARTY", 15 | "FIRSTPARTY", 16 | "LOCALFOLDER", 17 | ] 18 | 19 | # Extra standard libraries considered as part of python (permissive licenses 20 | extra_standard_library = [ 21 | "numpy", 22 | "h5py", 23 | "open3d", 24 | "torch", 25 | "tensordict", 26 | "bpy", 27 | "matplotlib", 28 | "gymnasium", 29 | "gym", 30 | "scipy", 31 | "hid", 32 | "yaml", 33 | "prettytable", 34 | "toml", 35 | "trimesh", 36 | "tqdm", 37 | "torchvision", 38 | "transformers", 39 | ] 40 | # Imports from Isaac Sim and Omniverse 41 | known_third_party = [ 42 | "isaacsim.core.api", 43 | "isaacsim.replicator.common", 44 | "omni.replicator.core", 45 | "pxr", 46 | "omni.kit.*", 47 | "warp", 48 | "carb", 49 | "Semantics", 50 | "isaaclab", 51 | "isaaclab_assets", 52 | "isaaclab_rl", 53 | "isaaclab_mimic", 54 | "isaaclab_tasks", 55 | ] 56 | # Imports from this repository 57 | known_first_party = "isaaclab_arena" 58 | 59 | [tool.pyright] 60 | 61 | include = ["source", "scripts"] 62 | exclude = [ 63 | "**/__pycache__", 64 | "**/_isaac_sim", 65 | "**/docs", 66 | "**/logs", 67 | ".git", 68 | ".vscode", 69 | ] 70 | 71 | typeCheckingMode = "basic" 72 | pythonVersion = "3.10" 73 | pythonPlatform = "Linux" 74 | enableTypeIgnoreComments = true 75 | 76 | # This is required as the CI pre-commit does not download the module (i.e. numpy, torch, prettytable) 77 | # Therefore, we have to ignore missing imports 78 | reportMissingImports = "none" 79 | # This is required to ignore for type checks of modules with stubs missing. 80 | reportMissingModuleSource = "none" # -> most common: prettytable in mdp managers 81 | 82 | reportGeneralTypeIssues = "none" # -> raises 218 errors (usage of literal MISSING in dataclasses) 83 | reportOptionalMemberAccess = "warning" # -> raises 8 errors 84 | reportPrivateUsage = "warning" 85 | 86 | 87 | [tool.codespell] 88 | skip = '*.usd,*.svg,*.png,_isaac_sim*,*.bib,*.css,*/_build' 89 | quiet-level = 0 90 | # the world list should always have words in lower case 91 | ignore-words-list = "haa,slq,collapsable,buss" 92 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | repos: 7 | - repo: https://github.com/python/black 8 | rev: 24.3.0 9 | hooks: 10 | - id: black 11 | args: ["--line-length", "120", "--unstable"] 12 | - repo: https://github.com/pycqa/flake8 13 | rev: 7.0.0 14 | hooks: 15 | - id: flake8 16 | additional_dependencies: [flake8-simplify, flake8-return] 17 | - repo: https://github.com/pre-commit/pre-commit-hooks 18 | rev: v4.5.0 19 | hooks: 20 | - id: trailing-whitespace 21 | - id: check-symlinks 22 | - id: destroyed-symlinks 23 | - id: check-added-large-files 24 | args: ["--maxkb=2000"] # restrict files more than 2 MB. Should use git-lfs instead. 25 | - id: check-yaml 26 | exclude: ^osmo/ # The linter gets triggered by the jinja templates in the osmo directory. 27 | - id: check-merge-conflict 28 | - id: check-case-conflict 29 | - id: check-executables-have-shebangs 30 | - id: check-toml 31 | - id: end-of-file-fixer 32 | - id: check-shebang-scripts-are-executable 33 | - id: detect-private-key 34 | - id: debug-statements 35 | - repo: https://github.com/pycqa/isort 36 | rev: 5.13.2 37 | hooks: 38 | - id: isort 39 | name: isort (python) 40 | args: ["--profile", "black", "--filter-files"] 41 | - repo: https://github.com/asottile/pyupgrade 42 | rev: v3.15.1 43 | hooks: 44 | - id: pyupgrade 45 | args: ["--py310-plus"] 46 | - repo: https://github.com/codespell-project/codespell 47 | rev: v2.2.6 48 | hooks: 49 | - id: codespell 50 | additional_dependencies: 51 | - tomli 52 | - repo: https://github.com/pre-commit/pygrep-hooks 53 | rev: v1.10.0 54 | hooks: 55 | - id: rst-backticks 56 | - id: rst-directive-colons 57 | - id: rst-inline-touching-normal 58 | - repo: https://github.com/Lucas-C/pre-commit-hooks 59 | rev: v1.5.1 60 | hooks: 61 | - id: insert-license 62 | files: \.(py|ya?ml)$ 63 | args: 64 | # - --remove-header # Remove existing license headers. Useful when updating license. 65 | - --license-filepath 66 | - .github/LICENSE_HEADER.txt 67 | - --use-current-year 68 | exclude: "submodules/" 69 | -------------------------------------------------------------------------------- /isaaclab_arena/cli/isaaclab_arena_cli.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import argparse 7 | 8 | from isaaclab.app import AppLauncher 9 | 10 | 11 | def get_isaaclab_arena_cli_parser() -> argparse.ArgumentParser: 12 | """Get a complete argument parser with both Isaac Lab and IsaacLab Arena arguments.""" 13 | parser = argparse.ArgumentParser(description="IsaacLab Arena CLI parser.") 14 | AppLauncher.add_app_launcher_args(parser) 15 | add_isaac_lab_cli_args(parser) 16 | add_external_environments_cli_args(parser) 17 | return parser 18 | 19 | 20 | def add_isaac_lab_cli_args(parser: argparse.ArgumentParser) -> None: 21 | """Add Isaac Lab specific command line arguments to the given parser.""" 22 | 23 | isaac_lab_group = parser.add_argument_group("Isaac Lab Arguments", "Arguments specific to Isaac Lab framework") 24 | 25 | isaac_lab_group.add_argument( 26 | "--disable_fabric", action="store_true", default=False, help="Disable fabric and use USD I/O operations." 27 | ) 28 | isaac_lab_group.add_argument( 29 | "--seed", type=int, default=None, help="Optional seed for the random number generator." 30 | ) 31 | isaac_lab_group.add_argument("--num_envs", type=int, default=1, help="Number of environments to simulate.") 32 | isaac_lab_group.add_argument("--env_spacing", type=float, default=30.0, help="Spacing between environments.") 33 | # NOTE(alexmillane, 2025.07.25): Unlike base isaaclab, we enable pinocchio by default. 34 | isaac_lab_group.add_argument( 35 | "--disable_pinocchio", 36 | dest="enable_pinocchio", 37 | default=True, 38 | action="store_false", 39 | help="Disable Pinocchio.", 40 | ) 41 | isaac_lab_group.add_argument("--mimic", action="store_true", default=False, help="Enable mimic environment.") 42 | 43 | 44 | def add_external_environments_cli_args(parser: argparse.ArgumentParser) -> None: 45 | """Add external environments specific command line arguments to the given parser.""" 46 | external_environments_group = parser.add_argument_group( 47 | "External Environments Arguments", "Arguments specific to external environments" 48 | ) 49 | external_environments_group.add_argument( 50 | "--environment", 51 | type=str, 52 | default=None, 53 | help="Name of the external environment to run", 54 | ) 55 | -------------------------------------------------------------------------------- /isaaclab_arena/teleop_devices/avp_handtracking.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | from isaaclab.devices.device_base import DevicesCfg 20 | from isaaclab.devices.openxr import OpenXRDeviceCfg 21 | from isaaclab.devices.openxr.retargeters import GR1T2RetargeterCfg 22 | 23 | from isaaclab_arena.assets.register import register_device 24 | from isaaclab_arena.teleop_devices.teleop_device_base import TeleopDeviceBase 25 | 26 | 27 | @register_device 28 | class HandTrackingTeleopDevice(TeleopDeviceBase): 29 | """ 30 | Teleop device for hand tracking. 31 | """ 32 | 33 | name = "avp_handtracking" 34 | 35 | def __init__( 36 | self, sim_device: str | None = None, num_open_xr_hand_joints: int = 52, enable_visualization: bool = True 37 | ): 38 | super().__init__(sim_device=sim_device) 39 | self.num_open_xr_hand_joints = num_open_xr_hand_joints 40 | self.enable_visualization = enable_visualization 41 | 42 | def get_teleop_device_cfg(self, embodiment: object | None = None): 43 | return DevicesCfg( 44 | devices={ 45 | "avp_handtracking": OpenXRDeviceCfg( 46 | retargeters=[ 47 | GR1T2RetargeterCfg( 48 | enable_visualization=self.enable_visualization, 49 | # number of joints in both hands 50 | num_open_xr_hand_joints=self.num_open_xr_hand_joints, 51 | sim_device=self.sim_device, 52 | hand_joint_names=embodiment.get_action_cfg().upper_body_ik.hand_joint_names, 53 | ), 54 | ], 55 | sim_device=self.sim_device, 56 | xr_cfg=embodiment.get_xr_cfg(), 57 | ), 58 | } 59 | ) 60 | -------------------------------------------------------------------------------- /isaaclab_arena/tasks/task_base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from abc import ABC, abstractmethod 7 | from typing import Any 8 | 9 | from isaaclab.envs.common import ViewerCfg 10 | from isaaclab.managers.recorder_manager import RecorderManagerBaseCfg 11 | 12 | from isaaclab_arena.embodiments.common.mimic_arm_mode import MimicArmMode 13 | from isaaclab_arena.environments.isaaclab_arena_manager_based_env import IsaacLabArenaManagerBasedRLEnvCfg 14 | from isaaclab_arena.metrics.metric_base import MetricBase 15 | 16 | 17 | class TaskBase(ABC): 18 | 19 | def __init__(self, episode_length_s: float | None = None, task_description: str | None = None): 20 | self.episode_length_s = episode_length_s 21 | self.task_description = task_description 22 | 23 | @abstractmethod 24 | def get_scene_cfg(self) -> Any: 25 | raise NotImplementedError("Function not implemented yet.") 26 | 27 | @abstractmethod 28 | def get_termination_cfg(self) -> Any: 29 | raise NotImplementedError("Function not implemented yet.") 30 | 31 | @abstractmethod 32 | def get_events_cfg(self) -> Any: 33 | raise NotImplementedError("Function not implemented yet.") 34 | 35 | @abstractmethod 36 | def get_prompt(self) -> str: 37 | raise NotImplementedError("Function not implemented yet.") 38 | 39 | @abstractmethod 40 | def get_mimic_env_cfg(self, arm_mode: MimicArmMode) -> Any: 41 | raise NotImplementedError("Function not implemented yet.") 42 | 43 | @abstractmethod 44 | def get_metrics(self) -> list[MetricBase]: 45 | raise NotImplementedError("Function not implemented yet.") 46 | 47 | def get_observation_cfg(self) -> Any: 48 | return None 49 | 50 | def get_rewards_cfg(self) -> Any: 51 | return None 52 | 53 | def get_curriculum_cfg(self) -> Any: 54 | return None 55 | 56 | def get_commands_cfg(self) -> Any: 57 | return None 58 | 59 | def get_recorder_term_cfg(self) -> RecorderManagerBaseCfg: 60 | return None 61 | 62 | def modify_env_cfg(self, env_cfg: IsaacLabArenaManagerBasedRLEnvCfg) -> IsaacLabArenaManagerBasedRLEnvCfg: 63 | return env_cfg 64 | 65 | def get_viewer_cfg(self) -> ViewerCfg: 66 | return ViewerCfg() 67 | 68 | def get_episode_length_s(self) -> float | None: 69 | return self.episode_length_s 70 | 71 | def get_task_description(self) -> str | None: 72 | return self.task_description 73 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/config/configs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from dataclasses import MISSING, asdict, dataclass 7 | from typing import Literal 8 | 9 | from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR 10 | 11 | 12 | @dataclass 13 | class ArgsConfig: 14 | """Args Config for running the data collection loop.""" 15 | 16 | def update(self, config_dict: dict, strict: bool = False, skip_keys: list[str] = []): 17 | for k, v in config_dict.items(): 18 | if k in skip_keys: 19 | continue 20 | if strict and not hasattr(self, k): 21 | raise ValueError(f"Config {k} not found in {self.__class__.__name__}") 22 | if not strict and not hasattr(self, k): 23 | continue 24 | setattr(self, k, v) 25 | 26 | @classmethod 27 | def from_dict(cls, config_dict: dict, strict: bool = False, skip_keys: list[str] = []): 28 | instance = cls() 29 | instance.update(config_dict=config_dict, strict=strict, skip_keys=skip_keys) 30 | return instance 31 | 32 | def to_dict(self): 33 | return asdict(self) 34 | 35 | 36 | @dataclass 37 | class BaseConfig(ArgsConfig): 38 | """Base config inherited by all G1 control loops""" 39 | 40 | # WBC Configuration 41 | wbc_version: str = MISSING 42 | """Version of the whole body controller.""" 43 | 44 | wbc_model_path: str = MISSING 45 | """Path to WBC model file""" 46 | 47 | policy_config_path: str = MISSING 48 | """Policy related configuration to specify inputs/outputs dim""" 49 | 50 | # Robot Configuration 51 | enable_waist: bool = False 52 | """Whether to include waist joints in IK.""" 53 | 54 | 55 | @dataclass 56 | class HomieV2Config(BaseConfig): 57 | """Base config inherited by all G1 control loops""" 58 | 59 | # WBC Configuration 60 | wbc_version: Literal["homie_v2"] = "homie_v2" 61 | """Version of the whole body controller.""" 62 | 63 | wbc_model_path: str = ( 64 | f"{ISAACLAB_NUCLEUS_DIR}/Arena/wbc_policy/models/homie_v2/stand.onnx,{ISAACLAB_NUCLEUS_DIR}/Arena/wbc_policy/models/homie_v2/walk.onnx" 65 | ) 66 | """Path to WBC model file""" 67 | 68 | # Robot Configuration 69 | enable_waist: bool = False 70 | """Whether to include waist joints in IK.""" 71 | 72 | policy_config_path: str = "config/g1_homie_v2.yaml" 73 | """Policy related configuration to specify inputs/outputs dim""" 74 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/utils/g1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from typing import Literal 7 | 8 | from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR, retrieve_file_path 9 | 10 | from isaaclab_arena_g1.g1_env.g1_supplemental_info import ( 11 | G1SupplementalInfo, 12 | G1SupplementalInfoWaistLowerAndUpperBody, 13 | G1SupplementalInfoWaistUpperBody, 14 | ) 15 | from isaaclab_arena_g1.g1_env.robot_model import RobotModel 16 | 17 | 18 | def instantiate_g1_robot_model( 19 | waist_location: Literal["lower_body", "upper_body"] = "lower_body", 20 | ): 21 | """ 22 | Instantiate a G1 robot model with configurable waist location, and summarize the supplemental info. 23 | 24 | Args: 25 | waist_location: Whether to put waist in "lower_body" (default G1 behavior), 26 | "upper_body" (waist controlled with arms/manipulation via IK), 27 | or "lower_and_upper_body" (waist reference from arms/manipulation 28 | via IK then passed to lower body policy) 29 | 30 | Returns: 31 | RobotModel: Configured G1 robot model 32 | """ 33 | 34 | robot_model_config = { 35 | "asset_path": f"{ISAACLAB_NUCLEUS_DIR}/Arena/wbc_policy/robot_model/g1/", 36 | "urdf_path": f"{ISAACLAB_NUCLEUS_DIR}/Arena/wbc_policy/robot_model/g1/g1_29dof_with_hand.urdf", 37 | } 38 | 39 | asset_path_local = retrieve_file_path(robot_model_config["asset_path"], force_download=True) 40 | urdf_path_local = retrieve_file_path(robot_model_config["urdf_path"], force_download=True) 41 | 42 | assert waist_location in [ 43 | "lower_body", 44 | "upper_body", 45 | "lower_and_upper_body", 46 | ], f"Invalid waist_location: {waist_location}. Must be 'lower_body' or 'upper_body' or 'lower_and_upper_body'" 47 | # Choose supplemental info based on waist location preference 48 | if waist_location == "lower_body": 49 | robot_model_supplemental_info = G1SupplementalInfo() 50 | elif waist_location == "upper_body": 51 | robot_model_supplemental_info = G1SupplementalInfoWaistUpperBody() 52 | elif waist_location == "lower_and_upper_body": 53 | robot_model_supplemental_info = G1SupplementalInfoWaistLowerAndUpperBody() 54 | 55 | robot_model = RobotModel( 56 | urdf_path_local, 57 | asset_path_local, 58 | supplemental_info=robot_model_supplemental_info, 59 | ) 60 | return robot_model 61 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/policy/test_replay_lerobot_action_policy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import pytest 7 | 8 | from isaaclab_arena.tests.utils.constants import TestConstants 9 | from isaaclab_arena.tests.utils.subprocess import run_subprocess 10 | 11 | HEADLESS = True 12 | ENABLE_CAMERAS = True 13 | NUM_STEPS = 10 14 | # Only 1 traj in test data 15 | TRAJECTORY_INDEX = 0 16 | 17 | 18 | def test_g1_locomanip_replay_lerobot_policy_runner_single_env(): 19 | args = [TestConstants.python_path, f"{TestConstants.examples_dir}/policy_runner.py"] 20 | args.append("--policy_type") 21 | args.append("replay_lerobot") 22 | args.append("--config_yaml_path") 23 | args.append(TestConstants.test_data_dir + "/test_g1_locomanip_lerobot/test_g1_locomanip_replay_action_config.yaml") 24 | args.append("--max_steps") 25 | args.append(str(NUM_STEPS)) 26 | args.append("--trajectory_index") 27 | args.append(str(TRAJECTORY_INDEX)) 28 | if HEADLESS: 29 | args.append("--headless") 30 | if ENABLE_CAMERAS: 31 | args.append("--enable_cameras") 32 | # example env 33 | args.append("galileo_g1_locomanip_pick_and_place") 34 | args.append("--object") 35 | args.append("brown_box") 36 | args.append("--embodiment") 37 | args.append("g1_wbc_joint") 38 | run_subprocess(args) 39 | 40 | 41 | @pytest.mark.skip(reason="Fails on CI for reasons under investigation.") 42 | def test_gr1_manip_replay_lerobot_policy_runner_single_env(): 43 | args = [TestConstants.python_path, f"{TestConstants.examples_dir}/policy_runner.py"] 44 | args.append("--policy_type") 45 | args.append("replay_lerobot") 46 | args.append("--config_yaml_path") 47 | args.append(TestConstants.test_data_dir + "/test_gr1_manip_lerobot/test_gr1_manip_replay_action_config.yaml") 48 | args.append("--max_steps") 49 | args.append(str(NUM_STEPS)) 50 | args.append("--trajectory_index") 51 | args.append(str(TRAJECTORY_INDEX)) 52 | if HEADLESS: 53 | args.append("--headless") 54 | if ENABLE_CAMERAS: 55 | args.append("--enable_cameras") 56 | # example env 57 | args.append("gr1_open_microwave") 58 | args.append("--object") 59 | args.append("microwave") 60 | args.append("--embodiment") 61 | args.append("gr1_joint") 62 | run_subprocess(args) 63 | 64 | 65 | if __name__ == "__main__": 66 | test_g1_locomanip_replay_lerobot_policy_runner_single_env() 67 | test_gr1_manip_replay_lerobot_policy_runner_single_env() 68 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_configclass.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab.utils import configclass 7 | 8 | from isaaclab_arena.utils.configclass import combine_configclasses 9 | 10 | 11 | def test_combine_configclasses_with_multiple_inheritance(): 12 | 13 | # Side A - A class with a base class 14 | @configclass 15 | class FooCfgBase: 16 | a: int = 1 17 | b: int = 2 18 | 19 | @configclass 20 | class FooCfg(FooCfgBase): 21 | c: int = 3 22 | a: int = 4 23 | 24 | # Side B - A class without a base class 25 | @configclass 26 | class BarCfg(FooCfgBase): 27 | d: int = 4 28 | e: int = 5 29 | 30 | # Combine the two classes 31 | CombinedCfg = combine_configclasses("CombinedCfg", FooCfg, BarCfg, bases=(FooCfgBase,)) 32 | assert CombinedCfg().d() == 4 33 | assert CombinedCfg().c() == 3 34 | assert CombinedCfg().b() == 2 35 | assert CombinedCfg().a() == 4 36 | assert CombinedCfg().e() == 5 37 | assert isinstance(CombinedCfg(), FooCfgBase) 38 | 39 | 40 | def test_combine_configclasses_with_inheritance(): 41 | 42 | # Side A - A class with a base class 43 | @configclass 44 | class FooCfgBase: 45 | a: int = 1 46 | b: int = 2 47 | 48 | @configclass 49 | class FooCfg(FooCfgBase): 50 | c: int = 3 51 | a: int = 4 52 | 53 | # Side B - A class without a base class 54 | @configclass 55 | class BarCfg: 56 | d: int = 4 57 | 58 | # Combine the two classes 59 | CombinedCfg = combine_configclasses("CombinedCfg", FooCfg, BarCfg, bases=(FooCfgBase,)) 60 | assert CombinedCfg().d() == 4 61 | assert CombinedCfg().c() == 3 62 | assert CombinedCfg().b() == 2 63 | assert CombinedCfg().a() == 4 64 | assert isinstance(CombinedCfg(), FooCfgBase) 65 | 66 | 67 | def test_combine_configclasses_with_post_init(): 68 | 69 | # Side A - A class with a base class 70 | @configclass 71 | class FooCfg: 72 | a: int = 1 73 | b: int = 2 74 | 75 | def __post_init__(self): 76 | self.a = self.a() + 1 77 | self.b = self.b() + 1 78 | 79 | # Side B - A class without a base class 80 | @configclass 81 | class BarCfg: 82 | c: int = 3 83 | 84 | def __post_init__(self): 85 | self.c = self.c() + 1 86 | 87 | # Combine the two classes 88 | CombinedCfg = combine_configclasses("CombinedCfg", FooCfg, BarCfg) 89 | assert CombinedCfg().a == 2 90 | assert CombinedCfg().b == 3 91 | assert CombinedCfg().c == 4 92 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/pose.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | from dataclasses import dataclass 8 | 9 | from isaaclab.utils.math import matrix_from_quat, quat_from_matrix 10 | 11 | 12 | @dataclass 13 | class Pose: 14 | """Transform taking frame A to frame B. 15 | 16 | T_A_B = (t_B_A, q_B_A) 17 | 18 | p_B = p_A + t_B_A 19 | q_B = q_A * q_B_A 20 | """ 21 | 22 | position_xyz: tuple[float, float, float] = (0.0, 0.0, 0.0) 23 | """Translation vector from frame A to frame B.""" 24 | 25 | rotation_wxyz: tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0) 26 | """Quaternion from frame A to frame B. Order is (w, x, y, z).""" 27 | 28 | def __post_init__(self): 29 | assert isinstance(self.position_xyz, tuple) 30 | assert isinstance(self.rotation_wxyz, tuple) 31 | assert len(self.position_xyz) == 3 32 | assert len(self.rotation_wxyz) == 4 33 | 34 | @staticmethod 35 | def identity() -> "Pose": 36 | return Pose(position_xyz=(0.0, 0.0, 0.0), rotation_wxyz=(1.0, 0.0, 0.0, 0.0)) 37 | 38 | def to_tensor(self, device: torch.device) -> torch.Tensor: 39 | """Convert the pose to a tensor. 40 | 41 | The returned tensor has shape (1, 7), and is of the order (x, y, z, qw, qx, qy, qz). 42 | 43 | Args: 44 | device: The device to convert the tensor to. 45 | 46 | Returns: 47 | The pose as a tensor of shape (1, 7). 48 | """ 49 | position_tensor = torch.tensor(self.position_xyz, device=device) 50 | rotation_tensor = torch.tensor(self.rotation_wxyz, device=device) 51 | return torch.cat([position_tensor, rotation_tensor]) 52 | 53 | def multiply(self, other: "Pose") -> "Pose": 54 | return compose_poses(self, other) 55 | 56 | 57 | def compose_poses(T_C_B: Pose, T_B_A: Pose) -> Pose: 58 | """Compose two poses. T_C_A = T_C_B * T_B_A 59 | 60 | Args: 61 | T_B_A: The pose taking points from A to B. 62 | T_C_B: The pose taking points from B to C. 63 | 64 | Returns: 65 | The pose taking points from A to C. 66 | """ 67 | R_B_A = matrix_from_quat(torch.tensor(T_B_A.rotation_wxyz)) 68 | R_C_B = matrix_from_quat(torch.tensor(T_C_B.rotation_wxyz)) 69 | # Compose the rotations 70 | R_C_A = R_C_B @ R_B_A 71 | q_C_A = quat_from_matrix(R_C_A) 72 | # Compose the translations 73 | t_C_A = R_C_B @ torch.tensor(T_B_A.position_xyz) + torch.tensor(T_C_B.position_xyz) 74 | return Pose(position_xyz=tuple(t_C_A.tolist()), rotation_wxyz=tuple(q_C_A.tolist())) 75 | -------------------------------------------------------------------------------- /isaaclab_arena_g1/g1_whole_body_controller/wbc_policy/policy/wbc_policy_factory.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from isaaclab_arena_g1.g1_env.robot_model import RobotModel 7 | from isaaclab_arena_g1.g1_whole_body_controller.wbc_policy.config.configs import BaseConfig 8 | from isaaclab_arena_g1.g1_whole_body_controller.wbc_policy.policy.base import WBCPolicy 9 | from isaaclab_arena_g1.g1_whole_body_controller.wbc_policy.policy.g1_decoupled_whole_body_policy import ( 10 | G1DecoupledWholeBodyPolicy, 11 | ) 12 | from isaaclab_arena_g1.g1_whole_body_controller.wbc_policy.policy.g1_homie_policy import G1HomiePolicyV2 13 | from isaaclab_arena_g1.g1_whole_body_controller.wbc_policy.policy.identity_policy import IdentityPolicy 14 | 15 | 16 | def get_wbc_policy(robot_type: str, robot_model: RobotModel, wbc_config: BaseConfig, num_envs: int = 1) -> WBCPolicy: 17 | """Get the WBC policy for the given robot type and configuration. 18 | 19 | Args: 20 | robot_type: The type of robot to get the WBC policy for. Only "g1" is supported. 21 | robot_model: The robot model to use for the WBC policy 22 | wbc_config: The configuration for the WBC policy 23 | num_envs: The number of environments to use in IsaacLab 24 | 25 | Returns: 26 | The WBC policy for the given robot type and configuration 27 | """ 28 | assert num_envs > 0, f"num_envs must be greater than 0, got {num_envs}" 29 | if robot_type == "g1": 30 | # Only one mode for upper body -- passing thru, no interpolation 31 | upper_body_policy = IdentityPolicy() 32 | 33 | lower_body_policy_type = wbc_config.wbc_version 34 | assert wbc_config.policy_config_path is not None 35 | if lower_body_policy_type == "homie_v2": 36 | lower_body_policy = G1HomiePolicyV2( 37 | robot_model=robot_model, 38 | config_path=wbc_config.policy_config_path, 39 | model_path=wbc_config.wbc_model_path, 40 | num_envs=num_envs, 41 | ) 42 | else: 43 | raise ValueError( 44 | f"Invalid lower body policy type: {lower_body_policy_type}, Supported lower body policy types: homie_v2" 45 | ) 46 | 47 | wbc_policy = G1DecoupledWholeBodyPolicy( 48 | robot_model=robot_model, 49 | upper_body_policy=upper_body_policy, 50 | lower_body_policy=lower_body_policy, 51 | num_envs=num_envs, 52 | ) 53 | else: 54 | raise ValueError(f"Invalid robot type: {robot_type}. Supported robot types: g1") 55 | return wbc_policy 56 | -------------------------------------------------------------------------------- /docs/pages/concepts/concept_overview.rst: -------------------------------------------------------------------------------- 1 | Concept Overview 2 | ================ 3 | 4 | This section provides an overview of the core concepts in Isaac Lab Arena. 5 | 6 | .. figure:: ../../images/isaaclab_arena_core_framework.png 7 | :width: 100% 8 | :alt: Isaac Lab Arena Workflow 9 | :align: center 10 | 11 | IsaacLab Arena Workflow Overview 12 | 13 | In the core of the workflow, we have three main components, **Scene**, **Embodiment**, and **Task**. We compile most of the managers of the 14 | manager-based RL environment from these three components. We strongly incline towards keeping these components as independent as possible. This 15 | allows us to reuse the components in different environments and tasks, thus making the framework more modular and easier to extend. 16 | 17 | **Embodiment** 18 | 19 | Embodiments define robot-specific configurations and behaviors. They provide a modular way to integrate different robots into environments, 20 | encapsulating kinematics, control actions, observations, terminations and camera systems. See :doc:`./concept_embodiment_design` for more details. 21 | 22 | **Task** 23 | 24 | Tasks define objectives, success criteria, and behavior logic for environments. They provide configurations for termination conditions, event handling, 25 | metrics collection, and mimic components. See :doc:`./concept_tasks_design` for more details. 26 | 27 | **Scene** 28 | 29 | Scenes manage collections of assets that define the physical environment for simulation. They provide a unified interface for composing backgrounds, 30 | objects, and interactive elements. See :doc:`./concept_scene_design` for more details. 31 | 32 | When combining these three components we create the observation, action, event, termination, metrics, mimic components of the manager-based RL environment. 33 | For more details on how to combine these components, see :doc:`./concept_environment_compilation`. 34 | 35 | Other components of interest are the **Affordances** and the **Metrics**. 36 | 37 | **Affordances** 38 | 39 | Affordances define what interactions objects can perform - opening doors, pressing buttons, manipulating objects. 40 | They provide standardized interfaces that integrate with tasks and embodiments. See :doc:`./concept_affordances_design` for more details. 41 | 42 | **Metrics** 43 | 44 | Metrics define the performance evaluation metrics for the environment. 45 | Some metrics are independent of the task and the embodiment, such as the success rate metric, 46 | while others are task-specific, such as open door rate metric. See :doc:`./concept_metrics_design` for more details. 47 | 48 | These components together with teleoperation devices form the manager-based RL environment. 49 | See :doc:`./concept_environment_design` for more details on how these components are easily combined to create our environments. 50 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/policy/test_convert_hdf5_to_lerobot.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import shutil 7 | 8 | import pandas as pd 9 | 10 | from isaaclab_arena.tests.utils.constants import TestConstants 11 | from isaaclab_arena_gr00t.config.dataset_config import Gr00tDatasetConfig 12 | from isaaclab_arena_gr00t.data_utils.convert_hdf5_to_lerobot import convert_hdf5_to_lerobot 13 | from isaaclab_arena_gr00t.data_utils.io_utils import create_config_from_yaml 14 | 15 | 16 | def test_g1_convert_hdf5_to_lerobot(): 17 | # Load expected data for comparison 18 | expected_g1_parquet = pd.read_parquet( 19 | TestConstants.test_data_dir + "/test_g1_locomanip_lerobot/data/chunk-000/episode_000000.parquet" 20 | ) 21 | g1_ds_config = create_config_from_yaml( 22 | TestConstants.test_data_dir + "/test_g1_locomanip_lerobot/test_g1_locomanip_config.yaml", Gr00tDatasetConfig 23 | ) 24 | 25 | # Clean up any existing output directory 26 | if g1_ds_config.lerobot_data_dir.exists(): 27 | 28 | shutil.rmtree(g1_ds_config.lerobot_data_dir) 29 | 30 | # Run conversion 31 | convert_hdf5_to_lerobot(g1_ds_config) 32 | 33 | # assert it has episodes.jsonl file 34 | assert (g1_ds_config.lerobot_data_dir / "meta" / "episodes.jsonl").exists() 35 | 36 | # assert it has tasks.jsonl file 37 | assert (g1_ds_config.lerobot_data_dir / "meta" / "tasks.jsonl").exists() 38 | 39 | # assert it has info.json file 40 | assert (g1_ds_config.lerobot_data_dir / "meta" / "info.json").exists() 41 | 42 | # assert it has modality.json file 43 | assert (g1_ds_config.lerobot_data_dir / "meta" / "modality.json").exists() 44 | 45 | # assert it has data/ folder has parquet files 46 | parquet_files = list((g1_ds_config.lerobot_data_dir / "data").glob("**/*.parquet")) 47 | assert len(parquet_files) == 1 48 | 49 | # assert it has videos/ folder has mp4 files 50 | mp4_files = list((g1_ds_config.lerobot_data_dir / "videos").glob("**/*.mp4")) 51 | assert len(mp4_files) == 1 52 | # check parquet file contains expected columns 53 | actual_df = pd.read_parquet(parquet_files[0]) 54 | expected_columns = set(expected_g1_parquet.columns) 55 | actual_columns = set(actual_df.columns) 56 | assert expected_columns.issubset(actual_columns), f"Missing columns: {expected_columns - actual_columns}" 57 | # check parquet file data is the same as expected 58 | assert actual_df.equals(expected_g1_parquet) 59 | 60 | # remove lerobot_data_dir 61 | shutil.rmtree(g1_ds_config.lerobot_data_dir.parent) 62 | 63 | 64 | if __name__ == "__main__": 65 | test_g1_convert_hdf5_to_lerobot() 66 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_data/test_g1_locomanip_lerobot/test_g1_locomanip_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Gr00tDatasetConfig Example Configuration 7 | # This file shows how to configure the Gr00tDatasetConfig dataclass using YAML 8 | # Example for G1 locomanipulation task 9 | 10 | # Root directory for all data storage 11 | data_root: "isaaclab_arena/tests/test_data/" 12 | 13 | # Instruction given to the policy in natural language 14 | language_instruction: "Pick up the brown box from the shelf, and place it into the blue bin on the table located at the right of the shelf." 15 | task_index: 2 16 | 17 | # Name of the HDF5 file to use for the dataset 18 | hdf5_name: "test_g1_hdf5_to_lerobot.hdf5" 19 | 20 | # Mimic-generated HDF5 datafield names 21 | state_name_sim: "robot_joint_pos" 22 | left_eef_pos_name_sim: "left_eef_pos" 23 | left_eef_quat_name_sim: "left_eef_quat" 24 | right_eef_pos_name_sim: "right_eef_pos" 25 | right_eef_quat_name_sim: "right_eef_quat" 26 | teleop_base_height_command_name_sim: "base_height_cmd" 27 | teleop_navigate_command_name_sim: "navigate_cmd" 28 | teleop_torso_orientation_rpy_command_name_sim: "torso_orientation_rpy_cmd" 29 | action_name_sim: "processed_actions" 30 | pov_cam_name_sim: "robot_head_cam_rgb" 31 | 32 | # Gr00t-LeRobot datafield names 33 | state_name_lerobot: "observation.state" 34 | action_name_lerobot: "action" 35 | action_eef_name_sim: "action.eef" 36 | video_name_lerobot: "observation.images.ego_view" 37 | task_description_lerobot: "annotation.human.task_description" 38 | 39 | # Parquet configuration 40 | chunks_size: 1000 41 | 42 | # Video configuration 43 | fps: 50 44 | 45 | # File path templates 46 | data_path: "data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet" 47 | video_path: "videos/chunk-{episode_chunk:03d}/{video_key}/episode_{episode_index:06d}.mp4" 48 | 49 | # Configuration file paths 50 | modality_template_path: "isaaclab_arena_gr00t/config/g1/modality.json" 51 | modality_fname: "modality.json" 52 | episodes_fname: "episodes.jsonl" 53 | tasks_fname: "tasks.jsonl" 54 | info_template_path: "isaaclab_arena_gr00t/config/g1/info.json" 55 | info_fname: "info.json" 56 | 57 | # GR00T policy specific parameters 58 | policy_joints_config_path: "isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml" 59 | robot_type: "unitree_g1" 60 | 61 | # Robot simulation specific parameters 62 | action_joints_config_path: "isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml" 63 | state_joints_config_path: "isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml" 64 | 65 | # Image configuration (height, width, channels) 66 | original_image_size: [480, 640, 3] 67 | target_image_size: [480, 640, 3] 68 | -------------------------------------------------------------------------------- /isaaclab_arena/utils/joint_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | 8 | from isaaclab.envs.manager_based_env import ManagerBasedEnv 9 | from isaaclab.managers import SceneEntityCfg 10 | 11 | 12 | def normalize_value(value: torch.Tensor, min_value: float, max_value: float) -> torch.Tensor: 13 | """Normalize a value to the range [0, 1] given min and max bounds.""" 14 | return (value - min_value) / (max_value - min_value) 15 | 16 | 17 | def unnormalize_value(value: float, min_value: float, max_value: float) -> float: 18 | """Unnormalize a value from [0, 1] back to the original range.""" 19 | return min_value + (max_value - min_value) * value 20 | 21 | 22 | def get_normalized_joint_position(env: ManagerBasedEnv, asset_cfg: SceneEntityCfg) -> torch.Tensor: 23 | """Get the normalized position of a joint (in range [0, 1]).""" 24 | articulation = env.scene.articulations[asset_cfg.name] 25 | assert len(asset_cfg.joint_names) == 1, "Only one joint name is supported for now." 26 | joint_index = articulation.data.joint_names.index(asset_cfg.joint_names[0]) 27 | joint_position = articulation.data.joint_pos[:, joint_index] 28 | joint_position_limits = articulation.data.joint_pos_limits[0, joint_index, :] 29 | joint_min, joint_max = joint_position_limits[0], joint_position_limits[1] 30 | normalized_position = normalize_value(joint_position, joint_min, joint_max) 31 | if joint_min < 0.0: 32 | normalized_position = 1 - normalized_position 33 | return normalized_position 34 | 35 | 36 | def set_normalized_joint_position( 37 | env: ManagerBasedEnv, asset_cfg: SceneEntityCfg, target_joint_position: float, env_ids: torch.Tensor | None = None 38 | ) -> None: 39 | """Set the position of a joint using a normalized value (in range [0, 1]).""" 40 | articulation = env.scene.articulations[asset_cfg.name] 41 | assert len(asset_cfg.joint_names) == 1, "Only one joint name is supported for now." 42 | joint_index = articulation.data.joint_names.index(asset_cfg.joint_names[0]) 43 | joint_position_limits = articulation.data.joint_pos_limits[0, joint_index, :] 44 | joint_min, joint_max = joint_position_limits[0], joint_position_limits[1] 45 | if joint_min < 0.0: 46 | target_joint_position = 1 - target_joint_position 47 | target_joint_position_unnormlized = unnormalize_value(target_joint_position, joint_min, joint_max) 48 | articulation.write_joint_position_to_sim( 49 | torch.tensor([[target_joint_position_unnormlized]]).to(env.device), 50 | torch.tensor([joint_index]).to(env.device), 51 | env_ids=env_ids.to(env.device) if env_ids is not None else None, 52 | ) 53 | -------------------------------------------------------------------------------- /isaaclab_arena_environments/press_button_environment.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import argparse 7 | 8 | from isaaclab_arena_environments.example_environment_base import ExampleEnvironmentBase 9 | 10 | # NOTE(alexmillane, 2025.09.04): There is an issue with type annotation in this file. 11 | # We cannot annotate types which require the simulation app to be started in order to 12 | # import, because this file is used to retrieve CLI arguments, so it must be imported 13 | # before the simulation app is started. 14 | # TODO(alexmillane, 2025.09.04): Fix this. 15 | 16 | 17 | class PressButtonEnvironment(ExampleEnvironmentBase): 18 | 19 | name: str = "press_button" 20 | 21 | def get_env(self, args_cli: argparse.Namespace): # -> IsaacLabArenaEnvironment: 22 | from isaaclab_arena.environments.isaaclab_arena_environment import IsaacLabArenaEnvironment 23 | from isaaclab_arena.scene.scene import Scene 24 | from isaaclab_arena.tasks.press_button_task import PressButtonTask 25 | from isaaclab_arena.utils.pose import Pose 26 | 27 | embodiment = self.asset_registry.get_asset_by_name(args_cli.embodiment)() 28 | 29 | background = self.asset_registry.get_asset_by_name("packing_table")() 30 | press_object = self.asset_registry.get_asset_by_name("coffee_machine")() 31 | 32 | assets = [background, press_object] 33 | 34 | if args_cli.teleop_device is not None: 35 | teleop_device = self.device_registry.get_device_by_name(args_cli.teleop_device)() 36 | else: 37 | teleop_device = None 38 | 39 | # Put the coffee_machine on the packing table. 40 | press_object_pose = Pose(position_xyz=(0.7, 0.4, 0.19), rotation_wxyz=(0.7071, 0.0, 0.0, -0.7071)) 41 | press_object.set_initial_pose(press_object_pose) 42 | 43 | # Compose the scene 44 | scene = Scene(assets=assets) 45 | 46 | isaaclab_arena_environment = IsaacLabArenaEnvironment( 47 | name=self.name, 48 | embodiment=embodiment, 49 | scene=scene, 50 | task=PressButtonTask(press_object, reset_pressedness=0.8), 51 | teleop_device=teleop_device, 52 | ) 53 | return isaaclab_arena_environment 54 | 55 | @staticmethod 56 | def add_cli_args(parser: argparse.ArgumentParser) -> None: 57 | parser.add_argument("--object", type=str, default=None) 58 | # NOTE(alexmillane, 2025.09.04): We need a teleop device argument in order 59 | # to be used in the record_demos.py script. 60 | parser.add_argument("--teleop_device", type=str, default=None) 61 | parser.add_argument("--embodiment", type=str, default="franka") 62 | -------------------------------------------------------------------------------- /isaaclab_arena/affordances/pressable.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | 8 | from isaaclab.envs.manager_based_env import ManagerBasedEnv 9 | from isaaclab.managers import SceneEntityCfg 10 | 11 | from isaaclab_arena.affordances.affordance_base import AffordanceBase 12 | from isaaclab_arena.utils.joint_utils import get_normalized_joint_position, set_normalized_joint_position 13 | 14 | 15 | class Pressable(AffordanceBase): 16 | """Interface for pressable objects.""" 17 | 18 | def __init__(self, pressable_joint_name: str, pressedness_threshold: float = 0.5, **kwargs): 19 | super().__init__(**kwargs) 20 | self.pressable_joint_name = pressable_joint_name 21 | self.pressedness_threshold = pressedness_threshold 22 | 23 | def is_pressed( 24 | self, env: ManagerBasedEnv, asset_cfg: SceneEntityCfg | None = None, pressedness_threshold: float | None = None 25 | ) -> torch.Tensor: 26 | """Returns a boolean tensor of whether the object is pressed.""" 27 | if asset_cfg is None: 28 | asset_cfg = SceneEntityCfg(self.name) 29 | # We allow for overriding the object-level threshold by passing an argument to this 30 | # function explicitly. Otherwise we use the object-level threshold. 31 | if pressedness_threshold is None: 32 | pressedness_threshold = self.pressedness_threshold 33 | asset_cfg = self._add_joint_name_to_scene_entity_cfg(asset_cfg) 34 | return get_normalized_joint_position(env, asset_cfg) > pressedness_threshold 35 | 36 | def press( 37 | self, 38 | env: ManagerBasedEnv, 39 | env_ids: torch.Tensor | None, 40 | asset_cfg: SceneEntityCfg | None = None, 41 | pressed_percentage: float = 1.0, 42 | ): 43 | """Press the object (in all the environments).""" 44 | if asset_cfg is None: 45 | asset_cfg = SceneEntityCfg(self.name) 46 | asset_cfg = self._add_joint_name_to_scene_entity_cfg(asset_cfg) 47 | set_normalized_joint_position(env, asset_cfg, pressed_percentage, env_ids) 48 | 49 | def unpress( 50 | self, 51 | env: ManagerBasedEnv, 52 | env_ids: torch.Tensor | None, 53 | asset_cfg: SceneEntityCfg | None = None, 54 | unpressed_percentage: float = 1.0, 55 | ): 56 | """Unpress the object (in all the environments).""" 57 | pressed_percentage = 1.0 - unpressed_percentage 58 | self.press(env, env_ids, asset_cfg, pressed_percentage) 59 | 60 | def _add_joint_name_to_scene_entity_cfg(self, asset_cfg: SceneEntityCfg) -> SceneEntityCfg: 61 | asset_cfg.joint_names = [self.pressable_joint_name] 62 | return asset_cfg 63 | -------------------------------------------------------------------------------- /isaaclab_arena_gr00t/config/g1_locomanip_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Gr00tDatasetConfig Example Configuration 7 | # This file shows how to configure the Gr00tDatasetConfig dataclass using YAML 8 | # Example for G1 locomanipulation task 9 | 10 | # Root directory for all data storage 11 | data_root: "/datasets/isaaclab_arena/locomanipulation_tutorial" 12 | 13 | # Instruction given to the policy in natural language 14 | language_instruction: "Pick up the brown box from the shelf, and place it into the blue bin on the table located at the right of the shelf." 15 | task_index: 2 16 | 17 | # Name of the HDF5 file to use for the dataset 18 | hdf5_name: "arena_g1_loco_manipulation_dataset_generated.hdf5" 19 | 20 | # Mimic-generated HDF5 datafield names 21 | state_name_sim: "robot_joint_pos" 22 | left_eef_pos_name_sim: "left_eef_pos" 23 | left_eef_quat_name_sim: "left_eef_quat" 24 | right_eef_pos_name_sim: "right_eef_pos" 25 | right_eef_quat_name_sim: "right_eef_quat" 26 | teleop_base_height_command_name_sim: "base_height_cmd" 27 | teleop_navigate_command_name_sim: "navigate_cmd" 28 | teleop_torso_orientation_rpy_command_name_sim: "torso_orientation_rpy_cmd" 29 | action_name_sim: "processed_actions" 30 | pov_cam_name_sim: "robot_head_cam_rgb" 31 | 32 | # Gr00t-LeRobot datafield names 33 | state_name_lerobot: "observation.state" 34 | action_name_lerobot: "action" 35 | action_eef_name_sim: "action.eef" 36 | video_name_lerobot: "observation.images.ego_view" 37 | task_description_lerobot: "annotation.human.task_description" 38 | 39 | # Parquet configuration 40 | chunks_size: 1000 41 | 42 | # Video configuration 43 | fps: 50 44 | 45 | # File path templates 46 | data_path: "data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet" 47 | video_path: "videos/chunk-{episode_chunk:03d}/{video_key}/episode_{episode_index:06d}.mp4" 48 | 49 | # Configuration file paths 50 | modality_template_path: "isaaclab_arena_gr00t/config/g1/modality.json" 51 | modality_fname: "modality.json" 52 | episodes_fname: "episodes.jsonl" 53 | tasks_fname: "tasks.jsonl" 54 | info_template_path: "isaaclab_arena_gr00t/config/g1/info.json" 55 | info_fname: "info.json" 56 | 57 | # policy specific parameters (gr00t demonstration data stored in lerobot format) 58 | policy_joints_config_path: "isaaclab_arena_gr00t/config/g1/gr00t_43dof_joint_space.yaml" 59 | robot_type: "unitree_g1" 60 | 61 | # Robot simulation specific parameters 62 | action_joints_config_path: "isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml" 63 | state_joints_config_path: "isaaclab_arena_gr00t/config/g1/43dof_joint_space.yaml" 64 | 65 | # Image configuration (height, width, channels) 66 | original_image_size: [480, 640, 3] 67 | target_image_size: [480, 640, 3] 68 | -------------------------------------------------------------------------------- /isaaclab_arena/assets/object_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | from pxr import Usd 7 | 8 | from isaaclab_arena.assets.object_base import ObjectType 9 | from isaaclab_arena.utils.usd_helpers import get_prim_depth, is_articulation_root, is_rigid_body 10 | 11 | 12 | def detect_object_type(usd_path: str | None = None, stage: Usd.Stage | None = None) -> ObjectType: 13 | """Detect the object type of the asset 14 | 15 | Goes through the USD tree and detects the object type. The detection is based 16 | on the presence of a RigidBodyAPI or ArticulationRootAPI at the shallowest depth 17 | in which one of these APIs is present. 18 | 19 | Note that if more than one API is present on that shallowest depth, we raise an error. 20 | 21 | Args: 22 | usd_path: The path to the USD file to inspect. Either this or stage must be provided. 23 | stage: The stage to inspect. Either this or usd_path must be provided. 24 | 25 | Returns: 26 | The object type of the asset. 27 | """ 28 | assert usd_path is not None or stage is not None, "Either usd_path or stage must be provided" 29 | assert usd_path is None or stage is None, "Either usd_path or stage must be provided" 30 | if usd_path is not None: 31 | # Open a stage to inspect the USD. 32 | stage = Usd.Stage.Open(usd_path) 33 | # We do a Breadth First Search (BFS) through the prims, until we find either 34 | # a rigid body or an articulation root. At that point, we continue searching 35 | # the rest of the prims at that depth, to ensure that there's nothing else. 36 | # If we find more than one, we raise an error. 37 | open_prims = [stage.GetPseudoRoot()] 38 | found = False 39 | found_depth = -1 40 | interesting_prim = None 41 | while len(open_prims) > 0: 42 | # Update the DFS list 43 | prim = open_prims.pop(0) 44 | open_prims.extend(prim.GetChildren()) 45 | # Check if we found an interesting prim on this level 46 | if is_articulation_root(prim) or is_rigid_body(prim): 47 | if found: 48 | raise ValueError(f"Found multiple rigid body or articulation roots at depth {get_prim_depth(prim)}") 49 | found_depth = get_prim_depth(prim) 50 | found = True 51 | interesting_prim = prim 52 | if found and get_prim_depth(prim) > found_depth: 53 | break 54 | if not found: 55 | return ObjectType.BASE 56 | if found and is_rigid_body(interesting_prim): 57 | return ObjectType.RIGID 58 | if found and is_articulation_root(interesting_prim): 59 | return ObjectType.ARTICULATION 60 | else: 61 | raise ValueError("This should not happen. There is an unknown USD type in the tree.") 62 | -------------------------------------------------------------------------------- /isaaclab_arena/policy/replay_action_policy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import gymnasium as gym 7 | import torch 8 | from gymnasium.spaces.dict import Dict as GymSpacesDict 9 | 10 | from isaaclab.utils.datasets import HDF5DatasetFileHandler 11 | 12 | from isaaclab_arena.policy.policy_base import PolicyBase 13 | 14 | 15 | class ReplayActionPolicy(PolicyBase): 16 | """ 17 | Replay the actions from an named episode stored in a HDF5 file. 18 | If no episode name is provided, the first episode will be replayed. 19 | """ 20 | 21 | def __init__(self, replay_file_path: str, device: str = "cuda", episode_name: str | None = None): 22 | super().__init__() 23 | self.episode_name = episode_name 24 | self.dataset_file_handler = HDF5DatasetFileHandler() 25 | self.dataset_file_handler.open(replay_file_path) 26 | self.available_episode_names = list(self.dataset_file_handler.get_episode_names()) 27 | 28 | # Take the first episode if no episode name is provided 29 | if self.episode_name is None: 30 | self.episode_name = self.available_episode_names[0] 31 | else: 32 | assert self.episode_name in self.available_episode_names, ( 33 | f"Episode {self.episode_name} not found in {replay_file_path}." 34 | f"Available episodes: {self.available_episode_names}" 35 | ) 36 | 37 | self.episode_data = self.dataset_file_handler.load_episode(self.episode_name, device=device) 38 | self.current_action_index = 0 39 | 40 | def __len__(self) -> int: 41 | """Return the number of actions in the episode.""" 42 | return len(self.episode_data.data["actions"]) 43 | 44 | def get_action(self, env: gym.Env, observation: GymSpacesDict) -> torch.Tensor | None: 45 | """Get the action of the next current index from the dataset.""" 46 | action = self.get_action_from_index(self.current_action_index) 47 | if action.dim() == 1: 48 | action = action.unsqueeze(0) # Add batch dimension 49 | if action is not None: 50 | self.current_action_index += 1 51 | return action 52 | 53 | def get_action_from_index(self, action_index: int) -> torch.Tensor | None: 54 | """Get the action of the specified index from the dataset.""" 55 | if "actions" not in self.episode_data.data: 56 | return None 57 | if action_index >= len(self.episode_data.data["actions"]): 58 | return None 59 | return self.episode_data.data["actions"][action_index] 60 | 61 | def get_available_episode_names(self): 62 | return self.available_episode_names 63 | 64 | def get_initial_state(self) -> torch.Tensor: 65 | return self.episode_data.get_initial_state() 66 | -------------------------------------------------------------------------------- /docs/pages/concepts/concept_teleop_devices_design.rst: -------------------------------------------------------------------------------- 1 | Teleop Devices Design 2 | ====================== 3 | 4 | Teleop devices defined in Arena are a thin wrapper around the Isaac Lab teleop devices. 5 | We define this wrapper to allow for easy registration and discovery of teleop devices. 6 | 7 | Core Architecture 8 | ----------------- 9 | 10 | Teleop devices use the ``TeleopDeviceBase`` abstract class with automatic registration: 11 | 12 | .. code-block:: python 13 | 14 | class TeleopDeviceBase(ABC): 15 | name: str | None = None 16 | 17 | @abstractmethod 18 | def get_teleop_device_cfg(self, embodiment: object | None = None): 19 | """Return Isaac Lab DevicesCfg for the specific device.""" 20 | 21 | @register_device 22 | class KeyboardTeleopDevice(TeleopDeviceBase): 23 | name = "keyboard" 24 | 25 | def get_teleop_device_cfg(self, embodiment=None): 26 | return DevicesCfg(devices={"keyboard": Se3KeyboardCfg(...)}) 27 | 28 | Devices are automatically discovered through decorator-based registration and provide Isaac Lab-compatible configurations. 29 | 30 | Teleop Devices in Detail 31 | ------------------------- 32 | 33 | **Available Devices** 34 | Three primary input modalities for different use cases: 35 | 36 | - **Keyboard**: WASD-style SE3 manipulation with configurable sensitivity parameters 37 | - **SpaceMouse**: 6DOF precise spatial control for manipulation tasks 38 | - **Hand Tracking**: OpenXR-based hand tracking with GR1T2 retargeting for humanoid control 39 | 40 | **Registration and Discovery** 41 | Decorator-based system for automatic device management: 42 | 43 | - **@register_device**: Automatic registration during module import 44 | - **Device Registry**: Central discovery mechanism for available devices 45 | 46 | Environment Integration 47 | ----------------------- 48 | 49 | .. code-block:: python 50 | 51 | # Device selection during environment creation 52 | teleop_device = device_registry.get_device_by_name(args_cli.teleop_device)() 53 | 54 | # Environment composition with teleop support 55 | environment = IsaacLabArenaEnvironment( 56 | name="manipulation_task", 57 | embodiment=embodiment, 58 | scene=scene, 59 | task=task, 60 | teleop_device=teleop_device # Optional human control interface 61 | ) 62 | 63 | # Automatic device configuration and integration 64 | env = env_builder.make_registered() # Handles device setup internally 65 | 66 | Usage Examples 67 | -------------- 68 | 69 | **Keyboard Teleoperation** 70 | 71 | .. code-block:: bash 72 | 73 | # Basic keyboard control 74 | python isaaclab_arena/scripts/teleop.py --teleop_device keyboard kitchen_pick_and_place 75 | 76 | **SpaceMouse Control** 77 | 78 | .. code-block:: bash 79 | 80 | # Precise manipulation with SpaceMouse 81 | python isaaclab_arena/scripts/teleop.py --teleop_device spacemouse kitchen_pick_and_place --sensitivity 2.0 82 | 83 | **Hand Tracking** 84 | 85 | .. code-block:: bash 86 | 87 | # VR hand tracking for humanoid control 88 | python isaaclab_arena/scripts/teleop.py --teleop_device avp_handtracking gr1_open_microwave 89 | -------------------------------------------------------------------------------- /isaaclab_arena/metrics/success_rate.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import numpy as np 7 | import torch 8 | 9 | from isaaclab.managers.recorder_manager import RecorderTerm, RecorderTermCfg 10 | from isaaclab.utils import configclass 11 | 12 | from isaaclab_arena.metrics.metric_base import MetricBase 13 | 14 | 15 | class SuccessRecorder(RecorderTerm): 16 | """Records whether an episode was successful just before the environment is reset.""" 17 | 18 | name = "success" 19 | 20 | def __init__(self, cfg, env): 21 | super().__init__(cfg, env) 22 | # We track the first reset for each environment 23 | self.first_reset = True 24 | 25 | def record_pre_reset(self, env_ids): 26 | # The first time that the environment is reset, we don't want to record the success, 27 | # because nothing has happened yet. 28 | if self.first_reset: 29 | # We expect that on the first reset ALL the environments are reset. 30 | assert len(env_ids) == self._env.num_envs 31 | self.first_reset = False 32 | # Record nothing. 33 | return None, None 34 | assert hasattr(self._env, "termination_manager") 35 | assert "success" in self._env.termination_manager.active_terms 36 | success_results = torch.zeros(len(env_ids), dtype=bool, device=self._env.device) 37 | success_results |= self._env.termination_manager.get_term("success")[env_ids] 38 | return self.name, success_results 39 | 40 | 41 | @configclass 42 | class SuccessRecorderCfg(RecorderTermCfg): 43 | class_type: type[RecorderTerm] = SuccessRecorder 44 | 45 | 46 | class SuccessRateMetric(MetricBase): 47 | """Computes the success rate. 48 | 49 | The success rate is the number of episodes in which the environment was successful, divided 50 | by the total number of episodes. 51 | """ 52 | 53 | name = "success_rate" 54 | recorder_term_name = SuccessRecorder.name 55 | 56 | def get_recorder_term_cfg(self) -> RecorderTermCfg: 57 | """Return the recorder term configuration for the success rate metric.""" 58 | return SuccessRecorderCfg() 59 | 60 | def compute_metric_from_recording(self, recorded_metric_data: list[np.ndarray]) -> float: 61 | """Gets the average success rate from a list of recorded success flags. 62 | 63 | Args: 64 | recorded_metric_data(list[np.ndarray]): The recorded success flags per simulated episode. 65 | 66 | Returns: 67 | The success rate(float). Value between 0 and 1. The proportion of episodes in 68 | which the environment was successful. 69 | """ 70 | num_demos = len(recorded_metric_data) 71 | if num_demos == 0: 72 | return 0.0 73 | all_demos_success_flags = np.concatenate(recorded_metric_data) 74 | assert all_demos_success_flags.ndim == 1 75 | assert all_demos_success_flags.shape[0] == num_demos 76 | success_rate = np.mean(all_demos_success_flags) 77 | return success_rate 78 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_device_registry.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import gymnasium as gym 7 | import torch 8 | import tqdm 9 | 10 | from isaaclab_arena.cli.isaaclab_arena_cli import get_isaaclab_arena_cli_parser 11 | from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function 12 | from isaaclab_arena.utils.isaaclab_utils.simulation_app import teardown_simulation_app 13 | 14 | NUM_STEPS = 2 15 | HEADLESS = True 16 | DEVICE_NAMES = ["avp_handtracking", "spacemouse", "keyboard"] 17 | 18 | 19 | def _test_all_devices_in_registry(simulation_app): 20 | # Import the necessary classes. 21 | 22 | from isaaclab_arena.assets.asset_registry import AssetRegistry, DeviceRegistry 23 | from isaaclab_arena.embodiments.gr1t2.gr1t2 import GR1T2PinkEmbodiment 24 | from isaaclab_arena.environments.arena_env_builder import ArenaEnvBuilder 25 | from isaaclab_arena.environments.isaaclab_arena_environment import IsaacLabArenaEnvironment 26 | from isaaclab_arena.scene.scene import Scene 27 | from isaaclab_arena.tasks.dummy_task import DummyTask 28 | 29 | # Base Environment 30 | asset_registry = AssetRegistry() 31 | device_registry = DeviceRegistry() 32 | background = asset_registry.get_asset_by_name("packing_table")() 33 | asset = asset_registry.get_asset_by_name("cracker_box")() 34 | 35 | for device_name in DEVICE_NAMES: 36 | 37 | teleop_device = device_registry.get_device_by_name(device_name)() 38 | isaaclab_arena_environment = IsaacLabArenaEnvironment( 39 | name="kitchen", 40 | embodiment=GR1T2PinkEmbodiment(), 41 | scene=Scene([background, asset]), 42 | task=DummyTask(), 43 | teleop_device=teleop_device, 44 | ) 45 | 46 | # Remove previous environment if it exists. 47 | if isaaclab_arena_environment.name in gym.registry: 48 | del gym.registry[isaaclab_arena_environment.name] 49 | 50 | # Compile the environment. 51 | args_parser = get_isaaclab_arena_cli_parser() 52 | args_cli = args_parser.parse_args([]) 53 | 54 | builder = ArenaEnvBuilder(isaaclab_arena_environment, args_cli) 55 | 56 | env = builder.make_registered() 57 | 58 | env.reset() 59 | # Run some zero actions. 60 | for _ in tqdm.tqdm(range(NUM_STEPS)): 61 | with torch.inference_mode(): 62 | actions = torch.zeros(env.action_space.shape, device=env.unwrapped.device) 63 | env.step(actions) 64 | 65 | # Close the environment using safe teardown 66 | # Also creates a new stage for the next test 67 | teardown_simulation_app(suppress_exceptions=True, make_new_stage=True) 68 | 69 | return True 70 | 71 | 72 | def test_all_devices_in_registry(): 73 | # Basic test that just adds all our pick-up objects to the scene and checks that nothing crashes. 74 | result = run_simulation_app_function( 75 | _test_all_devices_in_registry, 76 | headless=HEADLESS, 77 | ) 78 | assert result, "Test failed" 79 | -------------------------------------------------------------------------------- /isaaclab_arena/tests/test_camera_observation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). 2 | # All rights reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | import torch 7 | import tqdm 8 | 9 | import pytest 10 | 11 | from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function 12 | 13 | NUM_STEPS = 2 14 | HEADLESS = True 15 | ENABLE_CAMERAS = True 16 | 17 | 18 | def _test_camera_observation(simulation_app) -> bool: 19 | 20 | from isaaclab_arena.assets.asset_registry import AssetRegistry 21 | from isaaclab_arena.cli.isaaclab_arena_cli import get_isaaclab_arena_cli_parser 22 | from isaaclab_arena.embodiments.gr1t2.gr1t2 import GR1T2PinkEmbodiment 23 | from isaaclab_arena.environments.arena_env_builder import ArenaEnvBuilder 24 | from isaaclab_arena.environments.isaaclab_arena_environment import IsaacLabArenaEnvironment 25 | from isaaclab_arena.scene.scene import Scene 26 | from isaaclab_arena.tasks.dummy_task import DummyTask 27 | from isaaclab_arena.utils.pose import Pose 28 | 29 | args_parser = get_isaaclab_arena_cli_parser() 30 | args_cli = args_parser.parse_args(["--enable_cameras"]) 31 | 32 | asset_registry = AssetRegistry() 33 | background = asset_registry.get_asset_by_name("packing_table")() 34 | cracker_box = asset_registry.get_asset_by_name("cracker_box")() 35 | 36 | cracker_box.set_initial_pose( 37 | Pose( 38 | position_xyz=(0.0758066475391388, -0.5088448524475098, 0.0), 39 | rotation_wxyz=(1, 0, 0, 0), 40 | ) 41 | ) 42 | 43 | scene = Scene(assets=[background, cracker_box]) 44 | 45 | isaaclab_arena_environment = IsaacLabArenaEnvironment( 46 | name="camera_observation_test", 47 | embodiment=GR1T2PinkEmbodiment(enable_cameras=True), 48 | scene=scene, 49 | task=DummyTask(), 50 | ) 51 | 52 | # Compile an IsaacLab compatible arena environment configuration 53 | builder = ArenaEnvBuilder(isaaclab_arena_environment, args_cli) 54 | env = builder.make_registered() 55 | env.reset() 56 | 57 | for _ in tqdm.tqdm(range(NUM_STEPS)): 58 | with torch.inference_mode(): 59 | actions = torch.zeros(env.action_space.shape, device=env.device) 60 | obs, _, _, _, _ = env.step(actions) 61 | # Get the camera observation 62 | camera_observation = obs["camera_obs"]["robot_pov_cam_rgb"] 63 | # Assert that the camera rgb observation has three channels 64 | assert camera_observation.shape[3] == 3, "Camera rgb observation does not have three channels" 65 | # Make sure the camera observation contains values other than 0 66 | assert camera_observation.any() != 0, "Camera observation contains only 0s" 67 | 68 | env.close() 69 | 70 | return True 71 | 72 | 73 | @pytest.mark.with_cameras 74 | def test_camera_observation(): 75 | 76 | result = run_simulation_app_function( 77 | _test_camera_observation, 78 | headless=HEADLESS, 79 | enable_cameras=ENABLE_CAMERAS, 80 | ) 81 | assert result, "Test failed" 82 | 83 | 84 | if __name__ == "__main__": 85 | test_camera_observation() 86 | --------------------------------------------------------------------------------