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/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. 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/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. 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/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. 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 `_, 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 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() 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__": 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" 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