From 3a0db9d761982dc65417e6c6d0714cec61ceadb3 Mon Sep 17 00:00:00 2001
From: rebeccazhang0707 <168459200+rebeccazhang0707@users.noreply.github.com>
Date: Tue, 23 Sep 2025 05:00:52 +0800
Subject: [PATCH 1/9] Updates default viewer pose to see the whole scene for
Agibot environment (#3516)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Description
Fixes bug for toy object intermittently spawning behind the box for the
task Isaac-Place-Toy2Box-Agibot-Right-Arm-RmpFlow-v0
- Reset the default viewer camera pose to see the whole scene.
## Type of change
- Bug fix (non-breaking change which fixes an issue)
## Screenshots
## Checklist
- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
---
.../place/config/agibot/place_toy2box_rmp_rel_env_cfg.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/config/agibot/place_toy2box_rmp_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/config/agibot/place_toy2box_rmp_rel_env_cfg.py
index 0fa7fd9cafa..18d8ccdf1cb 100644
--- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/config/agibot/place_toy2box_rmp_rel_env_cfg.py
+++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/config/agibot/place_toy2box_rmp_rel_env_cfg.py
@@ -198,6 +198,10 @@ def __post_init__(self):
self.sim.physx.gpu_total_aggregate_pairs_capacity = 16 * 1024
self.sim.physx.friction_correlation_distance = 0.00625
+ # set viewer to see the whole scene
+ self.viewer.eye = [1.5, -1.0, 1.5]
+ self.viewer.lookat = [0.5, 0.0, 0.0]
+
"""
Env to Replay Sim2Lab Demonstrations with JointSpaceAction
From cd204adf3b6f663299830386071edcaafe9e0ed4 Mon Sep 17 00:00:00 2001
From: ooctipus
Date: Tue, 23 Sep 2025 18:55:14 -0700
Subject: [PATCH 2/9] Adds torch hook to export libgomp.so.1 from installed
torch (#3512)
# Description
This PR makes the LD_PRELOAD always points to the right python
libgomp.so.1 when conda activate is invoked.
The ARM machines doesn't really work with conda unless LD_PRELOAD is
point to `torch/lib/libgomp.so.1`
This has been tested to work on linux and arm to work on both machines
## Type of change
- Bug fix (non-breaking change which fixes an issue)
## Screenshots
Please attach before and after screenshots of the change if applicable.
## Checklist
- [ ] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
---
isaaclab.sh | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/isaaclab.sh b/isaaclab.sh
index 5d5bc684641..263ff88e8a2 100755
--- a/isaaclab.sh
+++ b/isaaclab.sh
@@ -247,6 +247,45 @@ install_isaaclab_extension() {
fi
}
+# Resolve Torch-bundled libgomp and prepend to LD_PRELOAD, once per shell session
+write_torch_gomp_hooks() {
+ mkdir -p "${CONDA_PREFIX}/etc/conda/activate.d" "${CONDA_PREFIX}/etc/conda/deactivate.d"
+
+ # activation: resolve Torch's libgomp via this env's Python and prepend to LD_PRELOAD
+ cat > "${CONDA_PREFIX}/etc/conda/activate.d/torch_gomp.sh" <<'EOS'
+# Resolve Torch-bundled libgomp and prepend to LD_PRELOAD (quiet + idempotent)
+: "${_IL_PREV_LD_PRELOAD:=${LD_PRELOAD-}}"
+
+__gomp="$("$CONDA_PREFIX/bin/python" - <<'PY' 2>/dev/null || true
+import pathlib
+try:
+ import torch
+ p = pathlib.Path(torch.__file__).parent / 'lib' / 'libgomp.so.1'
+ print(p if p.exists() else "", end="")
+except Exception:
+ pass
+PY
+)"
+
+if [ -n "$__gomp" ] && [ -r "$__gomp" ]; then
+ case ":${LD_PRELOAD:-}:" in
+ *":$__gomp:"*) : ;; # already present
+ *) export LD_PRELOAD="$__gomp${LD_PRELOAD:+:$LD_PRELOAD}";;
+ esac
+fi
+unset __gomp
+EOS
+
+ # deactivation: restore original LD_PRELOAD
+ cat > "${CONDA_PREFIX}/etc/conda/deactivate.d/torch_gomp_unset.sh" <<'EOS'
+# restore LD_PRELOAD to pre-activation value
+if [ -v _IL_PREV_LD_PRELOAD ]; then
+ export LD_PRELOAD="$_IL_PREV_LD_PRELOAD"
+ unset _IL_PREV_LD_PRELOAD
+fi
+EOS
+}
+
# setup anaconda environment for Isaac Lab
setup_conda_env() {
# get environment name from input
@@ -311,6 +350,7 @@ setup_conda_env() {
'export RESOURCE_NAME="IsaacSim"' \
'' > ${CONDA_PREFIX}/etc/conda/activate.d/setenv.sh
+ write_torch_gomp_hooks
# check if we have _isaac_sim directory -> if so that means binaries were installed.
# we need to setup conda variables to load the binaries
local isaacsim_setup_conda_env_script=${ISAACLAB_PATH}/_isaac_sim/setup_conda_env.sh
From bd547aa60873ae8d696197ba9f233da36f65110d Mon Sep 17 00:00:00 2001
From: Cathy Li <40371641+cathyliyuanchen@users.noreply.github.com>
Date: Wed, 24 Sep 2025 18:39:27 -0700
Subject: [PATCH 3/9] Adds instructions on how to position the lighthouse for
manus+vive (#3496)
# Description
Adds instructions on how to position the lighthouse for manus+vive, to
resolve vive tracking quality issues that users may affect hand tracking
experience.
## Type of change
- Documentation update
## Checklist
- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
Co-authored-by: Cathy Li
---
docs/source/how-to/cloudxr_teleoperation.rst | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/docs/source/how-to/cloudxr_teleoperation.rst b/docs/source/how-to/cloudxr_teleoperation.rst
index 3a03b283589..237227f4d64 100644
--- a/docs/source/how-to/cloudxr_teleoperation.rst
+++ b/docs/source/how-to/cloudxr_teleoperation.rst
@@ -409,7 +409,7 @@ Manus + Vive Hand Tracking
Manus gloves and HTC Vive trackers can provide hand tracking when optical hand tracking from a headset is occluded.
This setup expects Manus gloves with a Manus SDK license and Vive trackers attached to the gloves.
-Requires Isaac Sim >=5.1.
+Requires Isaac Sim 5.1 or later.
Run the teleoperation example with Manus + Vive tracking:
@@ -425,6 +425,10 @@ Begin the session with your palms facing up.
This is necessary for calibrating Vive tracker poses using Apple Vision Pro wrist poses from a few initial frames,
as the Vive trackers attached to the back of the hands occlude the optical hand tracking.
+For optimal performance, position the lighthouse above the hands, tilted slightly downward.
+One lighthouse is sufficient if both hands are visible.
+Ensure the lighthouse remains stable; a stand is recommended to prevent wobbling.
+
.. note::
To avoid resource contention and crashes, ensure Manus and Vive devices are connected to different USB controllers/buses.
From 0a417e8465f9c18825c45fcaa5fddbc006b96eb9 Mon Sep 17 00:00:00 2001
From: Kelly Guo
Date: Mon, 29 Sep 2025 02:21:57 +0900
Subject: [PATCH 4/9] [Newton] Updates Newton docs for beta integration (#3518)
# Description
As we prepare for the new beta updates with Newton, there are some new
features/environments supported in the Newton integration. This change
reflects these updates in the docs.
## Type of change
- Documentation update
## Checklist
- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
---------
Signed-off-by: Kelly Guo
Co-authored-by: Antoine RICHARD
---
.../limitations-and-known-bugs.rst | 34 +++++++++++++++----
.../training-environments.rst | 16 +++++++++
2 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/docs/source/experimental-features/newton-physics-integration/limitations-and-known-bugs.rst b/docs/source/experimental-features/newton-physics-integration/limitations-and-known-bugs.rst
index d656f0ea406..b7499042540 100644
--- a/docs/source/experimental-features/newton-physics-integration/limitations-and-known-bugs.rst
+++ b/docs/source/experimental-features/newton-physics-integration/limitations-and-known-bugs.rst
@@ -9,28 +9,48 @@ We do not expect to be able to provide support or debugging assistance until the
Here is a non-exhaustive list of capabilities currently supported in the Newton experimental feature branch grouped by extension:
* isaaclab:
- * Articulation API
+ * Articulation API (supports both articulations and single-body articulations as rigid bodies)
* Contact Sensor
* Direct & Manager single agent workflows
* Omniverse Kit visualizer
* Newton visualizer
* isaaclab_assets:
- * Anymal-D
- * Unitree H1 & G1
+ * Quadrupeds
+ * Anymal-B, Anymal-C, Anymal-D
+ * Unitree A1, Go1, Go2
+ * Spot
+ * Humanoids
+ * Unitree H1 & G1
+ * Cassie
+ * Arms and Hands
+ * Franka
+ * UR10
+ * Allegro Hand
* Toy examples
* Cartpole
* Ant
* Humanoid
* isaaclab_tasks:
* Direct:
- * Cartpole
+ * Cartpole (State, RGB, Depth)
* Ant
* Humanoid
+ * Allegro Hand Repose Cube
* Manager based:
+ * Cartpole (State)
+ * Ant
+ * Humanoid
* Locomotion (velocity flat terrain)
+ * Anymal-B
+ * Anymal-C
* Anymal-D
+ * Cassie
+ * A1
+ * Go1
+ * Go2
+ * Spot
* Unitree G1
* Unitree H1
-
-Capabilities beyond the above are not currently available.
-We expect to support APIs related to rigid bodies soon in order to unlock manipulation based environments.
+ * Manipulation reach
+ * Franka
+ * UR10
diff --git a/docs/source/experimental-features/newton-physics-integration/training-environments.rst b/docs/source/experimental-features/newton-physics-integration/training-environments.rst
index 7ef5619661e..ef98339e5e6 100644
--- a/docs/source/experimental-features/newton-physics-integration/training-environments.rst
+++ b/docs/source/experimental-features/newton-physics-integration/training-environments.rst
@@ -6,12 +6,28 @@ To run training, we follow the standard Isaac Lab workflow. If you are new to Is
The currently supported tasks are as follows:
* Isaac-Cartpole-Direct-v0
+* Isaac-Cartpole-RGB-Camera-Direct-v0 (requires ``--enable_cameras``)
+* Isaac-Cartpole-Depth-Camera-Direct-v0 (requires ``--enable_cameras``)
+* Isaac-Cartpole-v0
* Isaac-Ant-Direct-v0
+* Isaac-Ant-v0
* Isaac-Humanoid-Direct-v0
+* Isaac-Humanoid-v0
+* Isaac-Velocity-Flat-Anymal-B-v0
+* Isaac-Velocity-Flat-Anymal-C-v0
* Isaac-Velocity-Flat-Anymal-D-v0
+* Isaac-Velocity-Flat-Cassie-v0
* Isaac-Velocity-Flat-G1-v0
* Isaac-Velocity-Flat-G1-v1 (Sim-to-Real tested)
* Isaac-Velocity-Flat-H1-v0
+* Isaac-Velocity-Flat-Unitree-A1-v0
+* Isaac-Velocity-Flat-Unitree-Go1-v0
+* Isaac-Velocity-Flat-Unitree-Go2-v0
+* Isaac-Velocity-Flat-Spot-v0
+* Isaac-Reach-Franka-v0
+* Isaac-Reach-UR10-v0
+* Isaac-Repose-Cube-Allegro-Direct-v0
+
To launch an environment and check that it loads as expected, we can start by trying it out with zero actions sent to its actuators.
This can be done as follows, where ``TASK_NAME`` is the name of the task you’d like to run, and ``NUM_ENVS`` is the number of instances of the task that you’d like to create.
From 34729a3ed4c23207a8f439b3487c55b6cedad314 Mon Sep 17 00:00:00 2001
From: Milad-Rakhsha-NV <167464435+Milad-Rakhsha-NV@users.noreply.github.com>
Date: Sun, 28 Sep 2025 10:22:26 -0700
Subject: [PATCH 5/9] [Newton] Updates newton visualizer documentation (#3551)
# Description
Updates documentation for Newton visualizer in preparation for the corl
release of Newton.
Fixes # (issue)
## Type of change
- Documentation update
## Screenshots
Please attach before and after screenshots of the change if applicable.
## Checklist
- [ ] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
Co-authored-by: Milad-Rakhsha
---
.../newton-physics-integration/newton-visualizer.rst | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/docs/source/experimental-features/newton-physics-integration/newton-visualizer.rst b/docs/source/experimental-features/newton-physics-integration/newton-visualizer.rst
index d59001d1810..9efc7639bfb 100644
--- a/docs/source/experimental-features/newton-physics-integration/newton-visualizer.rst
+++ b/docs/source/experimental-features/newton-physics-integration/newton-visualizer.rst
@@ -32,4 +32,8 @@ lower number of environments, we can omit the ``--headless`` option while still
These options are available across all the learning frameworks.
-For more information about the Newton Visualizer, please refer to the `Newton documentation `_ .
+For more information about the Newton Visualizer, please refer to the `Newton documentation `_.
+
+IsaacLab provides additional customizations to the Newton visualizer with several learning-oriented features. These include the ability to pause rendering during training or pause the training process itself. Pausing rendering accelerates training by skipping rendering frames, which is particularly useful when we want to periodically check the trained policy without the performance overhead of continuous rendering. Pausing the training process is valuable for debugging purposes. Additionally, the visualizer's update frequency can be adjusted using a slider in the visualizer window, making it easy to prioritize rendering quality against training performance and vice-versa.
+
+All IsaacLab-specific customizations are organized under the *IsaacLab Training Controls* tab in the visualizer window.
From faa96dfcbcbc50f3e114501eb3f186e71a0270c4 Mon Sep 17 00:00:00 2001
From: ooctipus
Date: Mon, 29 Sep 2025 14:33:54 -0700
Subject: [PATCH 6/9] Provides PBT training cfg example for
Isaac-Dexsuite-Kuka-Allegro-Lift-v0 env for rl_games (#3553)
# Description
This PR provides a PBT builtin training example for
Isaac-Dexsuite-Kuka-Allegro-Lift-v0 environment.
Though we had introduction and explanation for how to run PBT, We didn't
have an builtin example.
This will make using PBT easier for user.
Fixes # (issue)
## Type of change
- New feature (non-breaking change which adds functionality)
## Screenshots
Please attach before and after screenshots of the change if applicable.
## Checklist
- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
---
.../features/population_based_training.rst | 36 ++++++++++++++++---
source/isaaclab_tasks/config/extension.toml | 2 +-
source/isaaclab_tasks/docs/CHANGELOG.rst | 9 +++++
.../kuka_allegro/agents/rl_games_ppo_cfg.yaml | 25 +++++++++++++
4 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/docs/source/features/population_based_training.rst b/docs/source/features/population_based_training.rst
index 49c4d370ff8..d88b8195bc7 100644
--- a/docs/source/features/population_based_training.rst
+++ b/docs/source/features/population_based_training.rst
@@ -80,9 +80,8 @@ You must start **one process per policy** and point them to the **same workspace
Minimal flags you need:
* ``agent.pbt.enabled=True``
-* ``agent.pbt.workspace=``
+* ``agent.pbt.directory=``
* ``agent.pbt.policy_idx=<0..num_policies-1>``
-* ``agent.pbt.num_policies=``
.. note::
All processes must use the same ``agent.pbt.workspace`` so they can see each other's checkpoints.
@@ -93,8 +92,37 @@ Minimal flags you need:
Tips
----
-* Keep checkpoints fast: reduce ``interval_steps`` only if you really need tighter PBT cadence.
-* It is recommended to run 6+ workers to see benefit of pbt
+* Keep checkpoints reasonable: reduce ``interval_steps`` only if you really need tighter PBT cadence.
+* Use larger ``threshold_std`` and ``threshold_abs`` for greater population diversity.
+* It is recommended to run 6+ workers to see benefit of pbt.
+
+
+Training Example
+----------------
+
+We provide a reference PPO config here for task:
+`Isaac-Dexsuite-Kuka-Allegro-Lift-v0 `_.
+For the best logging experience, we recommend using wandb for the logging in the script.
+
+Launch *N* workers, where *n* indicates each worker index:
+
+.. code-block:: bash
+
+ # Run this once per worker (n = 0..N-1), all pointing to the same directory/workspace
+ ./isaaclab.sh -p scripts/reinforcement_learning/rl_games/train.py \
+ --seed= \
+ --task=Isaac-Dexsuite-Kuka-Allegro-Lift-v0 \
+ --num_envs=8192 \
+ --headless \
+ --track \
+ --wandb-name=idx \
+ --wandb-entity=<**entity**> \
+ --wandb-project-name=<**project**>
+ agent.pbt.enabled=True \
+ agent.pbt.num_policies= \
+ agent.pbt.policy_idx= \
+ agent.pbt.workspace=<**pbt_workspace_name**> \
+ agent.pbt.directory=<**/path/to/shared_folder**> \
References
diff --git a/source/isaaclab_tasks/config/extension.toml b/source/isaaclab_tasks/config/extension.toml
index 1a6d1b88d07..c1fd2d9226f 100644
--- a/source/isaaclab_tasks/config/extension.toml
+++ b/source/isaaclab_tasks/config/extension.toml
@@ -1,7 +1,7 @@
[package]
# Note: Semantic Versioning is used: https://semver.org/
-version = "0.11.0"
+version = "0.11.1"
# Description
title = "Isaac Lab Environments"
diff --git a/source/isaaclab_tasks/docs/CHANGELOG.rst b/source/isaaclab_tasks/docs/CHANGELOG.rst
index cda01d77b03..97170ffb6d7 100644
--- a/source/isaaclab_tasks/docs/CHANGELOG.rst
+++ b/source/isaaclab_tasks/docs/CHANGELOG.rst
@@ -1,6 +1,15 @@
Changelog
---------
+0.11.1 (2025-09-24)
+~~~~~~~~~~~~~~~~~~~~
+
+Added
+^^^^^
+
+* Added dextrous lifting pbt configuration example cfg for rl_games.
+
+
0.11.0 (2025-09-07)
~~~~~~~~~~~~~~~~~~~~
diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/config/kuka_allegro/agents/rl_games_ppo_cfg.yaml b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/config/kuka_allegro/agents/rl_games_ppo_cfg.yaml
index 3d23b745cc5..f4ac23fcd7a 100644
--- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/config/kuka_allegro/agents/rl_games_ppo_cfg.yaml
+++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/config/kuka_allegro/agents/rl_games_ppo_cfg.yaml
@@ -84,3 +84,28 @@ params:
clip_actions: False
seq_len: 4
bounds_loss_coef: 0.0001
+
+pbt:
+ enabled: False
+ policy_idx: 0 # policy index in a population
+ num_policies: 8 # total number of policies in the population
+ directory: .
+ workspace: "pbt_workspace" # suffix of the workspace dir name inside train_dir
+ objective: episode.Curriculum/adr
+
+ # PBT hyperparams
+ interval_steps: 50000000
+ threshold_std: 0.1
+ threshold_abs: 0.025
+ mutation_rate: 0.25
+ change_range: [1.1, 2.0]
+ mutation:
+
+ agent.params.config.learning_rate: "mutate_float"
+ agent.params.config.grad_norm: "mutate_float"
+ agent.params.config.entropy_coef: "mutate_float"
+ agent.params.config.critic_coef: "mutate_float"
+ agent.params.config.bounds_loss_coef: "mutate_float"
+ agent.params.config.kl_threshold: "mutate_float"
+ agent.params.config.gamma: "mutate_discount"
+ agent.params.config.tau: "mutate_discount"
From 902bded7c932daa2359ca293e9839d6c1417f4d7 Mon Sep 17 00:00:00 2001
From: Milad-Rakhsha-NV <167464435+Milad-Rakhsha-NV@users.noreply.github.com>
Date: Mon, 29 Sep 2025 14:34:13 -0700
Subject: [PATCH 7/9] [Newton] Adds policy transfer script for sim2sim transfer
from Newton to physX (#3565)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Description
This PR adds a play script to physX-based IsaacLab to make it possible
to play a Newton-based trained policy. Tested environments are
H1/G1/Anymal-D but other exisiting Newton environment should transfer as
well.
Please include a summary of the change and which issue is fixed. Please
also include relevant motivation and context.
List any dependencies that are required for this change.
Fixes # (issue)
## Type of change
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (existing functionality will not work without user
modification)
- Documentation update
## Screenshots
Please attach before and after screenshots of the change if applicable.
## Checklist
- [ ] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [ ] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
---------
Signed-off-by: Milad Rakhsha
---
.../newton-physics-integration/sim-to-sim.rst | 114 +++++--
.../config/newton_to_physx_anymal_d.yaml | 34 +++
.../config/newton_to_physx_g1.yaml | 84 +++++
.../config/newton_to_physx_go2.yaml | 33 ++
.../config/newton_to_physx_h1.yaml | 48 +++
scripts/sim2sim_transfer/rsl_rl_transfer.py | 286 ++++++++++++++++++
6 files changed, 576 insertions(+), 23 deletions(-)
create mode 100644 scripts/sim2sim_transfer/config/newton_to_physx_anymal_d.yaml
create mode 100644 scripts/sim2sim_transfer/config/newton_to_physx_g1.yaml
create mode 100644 scripts/sim2sim_transfer/config/newton_to_physx_go2.yaml
create mode 100644 scripts/sim2sim_transfer/config/newton_to_physx_h1.yaml
create mode 100644 scripts/sim2sim_transfer/rsl_rl_transfer.py
diff --git a/docs/source/experimental-features/newton-physics-integration/sim-to-sim.rst b/docs/source/experimental-features/newton-physics-integration/sim-to-sim.rst
index 24f791aa9cb..3ccc8807cc6 100644
--- a/docs/source/experimental-features/newton-physics-integration/sim-to-sim.rst
+++ b/docs/source/experimental-features/newton-physics-integration/sim-to-sim.rst
@@ -2,38 +2,40 @@
Sim-to-Sim Policy Transfer
==========================
-This section provides examples of sim-to-sim policy transfer using the Newton backend. Sim-to-sim transfer is an essential step before real robot deployment because it verifies that policies work across different simulators. Policies that pass sim-to-sim verification are much more likely to succeed on real robots.
+This section provides examples of sim-to-sim policy transfer between PhysX and Newton backends. Sim-to-sim transfer is an essential step before real robot deployment because it verifies that policies work across different simulators. Policies that pass sim-to-sim verification are much more likely to succeed on real robots.
Overview
--------
-This guide shows how to run a PhysX-trained policy on the Newton backend. While the method works for any robot and physics engine, it has only been tested with Unitree G1, Unitree H1, and ANYmal-D robots using PhysX-trained policies.
+This guide shows how to transfer policies between PhysX and Newton backends in both directions. The main challenge is that different physics engines may parse the same robot model with different joint and link ordering.
-PhysX-trained policies expect joints and links in a specific order determined by how PhysX parses the robot model. However, Newton may parse the same robot with different joint and link ordering.
+Policies trained in one backend expect joints and links in a specific order determined by how that backend parses the robot model. When transferring to another backend, the joint ordering may be different, requiring remapping of observations and actions.
In the future, we plan to solve this using **robot schema** that standardizes joint and link ordering across different backends.
-Currently, we solve this by remapping observations and actions using joint mappings defined in YAML files. These files specify joint names in both PhysX order (source) and Newton order (target). During policy execution, we use this mapping to reorder observations and actions so they work correctly with Newton.
+Currently, we solve this by remapping observations and actions using joint mappings defined in YAML files. These files specify joint names in both source and target backend orders. During policy execution, we use this mapping to reorder observations and actions so they work correctly with the target backend.
+
+The method has been tested with Unitree G1, Unitree Go2, Unitree H1, and ANYmal-D robots for both transfer directions.
What you need
~~~~~~~~~~~~~
-- A policy checkpoint trained with PhysX (RSL-RL).
-- A joint mapping YAML for your robot under ``scripts/newton_sim2sim/mappings/``.
-- The provided player script: ``scripts/newton_sim2sim/rsl_rl_transfer.py``.
+- A policy checkpoint trained with either PhysX or Newton (RSL-RL).
+- A joint mapping YAML for your robot under ``scripts/sim2sim_transfer/config/``.
+- The provided player script: ``scripts/sim2sim_transfer/rsl_rl_transfer.py``.
To add a new robot, create a YAML file with two lists where each joint name appears exactly once in both:
.. code-block:: yaml
# Example structure
- source_joint_names: # PhysX joint order
+ source_joint_names: # Source backend joint order
- joint_1
- joint_2
# ...
- target_joint_names: # Newton joint order
+ target_joint_names: # Target backend joint order
- joint_1
- joint_2
# ...
@@ -41,14 +43,14 @@ To add a new robot, create a YAML file with two lists where each joint name appe
The script automatically computes the necessary mappings for locomotion tasks.
-How to run
-~~~~~~~~~~
+PhysX-to-Newton Transfer
+~~~~~~~~~~~~~~~~~~~~~~~~
-Use this command template to run a PhysX-trained policy with Newton:
+To run a PhysX-trained policy with the Newton backend, use this command template:
.. code-block:: bash
- ./isaaclab.sh -p scripts/newton_sim2sim/rsl_rl_transfer.py \
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
--task= \
--num_envs=32 \
--checkpoint \
@@ -60,11 +62,11 @@ Here are examples for different robots:
.. code-block:: bash
- ./isaaclab.sh -p scripts/newton_sim2sim/rsl_rl_transfer.py \
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
--task=Isaac-Velocity-Flat-G1-v0 \
--num_envs=32 \
--checkpoint \
- --policy_transfer_file scripts/newton_sim2sim/mappings/sim2sim_g1.yaml
+ --policy_transfer_file scripts/sim2sim_transfer/config/physx_to_newton_g1.yaml
2. Unitree H1
@@ -72,28 +74,94 @@ Here are examples for different robots:
.. code-block:: bash
- ./isaaclab.sh -p scripts/newton_sim2sim/rsl_rl_transfer.py \
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
--task=Isaac-Velocity-Flat-H1-v0 \
--num_envs=32 \
--checkpoint \
- --policy_transfer_file scripts/newton_sim2sim/mappings/sim2sim_h1.yaml
+ --policy_transfer_file scripts/sim2sim_transfer/config/physx_to_newton_h1.yaml
+
+
+3. Unitree Go2
+.. code-block:: bash
-3. ANYmal-D
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
+ --task=Isaac-Velocity-Flat-Go2-v0 \
+ --num_envs=32 \
+ --checkpoint \
+ --policy_transfer_file scripts/sim2sim_transfer/config/physx_to_newton_go2.yaml
+
+
+4. ANYmal-D
.. code-block:: bash
- ./isaaclab.sh -p scripts/newton_sim2sim/rsl_rl_transfer.py \
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
--task=Isaac-Velocity-Flat-Anymal-D-v0 \
--num_envs=32 \
--checkpoint \
- --policy_transfer_file scripts/newton_sim2sim/mappings/sim2sim_anymal_d.yaml
+ --policy_transfer_file scripts/sim2sim_transfer/config/physx_to_newton_anymal_d.yaml
+
+Note that to run this, you need to checkout the Newton-based branch of IsaacLab such as ``feature/newton``.
+
+Newton-to-PhysX Transfer
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+To transfer Newton-trained policies to PhysX-based IsaacLab, use the reverse mapping files:
+
+Here are examples for different robots:
+
+1. Unitree G1
+
+.. code-block:: bash
+
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
+ --task=Isaac-Velocity-Flat-G1-v0 \
+ --num_envs=32 \
+ --checkpoint \
+ --policy_transfer_file scripts/sim2sim_transfer/config/newton_to_physx_g1.yaml
+
+
+2. Unitree H1
+
+.. code-block:: bash
+
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
+ --task=Isaac-Velocity-Flat-H1-v0 \
+ --num_envs=32 \
+ --checkpoint \
+ --policy_transfer_file scripts/sim2sim_transfer/config/newton_to_physx_h1.yaml
+
+
+3. Unitree Go2
+
+.. code-block:: bash
+
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
+ --task=Isaac-Velocity-Flat-Go2-v0 \
+ --num_envs=32 \
+ --checkpoint \
+ --policy_transfer_file scripts/sim2sim_transfer/config/newton_to_physx_go2.yaml
+
+
+4. ANYmal-D
+
+.. code-block:: bash
+
+ ./isaaclab.sh -p scripts/sim2sim_transfer/rsl_rl_transfer.py \
+ --task=Isaac-Velocity-Flat-Anymal-D-v0 \
+ --num_envs=32 \
+ --checkpoint \
+ --policy_transfer_file scripts/sim2sim_transfer/config/newton_to_physx_anymal_d.yaml
+The key difference is using the ``newton_to_physx_*.yaml`` mapping files instead of ``physx_to_newton_*.yaml`` files. Also note that you need to checkout a PhysX-based IsaacLab branch such as ``main``.
-Notes and limitations
+Notes and Limitations
~~~~~~~~~~~~~~~~~~~~~
-- This transfer method has only been tested with Unitree G1, Unitree H1, and ANYmal-D using PhysX-trained policies.
-- The observation remapping assumes a locomotion layout with base observations followed by joint observations. For different observation layouts, you'll need to modify ``scripts/newton_sim2sim/policy_mapping.py``.
+- Both transfer directions have been tested with Unitree G1, Unitree Go2, Unitree H1, and ANYmal-D robots.
+- PhysX-to-Newton transfer uses ``physx_to_newton_*.yaml`` mapping files.
+- Newton-to-PhysX transfer requires the corresponding ``newton_to_physx_*.yaml`` mapping files and the PhysX branch of IsaacLab.
+- The observation remapping assumes a locomotion layout with base observations followed by joint observations. For different observation layouts, you'll need to modify the ``get_joint_mappings`` function in ``scripts/sim2sim_transfer/rsl_rl_transfer.py``.
- When adding new robots or backends, make sure both source and target have identical joint names, and that the YAML lists reflect how each backend orders these joints.
diff --git a/scripts/sim2sim_transfer/config/newton_to_physx_anymal_d.yaml b/scripts/sim2sim_transfer/config/newton_to_physx_anymal_d.yaml
new file mode 100644
index 00000000000..bbf4b73dccb
--- /dev/null
+++ b/scripts/sim2sim_transfer/config/newton_to_physx_anymal_d.yaml
@@ -0,0 +1,34 @@
+# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Joint names in the source physics engine where policy is trained (Newton)
+source_joint_names:
+ - "LF_HAA"
+ - "LF_HFE"
+ - "LF_KFE"
+ - "LH_HAA"
+ - "LH_HFE"
+ - "LH_KFE"
+ - "RF_HAA"
+ - "RF_HFE"
+ - "RF_KFE"
+ - "RH_HAA"
+ - "RH_HFE"
+ - "RH_KFE"
+
+# Joint names in the target physics engine where policy is deployed (PhysX)
+target_joint_names:
+ - "LF_HAA"
+ - "LH_HAA"
+ - "RF_HAA"
+ - "RH_HAA"
+ - "LF_HFE"
+ - "LH_HFE"
+ - "RF_HFE"
+ - "RH_HFE"
+ - "LF_KFE"
+ - "LH_KFE"
+ - "RF_KFE"
+ - "RH_KFE"
diff --git a/scripts/sim2sim_transfer/config/newton_to_physx_g1.yaml b/scripts/sim2sim_transfer/config/newton_to_physx_g1.yaml
new file mode 100644
index 00000000000..3a2343405f3
--- /dev/null
+++ b/scripts/sim2sim_transfer/config/newton_to_physx_g1.yaml
@@ -0,0 +1,84 @@
+# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Joint names in the source physics engine where policy is trained (Newton)
+source_joint_names:
+ - "left_hip_pitch_joint"
+ - "left_hip_roll_joint"
+ - "left_hip_yaw_joint"
+ - "left_knee_joint"
+ - "left_ankle_pitch_joint"
+ - "left_ankle_roll_joint"
+ - "right_hip_pitch_joint"
+ - "right_hip_roll_joint"
+ - "right_hip_yaw_joint"
+ - "right_knee_joint"
+ - "right_ankle_pitch_joint"
+ - "right_ankle_roll_joint"
+ - "torso_joint"
+ - "left_shoulder_pitch_joint"
+ - "left_shoulder_roll_joint"
+ - "left_shoulder_yaw_joint"
+ - "left_elbow_pitch_joint"
+ - "left_elbow_roll_joint"
+ - "left_five_joint"
+ - "left_six_joint"
+ - "left_three_joint"
+ - "left_four_joint"
+ - "left_zero_joint"
+ - "left_one_joint"
+ - "left_two_joint"
+ - "right_shoulder_pitch_joint"
+ - "right_shoulder_roll_joint"
+ - "right_shoulder_yaw_joint"
+ - "right_elbow_pitch_joint"
+ - "right_elbow_roll_joint"
+ - "right_five_joint"
+ - "right_six_joint"
+ - "right_three_joint"
+ - "right_four_joint"
+ - "right_zero_joint"
+ - "right_one_joint"
+ - "right_two_joint"
+
+# Joint names in the target physics engine where policy is deployed (PhysX)
+target_joint_names:
+ - "left_hip_pitch_joint"
+ - "right_hip_pitch_joint"
+ - "torso_joint"
+ - "left_hip_roll_joint"
+ - "right_hip_roll_joint"
+ - "left_shoulder_pitch_joint"
+ - "right_shoulder_pitch_joint"
+ - "left_hip_yaw_joint"
+ - "right_hip_yaw_joint"
+ - "left_shoulder_roll_joint"
+ - "right_shoulder_roll_joint"
+ - "left_knee_joint"
+ - "right_knee_joint"
+ - "left_shoulder_yaw_joint"
+ - "right_shoulder_yaw_joint"
+ - "left_ankle_pitch_joint"
+ - "right_ankle_pitch_joint"
+ - "left_elbow_pitch_joint"
+ - "right_elbow_pitch_joint"
+ - "left_ankle_roll_joint"
+ - "right_ankle_roll_joint"
+ - "left_elbow_roll_joint"
+ - "right_elbow_roll_joint"
+ - "left_five_joint"
+ - "left_three_joint"
+ - "left_zero_joint"
+ - "right_five_joint"
+ - "right_three_joint"
+ - "right_zero_joint"
+ - "left_six_joint"
+ - "left_four_joint"
+ - "left_one_joint"
+ - "right_six_joint"
+ - "right_four_joint"
+ - "right_one_joint"
+ - "left_two_joint"
+ - "right_two_joint"
diff --git a/scripts/sim2sim_transfer/config/newton_to_physx_go2.yaml b/scripts/sim2sim_transfer/config/newton_to_physx_go2.yaml
new file mode 100644
index 00000000000..143ca36d799
--- /dev/null
+++ b/scripts/sim2sim_transfer/config/newton_to_physx_go2.yaml
@@ -0,0 +1,33 @@
+# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Joint names in the source physics engine where policy is trained (Newton)
+source_joint_names:
+ - "FL_hip_joint"
+ - "FL_thigh_joint"
+ - "FL_calf_joint"
+ - "FR_hip_joint"
+ - "FR_thigh_joint"
+ - "FR_calf_joint"
+ - "RL_hip_joint"
+ - "RL_thigh_joint"
+ - "RL_calf_joint"
+ - "RR_hip_joint"
+ - "RR_thigh_joint"
+ - "RR_calf_joint"
+# Joint names in the target physics engine where policy is deployed (PhysX)
+target_joint_names:
+ - "FL_hip_joint"
+ - "FR_hip_joint"
+ - "RL_hip_joint"
+ - "RR_hip_joint"
+ - "FL_thigh_joint"
+ - "FR_thigh_joint"
+ - "RL_thigh_joint"
+ - "RR_thigh_joint"
+ - "FL_calf_joint"
+ - "FR_calf_joint"
+ - "RL_calf_joint"
+ - "RR_calf_joint"
diff --git a/scripts/sim2sim_transfer/config/newton_to_physx_h1.yaml b/scripts/sim2sim_transfer/config/newton_to_physx_h1.yaml
new file mode 100644
index 00000000000..b88ee333cff
--- /dev/null
+++ b/scripts/sim2sim_transfer/config/newton_to_physx_h1.yaml
@@ -0,0 +1,48 @@
+# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Joint names in the source physics engine where policy is trained (Newton)
+source_joint_names:
+ - "left_hip_yaw"
+ - "left_hip_roll"
+ - "left_hip_pitch"
+ - "left_knee"
+ - "left_ankle"
+ - "right_hip_yaw"
+ - "right_hip_roll"
+ - "right_hip_pitch"
+ - "right_knee"
+ - "right_ankle"
+ - "torso"
+ - "left_shoulder_pitch"
+ - "left_shoulder_roll"
+ - "left_shoulder_yaw"
+ - "left_elbow"
+ - "right_shoulder_pitch"
+ - "right_shoulder_roll"
+ - "right_shoulder_yaw"
+ - "right_elbow"
+
+# Joint names in the target physics engine where policy is deployed (PhysX)
+target_joint_names:
+ - "left_hip_yaw"
+ - "right_hip_yaw"
+ - "torso"
+ - "left_hip_roll"
+ - "right_hip_roll"
+ - "left_shoulder_pitch"
+ - "right_shoulder_pitch"
+ - "left_hip_pitch"
+ - "right_hip_pitch"
+ - "left_shoulder_roll"
+ - "right_shoulder_roll"
+ - "left_knee"
+ - "right_knee"
+ - "left_shoulder_yaw"
+ - "right_shoulder_yaw"
+ - "left_ankle"
+ - "right_ankle"
+ - "left_elbow"
+ - "right_elbow"
diff --git a/scripts/sim2sim_transfer/rsl_rl_transfer.py b/scripts/sim2sim_transfer/rsl_rl_transfer.py
new file mode 100644
index 00000000000..d35d57c6224
--- /dev/null
+++ b/scripts/sim2sim_transfer/rsl_rl_transfer.py
@@ -0,0 +1,286 @@
+# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+"""Script to play a checkpoint of an RL agent from RSL-RL with policy transfer capabilities."""
+
+"""Launch Isaac Sim Simulator first."""
+
+import argparse
+import os
+import sys
+
+from isaaclab.app import AppLauncher
+
+# local imports
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../.."))
+from scripts.reinforcement_learning.rsl_rl import cli_args # isort: skip
+
+# add argparse arguments
+parser = argparse.ArgumentParser(description="Play an RL agent with RSL-RL with policy transfer.")
+parser.add_argument("--video", action="store_true", default=False, help="Record videos during training.")
+parser.add_argument("--video_length", type=int, default=200, help="Length of the recorded video (in steps).")
+parser.add_argument(
+ "--disable_fabric", action="store_true", default=False, help="Disable fabric and use USD I/O operations."
+)
+parser.add_argument("--num_envs", type=int, default=None, help="Number of environments to simulate.")
+parser.add_argument("--task", type=str, default=None, help="Name of the task.")
+parser.add_argument(
+ "--agent", type=str, default="rsl_rl_cfg_entry_point", help="Name of the RL agent configuration entry point."
+)
+parser.add_argument("--seed", type=int, default=None, help="Seed used for the environment")
+parser.add_argument("--real-time", action="store_true", default=False, help="Run in real-time, if possible.")
+# Joint ordering arguments
+parser.add_argument(
+ "--policy_transfer_file",
+ type=str,
+ default=None,
+ help="Path to YAML file containing joint mapping configuration for policy transfer between physics engines.",
+)
+# append RSL-RL cli arguments
+cli_args.add_rsl_rl_args(parser)
+# append AppLauncher cli args
+AppLauncher.add_app_launcher_args(parser)
+# parse the arguments
+args_cli, hydra_args = parser.parse_known_args()
+# always enable cameras to record video
+if args_cli.video:
+ args_cli.enable_cameras = True
+
+# clear out sys.argv for Hydra
+sys.argv = [sys.argv[0]] + hydra_args
+
+# launch omniverse app
+app_launcher = AppLauncher(args_cli)
+simulation_app = app_launcher.app
+
+"""Rest everything follows."""
+
+import gymnasium as gym
+import os
+import time
+import torch
+import yaml
+
+from rsl_rl.runners import DistillationRunner, OnPolicyRunner
+
+from isaaclab.envs import (
+ DirectMARLEnv,
+ DirectMARLEnvCfg,
+ DirectRLEnvCfg,
+ ManagerBasedRLEnvCfg,
+ multi_agent_to_single_agent,
+)
+from isaaclab.utils.assets import retrieve_file_path
+from isaaclab.utils.dict import print_dict
+
+from isaaclab_rl.rsl_rl import RslRlBaseRunnerCfg, RslRlVecEnvWrapper, export_policy_as_jit, export_policy_as_onnx
+
+import isaaclab_tasks # noqa: F401
+from isaaclab_tasks.utils import get_checkpoint_path
+from isaaclab_tasks.utils.hydra import hydra_task_config
+
+# PLACEHOLDER: Extension template (do not remove this comment)
+
+
+def get_joint_mappings(args_cli, action_space_dim):
+ """Get joint mappings based on command line arguments.
+
+ Args:
+ args_cli: Command line arguments
+ action_space_dim: Dimension of the action space (number of joints)
+
+ Returns:
+ tuple: (source_to_target_list, target_to_source_list, source_to_target_obs_list)
+ """
+ num_joints = action_space_dim
+ if args_cli.policy_transfer_file:
+ # Load from YAML file
+ try:
+ with open(args_cli.policy_transfer_file) as file:
+ config = yaml.safe_load(file)
+ except Exception as e:
+ raise RuntimeError(f"Failed to load joint mapping from {args_cli.policy_transfer_file}: {e}")
+
+ source_joint_names = config["source_joint_names"]
+ target_joint_names = config["target_joint_names"]
+ # Find joint mapping
+ source_to_target = []
+ target_to_source = []
+
+ # Create source to target mapping
+ for joint_name in source_joint_names:
+ if joint_name in target_joint_names:
+ source_to_target.append(target_joint_names.index(joint_name))
+ else:
+ raise ValueError(f"Joint '{joint_name}' not found in target joint names")
+
+ # Create target to source mapping
+ for joint_name in target_joint_names:
+ if joint_name in source_joint_names:
+ target_to_source.append(source_joint_names.index(joint_name))
+ else:
+ raise ValueError(f"Joint '{joint_name}' not found in source joint names")
+ print(f"[INFO] Loaded joint mapping for policy transfer from YAML: {args_cli.policy_transfer_file}")
+ assert (
+ len(source_to_target) == len(target_to_source) == num_joints
+ ), "Number of source and target joints must match"
+ else:
+ # Use identity mapping (one-to-one)
+ identity_map = list(range(num_joints))
+ source_to_target, target_to_source = identity_map, identity_map
+
+ # Create observation mapping (first 12 values stay the same for locomotion examples, then map joint-related values)
+ obs_map = (
+ [0, 1, 2]
+ + [3, 4, 5]
+ + [6, 7, 8]
+ + [9, 10, 11]
+ + [i + 12 + num_joints * 0 for i in source_to_target]
+ + [i + 12 + num_joints * 1 for i in source_to_target]
+ + [i + 12 + num_joints * 2 for i in source_to_target]
+ )
+
+ return source_to_target, target_to_source, obs_map
+
+
+@hydra_task_config(args_cli.task, args_cli.agent)
+def main(env_cfg: ManagerBasedRLEnvCfg | DirectRLEnvCfg | DirectMARLEnvCfg, agent_cfg: RslRlBaseRunnerCfg):
+ """Play with RSL-RL agent with policy transfer capabilities."""
+
+ # override configurations with non-hydra CLI arguments
+ agent_cfg = cli_args.update_rsl_rl_cfg(agent_cfg, args_cli)
+ env_cfg.scene.num_envs = args_cli.num_envs if args_cli.num_envs is not None else env_cfg.scene.num_envs
+
+ # set the environment seed
+ # note: certain randomizations occur in the environment initialization so we set the seed here
+ env_cfg.seed = agent_cfg.seed
+ env_cfg.sim.device = args_cli.device if args_cli.device is not None else env_cfg.sim.device
+
+ # specify directory for logging experiments
+ log_root_path = os.path.join("logs", "rsl_rl", agent_cfg.experiment_name)
+ log_root_path = os.path.abspath(log_root_path)
+ print(f"[INFO] Loading experiment from directory: {log_root_path}")
+ if args_cli.checkpoint:
+ resume_path = retrieve_file_path(args_cli.checkpoint)
+ else:
+ resume_path = get_checkpoint_path(log_root_path, agent_cfg.load_run, agent_cfg.load_checkpoint)
+
+ log_dir = os.path.dirname(resume_path)
+
+ # set the log directory for the environment (works for all environment types)
+ env_cfg.log_dir = log_dir
+
+ # create isaac environment
+ env = gym.make(args_cli.task, cfg=env_cfg, render_mode="rgb_array" if args_cli.video else None)
+
+ # convert to single-agent instance if required by the RL algorithm
+ if isinstance(env.unwrapped, DirectMARLEnv):
+ env = multi_agent_to_single_agent(env)
+
+ # wrap for video recording
+ if args_cli.video:
+ video_kwargs = {
+ "video_folder": os.path.join(log_dir, "videos", "play"),
+ "step_trigger": lambda step: step == 0,
+ "video_length": args_cli.video_length,
+ "disable_logger": True,
+ }
+ print("[INFO] Recording videos during training.")
+ print_dict(video_kwargs, nesting=4)
+ env = gym.wrappers.RecordVideo(env, **video_kwargs)
+
+ # wrap around environment for rsl-rl
+ env = RslRlVecEnvWrapper(env, clip_actions=agent_cfg.clip_actions)
+
+ print(f"[INFO]: Loading model checkpoint from: {resume_path}")
+ # load previously trained model
+ if agent_cfg.class_name == "OnPolicyRunner":
+ runner = OnPolicyRunner(env, agent_cfg.to_dict(), log_dir=None, device=agent_cfg.device)
+ elif agent_cfg.class_name == "DistillationRunner":
+ runner = DistillationRunner(env, agent_cfg.to_dict(), log_dir=None, device=agent_cfg.device)
+ else:
+ raise ValueError(f"Unsupported runner class: {agent_cfg.class_name}")
+ runner.load(resume_path)
+
+ # obtain the trained policy for inference
+ policy = runner.get_inference_policy(device=env.unwrapped.device)
+
+ # extract the neural network module
+ # we do this in a try-except to maintain backwards compatibility.
+ try:
+ # version 2.3 onwards
+ policy_nn = runner.alg.policy
+ except AttributeError:
+ # version 2.2 and below
+ policy_nn = runner.alg.actor_critic
+
+ # extract the normalizer
+ if hasattr(policy_nn, "actor_obs_normalizer"):
+ normalizer = policy_nn.actor_obs_normalizer
+ elif hasattr(policy_nn, "student_obs_normalizer"):
+ normalizer = policy_nn.student_obs_normalizer
+ else:
+ normalizer = None
+
+ # export policy to onnx/jit
+ export_model_dir = os.path.join(os.path.dirname(resume_path), "exported")
+ export_policy_as_jit(policy_nn, normalizer=normalizer, path=export_model_dir, filename="policy.pt")
+ export_policy_as_onnx(policy_nn, normalizer=normalizer, path=export_model_dir, filename="policy.onnx")
+
+ dt = env.unwrapped.step_dt
+
+ # reset environment
+ obs = env.get_observations()
+ timestep = 0
+
+ # Get joint mappings for policy transfer
+ _, target_to_source, obs_map = get_joint_mappings(args_cli, env.action_space.shape[1])
+
+ # Create torch tensors for mappings
+ device = args_cli.device if args_cli.device else "cuda:0"
+ target_to_source_tensor = torch.tensor(target_to_source, device=device) if target_to_source else None
+ obs_map_tensor = torch.tensor(obs_map, device=device) if obs_map else None
+
+ def remap_obs(obs):
+ """Remap the observation to the target observation space."""
+ if obs_map_tensor is not None:
+ obs = obs[:, obs_map_tensor]
+ return obs
+
+ def remap_actions(actions):
+ """Remap the actions to the target action space."""
+ if target_to_source_tensor is not None:
+ actions = actions[:, target_to_source_tensor]
+ return actions
+
+ # simulate environment
+ while simulation_app.is_running():
+ start_time = time.time()
+ # run everything in inference mode
+ with torch.inference_mode():
+ # agent stepping
+ actions = policy(remap_obs(obs))
+ # env stepping
+ obs, _, _, _ = env.step(remap_actions(actions))
+ if args_cli.video:
+ timestep += 1
+ # Exit the play loop after recording one video
+ if timestep == args_cli.video_length:
+ break
+
+ # time delay for real-time evaluation
+ sleep_time = dt - (time.time() - start_time)
+ if args_cli.real_time and sleep_time > 0:
+ time.sleep(sleep_time)
+
+ # close the simulator
+ env.close()
+
+
+if __name__ == "__main__":
+ # run the main function
+ main()
+ # close sim app
+ simulation_app.close()
From 21bcb476b27ceedccccd63afef6bbd822adc2b2b Mon Sep 17 00:00:00 2001
From: Giulio Romualdi
Date: Mon, 29 Sep 2025 23:34:57 +0200
Subject: [PATCH 8/9] Randomizes viscous and dynamic joint friction based on
IsaacSim 5.0 (#3318)
# Description
This PR fixes https://github.com/isaac-sim/IsaacLab/issues/3266, adding
the possibility to randomize the friction coefficient when isaacsim is
higher than 5.0.0
## Type of change
- New feature (non-breaking change which adds functionality)
## Screenshots
Not applicable
## Checklist
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
---------
Signed-off-by: Giulio Romualdi
Signed-off-by: Mayank Mittal <12863862+Mayankm96@users.noreply.github.com>
Co-authored-by: James Tigue <166445701+jtigue-bdai@users.noreply.github.com>
Co-authored-by: Mayank Mittal <12863862+Mayankm96@users.noreply.github.com>
---
source/isaaclab/config/extension.toml | 2 +-
source/isaaclab/docs/CHANGELOG.rst | 9 ++-
.../assets/articulation/articulation.py | 60 +++++++++++++-----
source/isaaclab/isaaclab/envs/mdp/events.py | 50 ++++++++++++++-
.../isaaclab/test/assets/test_articulation.py | 63 +++++++++++++++++--
5 files changed, 163 insertions(+), 21 deletions(-)
diff --git a/source/isaaclab/config/extension.toml b/source/isaaclab/config/extension.toml
index fde6cb9bf91..731d14c2941 100644
--- a/source/isaaclab/config/extension.toml
+++ b/source/isaaclab/config/extension.toml
@@ -1,7 +1,7 @@
[package]
# Note: Semantic Versioning is used: https://semver.org/
-version = "0.46.2"
+version = "0.46.3"
# Description
title = "Isaac Lab framework for Robot Learning"
diff --git a/source/isaaclab/docs/CHANGELOG.rst b/source/isaaclab/docs/CHANGELOG.rst
index c33e307eebe..1e1a61ed67e 100644
--- a/source/isaaclab/docs/CHANGELOG.rst
+++ b/source/isaaclab/docs/CHANGELOG.rst
@@ -1,6 +1,14 @@
Changelog
---------
+0.46.3 (2025-09-17)
+~~~~~~~~~~~~~~~~~~~
+
+Added
+^^^^^
+
+* Modified setter to support for viscous and dynamic joint friction coefficients in articulation based on IsaacSim 5.0.
+* Added randomization of viscous and dynamic joint friction coefficients in event term.
0.46.2 (2025-09-13)
~~~~~~~~~~~~~~~~~~~
@@ -31,7 +39,6 @@ Added
during the traversal. Earlier, instanced prims were skipped since :meth:`Usd.Prim.GetChildren` did not return
instanced prims, which is now fixed.
-
Changed
^^^^^^^
diff --git a/source/isaaclab/isaaclab/assets/articulation/articulation.py b/source/isaaclab/isaaclab/assets/articulation/articulation.py
index 3a720de5573..deb8b6479f5 100644
--- a/source/isaaclab/isaaclab/assets/articulation/articulation.py
+++ b/source/isaaclab/isaaclab/assets/articulation/articulation.py
@@ -827,24 +827,33 @@ def write_joint_armature_to_sim(
def write_joint_friction_coefficient_to_sim(
self,
joint_friction_coeff: torch.Tensor | float,
+ joint_dynamic_friction_coeff: torch.Tensor | float | None = None,
+ joint_viscous_friction_coeff: torch.Tensor | float | None = None,
joint_ids: Sequence[int] | slice | None = None,
env_ids: Sequence[int] | None = None,
):
- r"""Write joint static friction coefficients into the simulation.
+ r"""Write joint friction coefficients into the simulation.
- The joint static friction is a unitless quantity. It relates the magnitude of the spatial force transmitted
- from the parent body to the child body to the maximal static friction force that may be applied by the solver
- to resist the joint motion.
+ For Isaac Sim versions below 5.0, only the static friction coefficient is set.
+ This limits the resisting force or torque up to a maximum proportional to the transmitted
+ spatial force: :math:`\|F_{resist}\| \leq \mu_s \, \|F_{spatial}\|`.
- Mathematically, this means that: :math:`F_{resist} \leq \mu F_{spatial}`, where :math:`F_{resist}`
- is the resisting force applied by the solver and :math:`F_{spatial}` is the spatial force
- transmitted from the parent body to the child body. The simulated static friction effect is therefore
- similar to static and Coulomb static friction.
+ For Isaac Sim versions 5.0 and above, the static, dynamic, and viscous friction coefficients
+ are set. The model combines Coulomb (static & dynamic) friction with a viscous term:
+
+ - Static friction :math:`\mu_s` defines the maximum effort that prevents motion at rest.
+ - Dynamic friction :math:`\mu_d` applies once motion begins and remains constant during motion.
+ - Viscous friction :math:`c_v` is a velocity-proportional resistive term.
Args:
- joint_friction_coeff: Joint static friction coefficient. Shape is (len(env_ids), len(joint_ids)).
- joint_ids: The joint indices to set the joint torque limits for. Defaults to None (all joints).
- env_ids: The environment indices to set the joint torque limits for. Defaults to None (all environments).
+ joint_friction_coeff: Static friction coefficient :math:`\mu_s`.
+ Shape is (len(env_ids), len(joint_ids)). Scalars are broadcast to all selections.
+ joint_dynamic_friction_coeff: Dynamic (Coulomb) friction coefficient :math:`\mu_d`.
+ Same shape as above. If None, the dynamic coefficient is not updated.
+ joint_viscous_friction_coeff: Viscous friction coefficient :math:`c_v`.
+ Same shape as above. If None, the viscous coefficient is not updated.
+ joint_ids: The joint indices to set the friction coefficients for. Defaults to None (all joints).
+ env_ids: The environment indices to set the friction coefficients for. Defaults to None (all environments).
"""
# resolve indices
physx_env_ids = env_ids
@@ -858,15 +867,38 @@ def write_joint_friction_coefficient_to_sim(
env_ids = env_ids[:, None]
# set into internal buffers
self._data.joint_friction_coeff[env_ids, joint_ids] = joint_friction_coeff
+
+ # if dynamic or viscous friction coeffs are provided, set them too
+ if joint_dynamic_friction_coeff is not None:
+ self._data.joint_dynamic_friction_coeff[env_ids, joint_ids] = joint_dynamic_friction_coeff
+ if joint_viscous_friction_coeff is not None:
+ self._data.joint_viscous_friction_coeff[env_ids, joint_ids] = joint_viscous_friction_coeff
+
+ # move the indices to cpu
+ physx_envs_ids_cpu = physx_env_ids.cpu()
+
# set into simulation
if int(get_version()[2]) < 5:
self.root_physx_view.set_dof_friction_coefficients(
- self._data.joint_friction_coeff.cpu(), indices=physx_env_ids.cpu()
+ self._data.joint_friction_coeff.cpu(), indices=physx_envs_ids_cpu
)
else:
friction_props = self.root_physx_view.get_dof_friction_properties()
- friction_props[physx_env_ids.cpu(), :, 0] = self._data.joint_friction_coeff[physx_env_ids, :].cpu()
- self.root_physx_view.set_dof_friction_properties(friction_props, indices=physx_env_ids.cpu())
+ friction_props[physx_envs_ids_cpu, :, 0] = self._data.joint_friction_coeff[physx_envs_ids_cpu, :].cpu()
+
+ # only set dynamic and viscous friction if provided
+ if joint_dynamic_friction_coeff is not None:
+ friction_props[physx_envs_ids_cpu, :, 1] = self._data.joint_dynamic_friction_coeff[
+ physx_envs_ids_cpu, :
+ ].cpu()
+
+ # only set viscous friction if provided
+ if joint_viscous_friction_coeff is not None:
+ friction_props[physx_envs_ids_cpu, :, 2] = self._data.joint_viscous_friction_coeff[
+ physx_envs_ids_cpu, :
+ ].cpu()
+
+ self.root_physx_view.set_dof_friction_properties(friction_props, indices=physx_envs_ids_cpu)
def write_joint_dynamic_friction_coefficient_to_sim(
self,
diff --git a/source/isaaclab/isaaclab/envs/mdp/events.py b/source/isaaclab/isaaclab/envs/mdp/events.py
index 5c0c967e840..923fd1597ab 100644
--- a/source/isaaclab/isaaclab/envs/mdp/events.py
+++ b/source/isaaclab/isaaclab/envs/mdp/events.py
@@ -714,8 +714,56 @@ def __call__(
operation=operation,
distribution=distribution,
)
+
+ # ensure the friction coefficient is non-negative
+ friction_coeff = torch.clamp(friction_coeff, min=0.0)
+
+ # Always set static friction (indexed once)
+ static_friction_coeff = friction_coeff[env_ids[:, None], joint_ids]
+
+ # if isaacsim version is lower than 5.0.0 we can set only the static friction coefficient
+ major_version = int(env.sim.get_version()[0])
+ if major_version >= 5:
+ # Randomize raw tensors
+ dynamic_friction_coeff = _randomize_prop_by_op(
+ self.asset.data.default_joint_dynamic_friction_coeff.clone(),
+ friction_distribution_params,
+ env_ids,
+ joint_ids,
+ operation=operation,
+ distribution=distribution,
+ )
+ viscous_friction_coeff = _randomize_prop_by_op(
+ self.asset.data.default_joint_viscous_friction_coeff.clone(),
+ friction_distribution_params,
+ env_ids,
+ joint_ids,
+ operation=operation,
+ distribution=distribution,
+ )
+
+ # Clamp to non-negative
+ dynamic_friction_coeff = torch.clamp(dynamic_friction_coeff, min=0.0)
+ viscous_friction_coeff = torch.clamp(viscous_friction_coeff, min=0.0)
+
+ # Ensure dynamic ≤ static (same shape before indexing)
+ dynamic_friction_coeff = torch.minimum(dynamic_friction_coeff, friction_coeff)
+
+ # Index once at the end
+ dynamic_friction_coeff = dynamic_friction_coeff[env_ids[:, None], joint_ids]
+ viscous_friction_coeff = viscous_friction_coeff[env_ids[:, None], joint_ids]
+ else:
+ # For versions < 5.0.0, we do not set these values
+ dynamic_friction_coeff = None
+ viscous_friction_coeff = None
+
+ # Single write call for all versions
self.asset.write_joint_friction_coefficient_to_sim(
- friction_coeff[env_ids[:, None], joint_ids], joint_ids=joint_ids, env_ids=env_ids
+ joint_friction_coeff=static_friction_coeff,
+ joint_dynamic_friction_coeff=dynamic_friction_coeff,
+ joint_viscous_friction_coeff=viscous_friction_coeff,
+ joint_ids=joint_ids,
+ env_ids=env_ids,
)
# joint armature
diff --git a/source/isaaclab/test/assets/test_articulation.py b/source/isaaclab/test/assets/test_articulation.py
index 46eb63762fd..dfacff5d2ec 100644
--- a/source/isaaclab/test/assets/test_articulation.py
+++ b/source/isaaclab/test/assets/test_articulation.py
@@ -1997,10 +1997,16 @@ def test_write_joint_frictions_to_sim(sim, num_articulations, device, add_ground
dynamic_friction = torch.rand(num_articulations, articulation.num_joints, device=device)
viscous_friction = torch.rand(num_articulations, articulation.num_joints, device=device)
friction = torch.rand(num_articulations, articulation.num_joints, device=device)
+
+ # Guarantee that the dynamic friction is not greater than the static friction
+ dynamic_friction = torch.min(dynamic_friction, friction)
+
+ # The static friction must be set first to be sure the dynamic friction is not greater than static
+ # when both are set.
+ articulation.write_joint_friction_coefficient_to_sim(friction)
if int(get_version()[2]) >= 5:
articulation.write_joint_dynamic_friction_coefficient_to_sim(dynamic_friction)
articulation.write_joint_viscous_friction_coefficient_to_sim(viscous_friction)
- articulation.write_joint_friction_coefficient_to_sim(friction)
articulation.write_data_to_sim()
for _ in range(100):
@@ -2010,9 +2016,58 @@ def test_write_joint_frictions_to_sim(sim, num_articulations, device, add_ground
articulation.update(sim.cfg.dt)
if int(get_version()[2]) >= 5:
- assert torch.allclose(articulation.data.joint_dynamic_friction_coeff, dynamic_friction)
- assert torch.allclose(articulation.data.joint_viscous_friction_coeff, viscous_friction)
- assert torch.allclose(articulation.data.joint_friction_coeff, friction)
+ friction_props_from_sim = articulation.root_physx_view.get_dof_friction_properties()
+ joint_friction_coeff_sim = friction_props_from_sim[:, :, 0]
+ joint_dynamic_friction_coeff_sim = friction_props_from_sim[:, :, 1]
+ joint_viscous_friction_coeff_sim = friction_props_from_sim[:, :, 2]
+ assert torch.allclose(joint_dynamic_friction_coeff_sim, dynamic_friction.cpu())
+ assert torch.allclose(joint_viscous_friction_coeff_sim, viscous_friction.cpu())
+ else:
+ joint_friction_coeff_sim = articulation.root_physx_view.get_dof_friction_properties()
+
+ assert torch.allclose(joint_friction_coeff_sim, friction.cpu())
+
+ # For Isaac Sim >= 5.0: also test the combined API that can set dynamic and viscous via
+ # write_joint_friction_coefficient_to_sim; reset the sim to isolate this path.
+ if int(get_version()[2]) >= 5:
+ # Reset simulator to ensure a clean state for the alternative API path
+ sim.reset()
+
+ # Warm up a few steps to populate buffers
+ for _ in range(100):
+ sim.step()
+ articulation.update(sim.cfg.dt)
+
+ # New random coefficients
+ dynamic_friction_2 = torch.rand(num_articulations, articulation.num_joints, device=device)
+ viscous_friction_2 = torch.rand(num_articulations, articulation.num_joints, device=device)
+ friction_2 = torch.rand(num_articulations, articulation.num_joints, device=device)
+
+ # Guarantee that the dynamic friction is not greater than the static friction
+ dynamic_friction_2 = torch.min(dynamic_friction_2, friction_2)
+
+ # Use the combined setter to write all three at once
+ articulation.write_joint_friction_coefficient_to_sim(
+ joint_friction_coeff=friction_2,
+ joint_dynamic_friction_coeff=dynamic_friction_2,
+ joint_viscous_friction_coeff=viscous_friction_2,
+ )
+ articulation.write_data_to_sim()
+
+ # Step to let sim ingest new params and refresh data buffers
+ for _ in range(100):
+ sim.step()
+ articulation.update(sim.cfg.dt)
+
+ friction_props_from_sim_2 = articulation.root_physx_view.get_dof_friction_properties()
+ joint_friction_coeff_sim_2 = friction_props_from_sim_2[:, :, 0]
+ friction_dynamic_coef_sim_2 = friction_props_from_sim_2[:, :, 1]
+ friction_viscous_coeff_sim_2 = friction_props_from_sim_2[:, :, 2]
+
+ # Validate values propagated
+ assert torch.allclose(friction_viscous_coeff_sim_2, viscous_friction_2.cpu())
+ assert torch.allclose(friction_dynamic_coef_sim_2, dynamic_friction_2.cpu())
+ assert torch.allclose(joint_friction_coeff_sim_2, friction_2.cpu())
if __name__ == "__main__":
From ad4ce34e1519ede8629d15c759b5b9d24656c3ec Mon Sep 17 00:00:00 2001
From: Michael Gussert
Date: Wed, 1 Oct 2025 16:34:59 -0700
Subject: [PATCH 9/9] Fixes broken link to conda in installation doc (#3601)
Fixes broken link to conda in installation doc
---
.../setup/installation/include/pip_python_virtual_env.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/setup/installation/include/pip_python_virtual_env.rst b/docs/source/setup/installation/include/pip_python_virtual_env.rst
index e7ff0872190..3586ef61cef 100644
--- a/docs/source/setup/installation/include/pip_python_virtual_env.rst
+++ b/docs/source/setup/installation/include/pip_python_virtual_env.rst
@@ -62,7 +62,7 @@ If you wish to install Isaac Sim 4.5, please use modify the instructions accordi
.. tab-item:: Conda Environment
- To install conda, please follow the instructions `here __`.
+ To install conda, please follow the instructions `here `__.
You can create the Isaac Lab environment using the following commands.
We recommend using `Miniconda `_,