diff --git a/source/extensions/omni.isaac.lab/config/extension.toml b/source/extensions/omni.isaac.lab/config/extension.toml index 7e9225c2b3b..517ac006104 100644 --- a/source/extensions/omni.isaac.lab/config/extension.toml +++ b/source/extensions/omni.isaac.lab/config/extension.toml @@ -1,7 +1,7 @@ [package] # Note: Semantic Versioning is used: https://semver.org/ -version = "0.25.0" +version = "0.25.1" # Description title = "Isaac Lab framework for Robot Learning" diff --git a/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst b/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst index b0fa66f6291..e78abdb068d 100644 --- a/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst +++ b/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst @@ -1,6 +1,16 @@ Changelog --------- +0.25.1 (2024-10-10) +~~~~~~~~~~~~~~~~~~~ + +Fixed +^^^^^ + +* Fixed potential issue where default joint positions can fall outside of the limits being set with Articulation's + ``write_joint_limits_to_sim`` API. + + 0.25.0 (2024-10-06) ~~~~~~~~~~~~~~~~~~~ @@ -14,7 +24,7 @@ Added 0.24.20 (2024-10-07) ~~~~~~~~~~~~~~~~~~~~ -Fixes +Fixed ^^^^^ * Fixed the :meth:`omni.isaac.lab.envs.mdp.events.randomize_rigid_body_material` function to diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py index c1765df56c3..9357d90ca5c 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py @@ -539,6 +539,13 @@ def write_joint_limits_to_sim( env_ids = env_ids[:, None] # set into internal buffers self._data.joint_limits[env_ids, joint_ids] = limits + # update default joint pos to stay within the new limits + if torch.any((self._data.default_joint_pos < limits[..., 0]) | (self._data.default_joint_pos > limits[..., 1])): + self._data.default_joint_pos = torch.clamp(self._data.default_joint_pos, limits[..., 0], limits[..., 1]) + carb.log_warn( + "Some default joint positions are outside of the range of the new joint limits. Default joint positions" + " will be clamped to be within the new joint limits." + ) # set into simulation self.root_physx_view.set_dof_limits(self._data.joint_limits.cpu(), indices=physx_env_ids.cpu()) diff --git a/source/extensions/omni.isaac.lab/test/assets/test_articulation.py b/source/extensions/omni.isaac.lab/test/assets/test_articulation.py index 2fc0910ee97..da0b9accf6f 100644 --- a/source/extensions/omni.isaac.lab/test/assets/test_articulation.py +++ b/source/extensions/omni.isaac.lab/test/assets/test_articulation.py @@ -542,6 +542,48 @@ def test_out_of_range_default_joint_vel(self): # Check if articulation is initialized self.assertFalse(articulation._is_initialized) + def test_joint_limits(self): + """Test write_joint_limits_to_sim API and when default pos falls outside of the new limits.""" + for num_articulations in (1, 2): + for device in ("cuda:0", "cpu"): + with self.subTest(num_articulations=num_articulations, device=device): + with build_simulation_context(device=device, add_ground_plane=True, auto_add_lighting=True) as sim: + # Create articulation + articulation_cfg = generate_articulation_cfg(articulation_type="panda") + articulation, _ = generate_articulation(articulation_cfg, num_articulations, device) + + # Play sim + sim.reset() + # Check if articulation is initialized + self.assertTrue(articulation._is_initialized) + + # Get current default joint pos + default_joint_pos = articulation._data.default_joint_pos.clone() + + # Set new joint limits + limits = torch.zeros(num_articulations, articulation.num_joints, 2, device=device) + limits[..., 0] = ( + torch.rand(num_articulations, articulation.num_joints, device=device) + 5.0 + ) * -1.0 + limits[..., 1] = torch.rand(num_articulations, articulation.num_joints, device=device) + 5.0 + articulation.write_joint_limits_to_sim(limits) + + # Check new limits are in place + torch.testing.assert_close(articulation._data.joint_limits, limits) + torch.testing.assert_close(articulation._data.default_joint_pos, default_joint_pos) + + # Set new joint limits that invalidate default joint pos + limits = torch.zeros(num_articulations, articulation.num_joints, 2, device=device) + limits[..., 0] = torch.rand(num_articulations, articulation.num_joints, device=device) * -0.1 + limits[..., 1] = torch.rand(num_articulations, articulation.num_joints, device=device) * 0.1 + articulation.write_joint_limits_to_sim(limits) + + # Check if all values are within the bounds + within_bounds = (articulation._data.default_joint_pos >= limits[..., 0]) & ( + articulation._data.default_joint_pos <= limits[..., 1] + ) + self.assertTrue(torch.all(within_bounds)) + def test_external_force_on_single_body(self): """Test application of external force on the base of the articulation.""" for num_articulations in (1, 2): diff --git a/tools/per_test_timeouts.py b/tools/per_test_timeouts.py index e9fad0a2938..e98595372f8 100644 --- a/tools/per_test_timeouts.py +++ b/tools/per_test_timeouts.py @@ -8,6 +8,7 @@ Any tests not listed here will use the default timeout. """ PER_TEST_TIMEOUTS = { + "test_articulation.py": 200, "test_environments.py": 1200, # This test runs through all the environments for 100 steps each "test_environment_determinism.py": 200, # This test runs through many the environments for 100 steps each "test_env_rendering_logic.py": 300,