From 8b7a4a50575e34ee116ec0cf2303e06effdf0d68 Mon Sep 17 00:00:00 2001 From: JuanaDu Date: Mon, 22 Sep 2025 16:01:02 +0800 Subject: [PATCH 01/11] [Bugfix] use effort_limit from USD asset if not specified in cfg --- source/isaaclab/isaaclab/actuators/actuator_base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/isaaclab/isaaclab/actuators/actuator_base.py b/source/isaaclab/isaaclab/actuators/actuator_base.py index 16f04b30b69..3ce033fd632 100644 --- a/source/isaaclab/isaaclab/actuators/actuator_base.py +++ b/source/isaaclab/isaaclab/actuators/actuator_base.py @@ -159,7 +159,10 @@ def __init__( self.joint_property_resolution_table: dict[str, list] = {} # For explicit models, we do not want to enforce the effort limit through the solver # (unless it is explicitly set) - if not self.is_implicit_model and self.cfg.effort_limit_sim is None: + effort_limit_is_finite = ( + effort_limit != torch.inf if isinstance(effort_limit, float) else torch.all(effort_limit != torch.inf) + ) + if not self.is_implicit_model and self.cfg.effort_limit_sim is None and (not effort_limit_is_finite): self.cfg.effort_limit_sim = self._DEFAULT_MAX_EFFORT_SIM # resolve usd, actuator configuration values From 51f3234dc6228083e804666dd485414db2b50ff3 Mon Sep 17 00:00:00 2001 From: JuanaDu Date: Tue, 23 Sep 2025 15:57:45 +0800 Subject: [PATCH 02/11] fit effort_limit overwritten bug --- .../isaaclab/actuators/actuator_base.py | 9 +++--- .../assets/articulation/articulation.py | 3 +- .../isaaclab/test/assets/test_articulation.py | 31 +++++++++++++++---- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/source/isaaclab/isaaclab/actuators/actuator_base.py b/source/isaaclab/isaaclab/actuators/actuator_base.py index 3ce033fd632..826d7994339 100644 --- a/source/isaaclab/isaaclab/actuators/actuator_base.py +++ b/source/isaaclab/isaaclab/actuators/actuator_base.py @@ -159,10 +159,7 @@ def __init__( self.joint_property_resolution_table: dict[str, list] = {} # For explicit models, we do not want to enforce the effort limit through the solver # (unless it is explicitly set) - effort_limit_is_finite = ( - effort_limit != torch.inf if isinstance(effort_limit, float) else torch.all(effort_limit != torch.inf) - ) - if not self.is_implicit_model and self.cfg.effort_limit_sim is None and (not effort_limit_is_finite): + if not self.is_implicit_model and self.cfg.effort_limit_sim is None: self.cfg.effort_limit_sim = self._DEFAULT_MAX_EFFORT_SIM # resolve usd, actuator configuration values @@ -199,7 +196,9 @@ def __init__( ) self.velocity_limit = self._parse_joint_parameter(self.cfg.velocity_limit, self.velocity_limit_sim) - self.effort_limit = self._parse_joint_parameter(self.cfg.effort_limit, self.effort_limit_sim) + # For effort_limit, use the tensor passed to constructor if cfg.effort_limit is None + effort_default = self.effort_limit_sim if self.cfg.effort_limit is not None else effort_limit + self.effort_limit = self._parse_joint_parameter(self.cfg.effort_limit, effort_default) # create commands buffers for allocation self.computed_effort = torch.zeros(self._num_envs, self.num_joints, device=self._device) diff --git a/source/isaaclab/isaaclab/assets/articulation/articulation.py b/source/isaaclab/isaaclab/assets/articulation/articulation.py index 3a720de5573..968305163e0 100644 --- a/source/isaaclab/isaaclab/assets/articulation/articulation.py +++ b/source/isaaclab/isaaclab/assets/articulation/articulation.py @@ -1681,7 +1681,7 @@ def _process_actuators_cfg(self): friction=self._data.default_joint_friction_coeff[:, joint_ids], dynamic_friction=self._data.default_joint_dynamic_friction_coeff[:, joint_ids], viscous_friction=self._data.default_joint_viscous_friction_coeff[:, joint_ids], - effort_limit=self._data.joint_effort_limits[:, joint_ids], + effort_limit=self._data.joint_effort_limits[:, joint_ids].clone(), velocity_limit=self._data.joint_vel_limits[:, joint_ids], ) # log information on actuator groups @@ -1811,6 +1811,7 @@ def _apply_actuator_model(self): """ # process actions per group for actuator in self.actuators.values(): + # prepare input for actuator model based on cached data # TODO : A tensor dict would be nice to do the indexing of all tensors together control_action = ArticulationActions( diff --git a/source/isaaclab/test/assets/test_articulation.py b/source/isaaclab/test/assets/test_articulation.py index 46eb63762fd..333e8b08913 100644 --- a/source/isaaclab/test/assets/test_articulation.py +++ b/source/isaaclab/test/assets/test_articulation.py @@ -1372,10 +1372,16 @@ def test_setting_velocity_limit_explicit(sim, num_articulations, device, vel_lim @pytest.mark.parametrize("num_articulations", [1, 2]) @pytest.mark.parametrize("device", ["cuda:0", "cpu"]) @pytest.mark.parametrize("effort_limit_sim", [1e5, None]) -@pytest.mark.parametrize("effort_limit", [1e2, None]) +@pytest.mark.parametrize("effort_limit", [1e2, 80.0, None]) @pytest.mark.isaacsim_ci def test_setting_effort_limit_implicit(sim, num_articulations, device, effort_limit_sim, effort_limit): - """Test setting of the effort limit for implicit actuators.""" + """Test setting of effort limit for implicit actuators. + + This test verifies the effort limit resolution logic for actuator models implemented in :class:`ActuatorBase`: + - Case 1: If USD value == actuator config value: values match correctly + - Case 2: If USD value != actuator config value: actuator config value is used + - Case 3: If actuator config value is None: USD value is used as default + """ articulation_cfg = generate_articulation_cfg( articulation_type="single_joint_implicit", effort_limit_sim=effort_limit_sim, @@ -1419,10 +1425,18 @@ def test_setting_effort_limit_implicit(sim, num_articulations, device, effort_li @pytest.mark.parametrize("num_articulations", [1, 2]) @pytest.mark.parametrize("device", ["cuda:0", "cpu"]) @pytest.mark.parametrize("effort_limit_sim", [1e5, None]) -@pytest.mark.parametrize("effort_limit", [1e2, None]) +@pytest.mark.parametrize("effort_limit", [80.0, 1e2, None]) @pytest.mark.isaacsim_ci def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_limit_sim, effort_limit): - """Test setting of effort limit for explicit actuators.""" + """Test setting of effort limit for explicit actuators. + + This test verifies the effort limit resolution logic for actuator models implemented in :class:`ActuatorBase`: + - Case 1: If USD value == actuator config value: values match correctly + - Case 2: If USD value != actuator config value: actuator config value is used + - Case 3: If actuator config value is None: USD value is used as default + + """ + articulation_cfg = generate_articulation_cfg( articulation_type="single_joint_explicit", effort_limit_sim=effort_limit_sim, @@ -1436,6 +1450,9 @@ def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_li # Play sim sim.reset() + # usd default is 80 + usd_default = 80.0 + # collect limit init values physx_effort_limit = articulation.root_physx_view.get_dof_max_forces().to(device) actuator_effort_limit = articulation.actuators["joint"].effort_limit @@ -1452,8 +1469,9 @@ def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_li # check physx effort limit does not match the one explicit actuator has assert not (torch.allclose(actuator_effort_limit, physx_effort_limit)) else: - # check actuator effort_limit is the same as the PhysX default - torch.testing.assert_close(actuator_effort_limit, physx_effort_limit) + # When effort_limit is None, actuator should use USD default values + expected_actuator_effort_limit = torch.full_like(physx_effort_limit, usd_default) + torch.testing.assert_close(actuator_effort_limit, expected_actuator_effort_limit) # when using explicit actuators, the limits are set to high unless user overrides if effort_limit_sim is not None: @@ -1462,6 +1480,7 @@ def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_li limit = ActuatorBase._DEFAULT_MAX_EFFORT_SIM # type: ignore # check physx internal value matches the expected sim value expected_effort_limit = torch.full_like(physx_effort_limit, limit) + torch.testing.assert_close(actuator_effort_limit_sim, expected_effort_limit) torch.testing.assert_close(physx_effort_limit, expected_effort_limit) From c1af79e54316123a4f7c162ecc0c72587a6b25dc Mon Sep 17 00:00:00 2001 From: Juana Date: Mon, 27 Oct 2025 10:40:55 +0800 Subject: [PATCH 03/11] Update source/isaaclab/test/assets/test_articulation.py Co-authored-by: James Tigue <166445701+jtigue-bdai@users.noreply.github.com> Signed-off-by: Juana --- source/isaaclab/test/assets/test_articulation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/isaaclab/test/assets/test_articulation.py b/source/isaaclab/test/assets/test_articulation.py index 5284aa277cf..2f36d2cbf75 100644 --- a/source/isaaclab/test/assets/test_articulation.py +++ b/source/isaaclab/test/assets/test_articulation.py @@ -1450,8 +1450,8 @@ def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_li # Play sim sim.reset() - # usd default is 80 - usd_default = 80.0 + # usd default effort limit is set to 80 + usd_default_effort_limit = 80.0 # collect limit init values physx_effort_limit = articulation.root_physx_view.get_dof_max_forces().to(device) From 451a1f99296f62a10fb7cd6c7e64d22fdf9501f8 Mon Sep 17 00:00:00 2001 From: Juana Date: Mon, 27 Oct 2025 10:41:26 +0800 Subject: [PATCH 04/11] Update source/isaaclab/test/assets/test_articulation.py Co-authored-by: James Tigue <166445701+jtigue-bdai@users.noreply.github.com> Signed-off-by: Juana --- source/isaaclab/test/assets/test_articulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/isaaclab/test/assets/test_articulation.py b/source/isaaclab/test/assets/test_articulation.py index 2f36d2cbf75..3dda2c89396 100644 --- a/source/isaaclab/test/assets/test_articulation.py +++ b/source/isaaclab/test/assets/test_articulation.py @@ -1470,7 +1470,7 @@ def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_li assert not (torch.allclose(actuator_effort_limit, physx_effort_limit)) else: # When effort_limit is None, actuator should use USD default values - expected_actuator_effort_limit = torch.full_like(physx_effort_limit, usd_default) + expected_actuator_effort_limit = torch.full_like(physx_effort_limit, usd_default_effort_limit) torch.testing.assert_close(actuator_effort_limit, expected_actuator_effort_limit) # when using explicit actuators, the limits are set to high unless user overrides From 138b8c7ad205299bc4f2d368b0d6c75a536facfa Mon Sep 17 00:00:00 2001 From: Juana Date: Mon, 27 Oct 2025 10:43:06 +0800 Subject: [PATCH 05/11] Update source/isaaclab/isaaclab/actuators/actuator_base.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Signed-off-by: Juana --- source/isaaclab/isaaclab/actuators/actuator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/isaaclab/isaaclab/actuators/actuator_base.py b/source/isaaclab/isaaclab/actuators/actuator_base.py index 826d7994339..3086326d365 100644 --- a/source/isaaclab/isaaclab/actuators/actuator_base.py +++ b/source/isaaclab/isaaclab/actuators/actuator_base.py @@ -197,7 +197,7 @@ def __init__( self.velocity_limit = self._parse_joint_parameter(self.cfg.velocity_limit, self.velocity_limit_sim) # For effort_limit, use the tensor passed to constructor if cfg.effort_limit is None - effort_default = self.effort_limit_sim if self.cfg.effort_limit is not None else effort_limit + effort_default = effort_limit if self.cfg.effort_limit is None else self.effort_limit_sim self.effort_limit = self._parse_joint_parameter(self.cfg.effort_limit, effort_default) # create commands buffers for allocation From dc1f1ea2e758c00df3dfe5aa4cb4dd790f2b08b6 Mon Sep 17 00:00:00 2001 From: JuanaDu Date: Mon, 27 Oct 2025 11:22:50 +0800 Subject: [PATCH 06/11] improve documentation for effort_limit_sim , effort_limit and how they are processed --- .../isaaclab/actuators/actuator_base.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/source/isaaclab/isaaclab/actuators/actuator_base.py b/source/isaaclab/isaaclab/actuators/actuator_base.py index 3086326d365..3a2333bff77 100644 --- a/source/isaaclab/isaaclab/actuators/actuator_base.py +++ b/source/isaaclab/isaaclab/actuators/actuator_base.py @@ -55,13 +55,21 @@ class ActuatorBase(ABC): effort_limit: torch.Tensor """The effort limit for the actuator group. Shape is (num_envs, num_joints). - For implicit actuators, the :attr:`effort_limit` and :attr:`effort_limit_sim` are the same. + This limit is used differently depending on the actuator type: + + - **Explicit actuators**: Used for internal torque clipping within the actuator model + (e.g., motor torque limits in DC motor models). + - **Implicit actuators**: Same as :attr:`effort_limit_sim` (aliased for consistency). """ effort_limit_sim: torch.Tensor """The effort limit for the actuator group in the simulation. Shape is (num_envs, num_joints). For implicit actuators, the :attr:`effort_limit` and :attr:`effort_limit_sim` are the same. + + - **Explicit actuators**: Typically set to a large value (1.0e9) to avoid double-clipping, + since the actuator model already clips efforts using :attr:`effort_limit`. + - **Implicit actuators**: Same as :attr:`effort_limit` (both values are synchronized). """ velocity_limit: torch.Tensor @@ -123,8 +131,11 @@ def __init__( are not specified in the configuration, then their values provided in the constructor are used. .. note:: - The values in the constructor are typically obtained through the USD schemas corresponding - to the joints in the actuator model. + The values in the constructor are typically obtained through the USD values passed from the PhysX API calls + corresponding to the joints in the actuator model; these values serve as default values if the parameters + are not specified in the cfg. + + Args: cfg: The configuration of the actuator model. @@ -196,7 +207,10 @@ def __init__( ) self.velocity_limit = self._parse_joint_parameter(self.cfg.velocity_limit, self.velocity_limit_sim) - # For effort_limit, use the tensor passed to constructor if cfg.effort_limit is None + # Parse effort_limit with special default handling: + # - If cfg.effort_limit is None, use the original USD value (effort_limit parameter from constructor) + # - Otherwise, use effort_limit_sim as the default + # Please refer to the documentation of the effort_limit and effort_limit_sim parameters for more details. effort_default = effort_limit if self.cfg.effort_limit is None else self.effort_limit_sim self.effort_limit = self._parse_joint_parameter(self.cfg.effort_limit, effort_default) From 53965576a052d3402c45539fed807046ef2c3fa4 Mon Sep 17 00:00:00 2001 From: JuanaDu Date: Mon, 3 Nov 2025 16:26:34 +0800 Subject: [PATCH 07/11] Update CHANGELOG.rst and extension.toml --- source/isaaclab/config/extension.toml | 2 +- source/isaaclab/docs/CHANGELOG.rst | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/source/isaaclab/config/extension.toml b/source/isaaclab/config/extension.toml index 5903a09cef4..d281efd1f7f 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.47.5" +version = "0.47.6" # Description title = "Isaac Lab framework for Robot Learning" diff --git a/source/isaaclab/docs/CHANGELOG.rst b/source/isaaclab/docs/CHANGELOG.rst index 5fd5463ae75..0ace69fa351 100644 --- a/source/isaaclab/docs/CHANGELOG.rst +++ b/source/isaaclab/docs/CHANGELOG.rst @@ -1,6 +1,16 @@ Changelog --------- +0.47.6 (2025-11-03) +~~~~~~~~~~~~~~~~~~~ + +Changed +^^^^^^^ + +* Fixed the bug where effort limits were being overridden in :class:`~isaaclab.actuators.ActuatorBase` when the ``effort_limit`` parameter is set to None. +* Corrected the unit tests for three effort limit scenarios with proper assertions + + 0.47.5 (2025-10-30) ~~~~~~~~~~~~~~~~~~~ From 959de178d75597873ad6cc281460c6505dabec45 Mon Sep 17 00:00:00 2001 From: Kelly Guo Date: Wed, 5 Nov 2025 16:29:59 -0800 Subject: [PATCH 08/11] Update source/isaaclab/docs/CHANGELOG.rst Signed-off-by: Kelly Guo --- source/isaaclab/docs/CHANGELOG.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/source/isaaclab/docs/CHANGELOG.rst b/source/isaaclab/docs/CHANGELOG.rst index 4fa461fb6e0..4f373ecdb80 100644 --- a/source/isaaclab/docs/CHANGELOG.rst +++ b/source/isaaclab/docs/CHANGELOG.rst @@ -16,7 +16,6 @@ Fixed Changed ^^^^^^^ - * Changed Pink IK controller qpsolver from osqp to daqp. * Changed Null Space matrix computation in Pink IK's Null Space Posture Task to a faster matrix pseudo inverse computation. From c67e77ed22d5184966669dbb85d2dc0dd89a4cd0 Mon Sep 17 00:00:00 2001 From: Kelly Guo Date: Wed, 5 Nov 2025 16:30:08 -0800 Subject: [PATCH 09/11] Update source/isaaclab/docs/CHANGELOG.rst Signed-off-by: Kelly Guo --- source/isaaclab/docs/CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/isaaclab/docs/CHANGELOG.rst b/source/isaaclab/docs/CHANGELOG.rst index 4f373ecdb80..dc2f0eb16d2 100644 --- a/source/isaaclab/docs/CHANGELOG.rst +++ b/source/isaaclab/docs/CHANGELOG.rst @@ -10,6 +10,7 @@ Fixed * Fixed the bug where effort limits were being overridden in :class:`~isaaclab.actuators.ActuatorBase` when the ``effort_limit`` parameter is set to None. * Corrected the unit tests for three effort limit scenarios with proper assertions + 0.47.7 (2025-10-31) ~~~~~~~~~~~~~~~~~~~ From b6bdbc391e239dfdd79ebab8c0206d5b99d6d3e2 Mon Sep 17 00:00:00 2001 From: Kelly Guo Date: Wed, 5 Nov 2025 16:30:15 -0800 Subject: [PATCH 10/11] Update source/isaaclab/isaaclab/assets/articulation/articulation.py Signed-off-by: Kelly Guo --- source/isaaclab/isaaclab/assets/articulation/articulation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/source/isaaclab/isaaclab/assets/articulation/articulation.py b/source/isaaclab/isaaclab/assets/articulation/articulation.py index f65979b1b23..a76d5ae4444 100644 --- a/source/isaaclab/isaaclab/assets/articulation/articulation.py +++ b/source/isaaclab/isaaclab/assets/articulation/articulation.py @@ -1843,7 +1843,6 @@ def _apply_actuator_model(self): """ # process actions per group for actuator in self.actuators.values(): - # prepare input for actuator model based on cached data # TODO : A tensor dict would be nice to do the indexing of all tensors together control_action = ArticulationActions( From c651306735d468ca1f47e9db868b5dc466cb312a Mon Sep 17 00:00:00 2001 From: JuanaDu Date: Thu, 6 Nov 2025 20:04:24 +0800 Subject: [PATCH 11/11] Fix test_ideal_pd_actuator.py --- source/isaaclab/test/actuators/test_ideal_pd_actuator.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/isaaclab/test/actuators/test_ideal_pd_actuator.py b/source/isaaclab/test/actuators/test_ideal_pd_actuator.py index b1ca5a3f693..8db41edf164 100644 --- a/source/isaaclab/test/actuators/test_ideal_pd_actuator.py +++ b/source/isaaclab/test/actuators/test_ideal_pd_actuator.py @@ -68,9 +68,7 @@ def test_ideal_pd_actuator_init_minimum(num_envs, num_joints, device, usd_defaul torch.testing.assert_close(actuator.computed_effort, torch.zeros(num_envs, num_joints, device=device)) torch.testing.assert_close(actuator.applied_effort, torch.zeros(num_envs, num_joints, device=device)) - torch.testing.assert_close( - actuator.effort_limit, actuator._DEFAULT_MAX_EFFORT_SIM * torch.ones(num_envs, num_joints, device=device) - ) + torch.testing.assert_close(actuator.effort_limit, torch.inf * torch.ones(num_envs, num_joints, device=device)) torch.testing.assert_close( actuator.effort_limit_sim, actuator._DEFAULT_MAX_EFFORT_SIM * torch.ones(num_envs, num_joints, device=device) ) @@ -133,11 +131,11 @@ def test_ideal_pd_actuator_init_effort_limits(num_envs, num_joints, device, effo effort_lim_sim_expected = actuator._DEFAULT_MAX_EFFORT_SIM elif effort_lim is None and effort_lim_sim is not None: - effort_lim_expected = effort_lim_sim + effort_lim_expected = effort_lim_default effort_lim_sim_expected = effort_lim_sim elif effort_lim is None and effort_lim_sim is None: - effort_lim_expected = actuator._DEFAULT_MAX_EFFORT_SIM + effort_lim_expected = effort_lim_default effort_lim_sim_expected = actuator._DEFAULT_MAX_EFFORT_SIM elif effort_lim is not None and effort_lim_sim is not None: