What's Changed
This release focuses on stability, infrastructure improvements, workflow refinements, and incremental feature expansions, along with some significant new features, including Multirotor and thruster support for drones, Multi-mesh RayCaster, Visual-based tactile sensor, Haply device integration, and new OpenArm environments.
This release also includes improvements to training workflows, teleoperation and Mimic pipelines, Ray integration, simulation utilities, and developer tooling, along with a large number of robustness and quality-of-life fixes.
multi_mesh_ray_caster.mp4
multirotor_environment.mp4
Full Changelog: v2.3.1...v2.3.2
Note
This will be the final release from the current main branch as we shift our development focus to the develop branch.
Significant restructuring is planned on develop as we work toward Isaac Lab 3.0. We welcome continued community
contributions, but active development will primarily occur on develop going forward.
If you have an open PR, please retarget it to develop to ensure it remains aligned with the latest changes.
✨ New Features
Core & Simulation
- Adds Raycaster with tracking support for dynamic meshes by @renezurbruegg in #3298
- Adds visual-based tactile sensor with shape sensing example by @JuanaDd in #3420
- Adds wrench composers allowing the composition of multiple wrenches on the same bodies by @AntoineRichard in #3287
- Adds multirotor/thruster actuator, multirotor asset and manager-based ARL drone task #3760 by @mihirk284 @grzemal @Zwoelf12
- Adds automatic transform discovery for IMU sensors to find valid parent bodies by @bmccann-bdai in #3864
- Adds friction force reporting to ContactSensor by @gattra-rai in #3563
- Adds MJCF spawner for importing MJCF-based assets by @KyleM73 in #1672
Learning & Environments
Mimic & Teleoperation
- Adds Haply device API with force feedback and teleoperation demo by @mingxueg-nv in #3873
- Refactors retargeters and adds Quest retargeters for G1 tasks by @rwiltz in #3950
- Adds Arena G1 locomanipulation retargeters by @rwiltz in #4140
- Adds APIs to Isaac Lab Mimic for loco-manipulation data generation by @peterd-NV in #3992
🔧 Improvements
Core & Simulation
- Adds preserve-order flag to JointPositionToLimitsAction by @renezurbruegg in #3716
- Adds parsing of instanced meshes to prim fetching utilities by @Mayankm96 in #3367
- Adds configurable logdir parameter to environments by @kellyguo11 in #3391
- Exposes PhysX flag solveArticulationContactLast via PhysxCfg by @ooctipus in #3502
- Removes pickle dependency for config load and dump by @kellyguo11 in #3709
- Improves recorder manager to support custom demo indices by @rebeccazhang0707 in #3552
- Normalizes Python logging by replacing remaining omni.log usage by @pascal-roth in #3912
- Replaces Isaac Sim stage_utils, prim_utils, and nucleus_utils with Isaac Lab implementations by @pascal-roth in #3921, #3923, #3924
- Breaks actuator configuration into multiple files to avoid circular imports by @bmccann-bdai in #3994
- Moves logging configuration into shared utilities by @Mayankm96 in #4298
- Caches Isaac Sim package version for faster lookup by @Mayankm96 in #4299
- Simplifies imports of stage and prim utilities by @Mayankm96 in #4286
- Randomizes viscous and dynamic joint friction consistent with Isaac Sim 5.0 by @GiulioRomualdi in #3318
- Prevents randomization of rigid body mass to zero or negative values by @jtigue-bdai in #4060
- Improves image plotting normalization and colorization by @Mayankm96 in #4302
- Adds Fabric backend support to
isaaclab.sim.views.XformPrimViewby @ooctipus in #4374
Learning & Environments
- Enhances PBT usability with small workflow improvements by @ooctipus in #3449
- Supports vectorized environments for pick-and-place demo by @kellyguo11 in #3996
- Registers direct environments to Gymnasium using string-style imports by @ooctipus in #3803
- Updates Gymnasium dependency to version 1.2.1 by @Mayankm96 in #3696
- Updates SB3 PPO configuration to reduce excessive training time by @ooctipus in #3726
- Adds support for validating replay success using task termination conditions by @yami007007 in #4170
- Adds early stopping support for Ray-based training by @ozhanozen in #3276
- Adds support for custom ProgressReporter implementations in Ray integration by @ozhanozen in #3269
- Updates rsl_rl to version 3.1.2 to support state-dependent standard deviation by @ashwinvkNV in #3867
Infrastructure
- Switches linting and import sorting to Ruff by @Mayankm96 in #4329, #4377
- Moves flake8 and pytest configuration into pyproject.toml by @Mayankm96 in #4335, #4376
- Removes dependency on XformPrim for create_prim by @Mayankm96 in #4307
- Updates copyright year to 2026 by @ashwinvkNV in #4311
- Restricts .gitignore dataset rule to top-level directory only by @louislelay in #3400
- Adds uv as an alternative to conda in isaaclab.sh by @KyleM73 in #3172
- Fixes transformers dependency for theia issue and failing tests by @kellyguo11 in #4484
🐛 Bug Fixes
Core & Simulation
- Fixes missing actuator indices variable in joint randomization by @ooctipus in #3447
- Fixes ViewportCameraController numpy array missing datatype by @T-K-233 in #3375
- Fixes PDActuator docstring mismatch with implementation by @lorenwel in #3493
- Fixes rail difficulty-based height computation in mesh terrains by @KyleM73 in #3254
- Fixes contact threshold handling when activating contact sensors by @kellyguo11 in #3498
- Fixes indexing errors in joint parameter randomization by @GiulioRomualdi in #4051
- Fixes noisy velocities near joint limits by @AntoineRichard in #3989
- Fixes mesh converter not setting collision approximation attributes by @Soappyooo in #4082
- Fixes returned normal tensor shape in TiledCamera by @Rabbit-Hu in #4241
- Fixes advanced indexing shape mismatch in JointPositionToLimitsAction by @ooctipus in #3865
- Fixes teleoperation crash when using DirectRL environments by @emmanuel-ferdman in #4364
- Fixes lidar pattern horizontal resolution bug by @pascal-roth in #4452
Learning & Environments
Infrastructure & Tooling
- Fixes CI behavior to correctly fail fork PRs when general tests fail by @nv-apoddubny in #3412
- Fixes docker availability check in isaaclab.sh on systems without Docker by @klakhi in #4180
- Forces CRLF line endings for .bat files to avoid Windows execution errors by @jiang131072 in #3624
- Fixes environment test failures and disables unstable tests by @kellyguo11 in #3413
- Fixes vulnerability in eval usage for Ray resource parsing by @kellyguo11 in #4425
- Fixes curobo dockerfile for CI runs by @kellyguo11 in #4462
📜 Documentation
- Improves contribution guidelines for Isaac Lab by @Mayankm96 in #3403
- Abstracts common installation steps in documentation by @Mayankm96 in #3445
- Updates SkillGen documentation with data generation commands and success rates by @njawale42 in #3702
- Adds Newton Beta documentation updates and visualizer guidance by @kellyguo11 and @Milad-Rakhsha-NV in #3518, #3551
- Adds automated checks for broken documentation links and fixes existing ones by @kellyguo11 in #3888
- Updates technical report link for Isaac Lab by @Mayankm96 in #4074
- Adds clarification on missing pip in uv virtual environments by @DBinK in #4055
- Adds keyword filtering documentation for list_envs.py by @louislelay in #3384
- Adds documentation for Multirotor feature by @Mayankm96 in #4400
- Adds documentation for PVD and OVD comparison by @kellyguo11 in #4409
✈️ Migration Guide
External Force and Torque Application - Wrench Composers
The set_external_force_and_torque() method on articulations, rigid bodies, and rigid body collections has been deprecated in favor of a new composable wrench system.
Related PR: #3287
New Features:
- Permanent Wrench Composer: Applies forces/torques that persist across simulation steps until explicitly changed
- Instantaneous Wrench Composer: Applies forces/torques for a single simulation step, then automatically resets
- Composability: Multiple forces and torques can now be added together on the same body
- Mixed Frame Support: Seamlessly compose local and global frame wrenches
Migration Guide:
Old API (Deprecated):
# Old method - overwrites previous forces
asset.set_external_force_and_torque(
forces=torch.ones(1, 1, 3),
torques=torch.ones(1, 1, 3),
body_ids=[0],
env_ids=[0],
is_global=False,
)New API:
# Set initial permanent forces (replaces previous)
asset.permanent_wrench_composer.set_forces_and_torques(
forces=torch.ones(1, 1, 3),
env_ids=[0],
body_ids=[0],
)
# Compose additional forces on the same body
asset.permanent_wrench_composer.add_forces_and_torques(
forces=torch.ones(1, 1, 3),
env_ids=[0],
body_ids=[0],
is_global=True, # Mix local and global frames
)
# Add torques independently
asset.permanent_wrench_composer.add_forces_and_torques(
torques=torch.ones(1, 1, 3),
env_ids=[0],
body_ids=[0],
)
# Apply forces and torques together with custom application points
asset.permanent_wrench_composer.add_forces_and_torques(
forces=torch.ones(1, 1, 3),
torques=torch.ones(1, 1, 3),
positions=torch.ones(1, 1, 3),
env_ids=[0],
body_ids=[0],
)Instantaneous Wrenches (New):
# Apply forces for a single simulation step only
asset.instantaneous_wrench_composer.add_forces_and_torques(
forces=torch.ones(1, 1, 3),
env_ids=[0],
body_ids=[0],
)
# Multiple instantaneous wrenches compose automatically
asset.instantaneous_wrench_composer.add_forces_and_torques(
forces=torch.ones(1, 2, 3), # Add more forces
env_ids=[0],
body_ids=[0, 1],
)
# These are automatically reset after write_data_to_sim()Key Differences:
set_forces_and_torques()replaces existing wrenchesadd_forces_and_torques()composes with existing wrenches- Permanent and instantaneous wrenches compose automatically
- Instantaneous wrenches auto-clear after each simulation step
Use Cases:
- Drones: Compose thrust forces with aerodynamic drag and wind disturbances
- Boats: Apply buoyancy forces with wave-induced motions
Formatting and Linting - Migration to Ruff
The project has migrated from multiple tools (flake8 for linting, black for formatting, isort for import sorting) to a unified toolchain using ruff for all formatting and linting tasks.
Related PR: #4329, #4377, #4335, #4376
Why:
- Faster performance (10-100x speedup)
- Unified configuration in
pyproject.toml - More consistent formatting and linting rules
- Simplified developer workflow
Migration Steps:
-
Update configuration files:
# Copy the updated configuration from the main branch # Files to update: pyproject.toml, .pre-commit-config.yaml
-
Apply new formatting:
./isaaclab.sh --format
-
Resolve merge conflicts:
If you encounter merge conflicts after updating, they likely originate from formatting differences. After copying the new configuration files, rerun the formatting command and commit the changes.
Pre-commit hooks will automatically run
ruffon staged files. Ensure your code is formatted
before committing to avoid CI failures.
USD Utilities - Unified isaaclab.sim.utils Module
Isaac Lab now provides its own comprehensive USD utility module (isaaclab.sim.utils) instead of relying on scattered utilities from Isaac Sim's isaacsim.core.utils packages.
Related PR: #4286
Why:
- Better Organization: All USD operations grouped into logical submodules (stage, prims, queries, transforms, semantics)
- Type Hints: Full type annotations for better IDE support and code safety
- Version Compatibility: Handles differences between Isaac Sim versions automatically
Old API (Isaac Sim utilities):
import isaac.core.utils.stage as stage_utils
import isaac.core.utils.prims as prim_utils
# Stage operations
stage_utils.create_new_stage()
current_stage = stage_utils.get_current_stage()
# Prim operations
prim_utils.create_prim("/World/Cube", "Cube")
prim_utils.delete_prim("/World/OldObject")New API (Isaac Lab utilities):
import isaaclab.sim as sim_utils
# Stage operations
sim_utils.create_new_stage()
current_stage = sim_utils.get_current_stage()
# Prim operations
sim_utils.create_prim("/World/Cube", "Cube", attributes={"size": 1.0})
sim_utils.delete_prim("/World/OldObject")Legacy Support:
For backward compatibility, legacy functions are still available in isaaclab.sim.utils.legacy, but it's recommended to migrate to the new APIs or use USD directly.
🤗 New Contributors
- @jiang131072 made their first contribution in #3624
- @JuanaDd made their first contribution in #3522
- @mingxueg-nv made their first contribution in #3873
- @bmccann-bdai made their first contribution in #3994
- @renezurbruegg made their first contribution in #3716
- @gattra-rai made their first contribution in #3563
- @klakhi made their first contribution in #4180
- @Soappyooo made their first contribution in #4082
- @JinnnK made their first contribution in #4089
- @Rabbit-Hu made their first contribution in #4241
- @DBinK made their first contribution in #4055
- @emmanuel-ferdman made their first contribution in #4364
- @grzemal made their first contribution in #3760