├── .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 |
--------------------------------------------------------------------------------