Unverified Commit 4ee4957e authored by James Tigue's avatar James Tigue Committed by GitHub

Fixes actuator velocity limits propagation down the articulation root_physx_view (#1509)

# Description

<!--
Thank you for your interest in sending a pull request. Please make sure
to check the contribution guidelines.

Link: https://isaac-sim.github.io/IsaacLab/source/refs/contributing.html
-->

Previously the velocity limits of the the ActuatorBaseCfg do not get
used in most actuators. Only the DCMotor actuator uses it but it only
uses it for torque-speed limitations.

This PR propagates the velocity_limits of the ActuatorBaseCfg to the
articulation root_physx_view.

Fixes #1384 

<!-- As a practice, it is recommended to open an issue to have
discussions on the proposed pull request.
This makes it easier for the community to keep track of what is being
developed or added, and if a given feature
is demanded by more than one party. -->

## Type of change

<!-- As you go through the list, delete the ones that are not
applicable. -->

- Bug fix (non-breaking change which fixes an issue)

## Screenshots

Please attach before and after screenshots of the change if applicable.

<!--
Example:

| Before | After |
| ------ | ----- |
| _gif/png before_ | _gif/png after_ |

To upload images to a PR -- simply drag and drop an image while in edit
mode and it should upload the image directly. You can then paste that
source into the above before/after sections.
-->

## 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

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->

---------
Signed-off-by: 's avatarKelly Guo <kellyg@nvidia.com>
Co-authored-by: 's avatarKelly Guo <kellyg@nvidia.com>
Co-authored-by: 's avatarKelly Guo <kellyguo123@hotmail.com>
parent c2b32665
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.27.22" version = "0.27.23"
# Description # Description
title = "Isaac Lab framework for Robot Learning" title = "Isaac Lab framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.27.23 (2024-12-06)
~~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Fixed the enforcement of :attr:`~omni.isaac.lab.actuators.ActuatorBaseCfg.velocity_limits` at the
:attr:`~omni.isaac.lab.assets.Articulation.root_physx_view` level.
0.27.22 (2024-12-06) 0.27.22 (2024-12-06)
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
......
...@@ -424,6 +424,39 @@ class Articulation(AssetBase): ...@@ -424,6 +424,39 @@ class Articulation(AssetBase):
# set into simulation # set into simulation
self.root_physx_view.set_dof_dampings(self._data.joint_damping.cpu(), indices=physx_env_ids.cpu()) self.root_physx_view.set_dof_dampings(self._data.joint_damping.cpu(), indices=physx_env_ids.cpu())
def write_joint_velocity_limit_to_sim(
self,
limits: torch.Tensor | float,
joint_ids: Sequence[int] | slice | None = None,
env_ids: Sequence[int] | None = None,
):
"""Write joint max velocity to the simulation.
Args:
limits: Joint max velocity. Shape is (len(env_ids), len(joint_ids)).
joint_ids: The joint indices to set the max velocity for. Defaults to None (all joints).
env_ids: The environment indices to set the max velocity for. Defaults to None (all environments).
"""
# resolve indices
physx_env_ids = env_ids
if env_ids is None:
env_ids = slice(None)
physx_env_ids = self._ALL_INDICES
if joint_ids is None:
joint_ids = slice(None)
# broadcast env_ids if needed to allow double indexing
if env_ids != slice(None) and joint_ids != slice(None):
env_ids = env_ids[:, None]
# move tensor to cpu if needed
if isinstance(limits, torch.Tensor):
limits = limits.to(self.device)
# set into internal buffers
self._data.joint_velocity_limits = self.root_physx_view.get_dof_max_velocities().to(self.device)
self._data.joint_velocity_limits[env_ids, joint_ids] = limits
# set into simulation
self.root_physx_view.set_dof_max_velocities(self._data.joint_velocity_limits.cpu(), indices=physx_env_ids.cpu())
def write_joint_effort_limit_to_sim( def write_joint_effort_limit_to_sim(
self, self,
limits: torch.Tensor | float, limits: torch.Tensor | float,
...@@ -1158,6 +1191,7 @@ class Articulation(AssetBase): ...@@ -1158,6 +1191,7 @@ class Articulation(AssetBase):
self.write_joint_stiffness_to_sim(actuator.stiffness, joint_ids=actuator.joint_indices) self.write_joint_stiffness_to_sim(actuator.stiffness, joint_ids=actuator.joint_indices)
self.write_joint_damping_to_sim(actuator.damping, joint_ids=actuator.joint_indices) self.write_joint_damping_to_sim(actuator.damping, joint_ids=actuator.joint_indices)
self.write_joint_effort_limit_to_sim(actuator.effort_limit, joint_ids=actuator.joint_indices) self.write_joint_effort_limit_to_sim(actuator.effort_limit, joint_ids=actuator.joint_indices)
self.write_joint_velocity_limit_to_sim(actuator.velocity_limit, joint_ids=actuator.joint_indices)
self.write_joint_armature_to_sim(actuator.armature, joint_ids=actuator.joint_indices) self.write_joint_armature_to_sim(actuator.armature, joint_ids=actuator.joint_indices)
self.write_joint_friction_to_sim(actuator.friction, joint_ids=actuator.joint_indices) self.write_joint_friction_to_sim(actuator.friction, joint_ids=actuator.joint_indices)
else: else:
...@@ -1166,6 +1200,7 @@ class Articulation(AssetBase): ...@@ -1166,6 +1200,7 @@ class Articulation(AssetBase):
self.write_joint_stiffness_to_sim(0.0, joint_ids=actuator.joint_indices) self.write_joint_stiffness_to_sim(0.0, joint_ids=actuator.joint_indices)
self.write_joint_damping_to_sim(0.0, joint_ids=actuator.joint_indices) self.write_joint_damping_to_sim(0.0, joint_ids=actuator.joint_indices)
self.write_joint_effort_limit_to_sim(1.0e9, joint_ids=actuator.joint_indices) self.write_joint_effort_limit_to_sim(1.0e9, joint_ids=actuator.joint_indices)
self.write_joint_velocity_limit_to_sim(actuator.velocity_limit, joint_ids=actuator.joint_indices)
self.write_joint_armature_to_sim(actuator.armature, joint_ids=actuator.joint_indices) self.write_joint_armature_to_sim(actuator.armature, joint_ids=actuator.joint_indices)
self.write_joint_friction_to_sim(actuator.friction, joint_ids=actuator.joint_indices) self.write_joint_friction_to_sim(actuator.friction, joint_ids=actuator.joint_indices)
# Store the actual default stiffness and damping values for explicit actuators (not written the sim) # Store the actual default stiffness and damping values for explicit actuators (not written the sim)
......
...@@ -220,6 +220,9 @@ class ArticulationData: ...@@ -220,6 +220,9 @@ class ArticulationData:
joint_limits: torch.Tensor = None joint_limits: torch.Tensor = None
"""Joint limits provided to simulation. Shape is (num_instances, num_joints, 2).""" """Joint limits provided to simulation. Shape is (num_instances, num_joints, 2)."""
joint_velocity_limits: torch.Tensor = None
"""Joint maximum velocity provided to simulation. Shape is (num_instances, num_joints)."""
## ##
# Fixed tendon properties. # Fixed tendon properties.
## ##
......
...@@ -42,6 +42,8 @@ def generate_articulation_cfg( ...@@ -42,6 +42,8 @@ def generate_articulation_cfg(
articulation_type: Literal["humanoid", "panda", "anymal", "shadow_hand", "single_joint"], articulation_type: Literal["humanoid", "panda", "anymal", "shadow_hand", "single_joint"],
stiffness: float | None = 10.0, stiffness: float | None = 10.0,
damping: float | None = 2.0, damping: float | None = 2.0,
vel_limit: float | None = 100.0,
effort_limit: float | None = 400.0,
) -> ArticulationCfg: ) -> ArticulationCfg:
"""Generate an articulation configuration. """Generate an articulation configuration.
...@@ -72,8 +74,8 @@ def generate_articulation_cfg( ...@@ -72,8 +74,8 @@ def generate_articulation_cfg(
actuators={ actuators={
"joint": ImplicitActuatorCfg( "joint": ImplicitActuatorCfg(
joint_names_expr=[".*"], joint_names_expr=[".*"],
effort_limit=400.0, effort_limit=effort_limit,
velocity_limit=100.0, velocity_limit=vel_limit,
stiffness=0.0, stiffness=0.0,
damping=10.0, damping=10.0,
), ),
...@@ -813,6 +815,43 @@ class TestArticulation(unittest.TestCase): ...@@ -813,6 +815,43 @@ class TestArticulation(unittest.TestCase):
torch.testing.assert_close(articulation.actuators["body"].stiffness, expected_stiffness) torch.testing.assert_close(articulation.actuators["body"].stiffness, expected_stiffness)
torch.testing.assert_close(articulation.actuators["body"].damping, expected_damping) torch.testing.assert_close(articulation.actuators["body"].damping, expected_damping)
def test_setting_velocity_limits(self):
"""Test that velocity limits are loaded form the configuration correctly."""
for num_articulations in (1, 2):
for device in ("cuda:0", "cpu"):
for limit in (5.0, None):
with self.subTest(num_articulations=num_articulations, device=device, limit=limit):
with build_simulation_context(
device=device, add_ground_plane=False, auto_add_lighting=True
) as sim:
articulation_cfg = generate_articulation_cfg(
articulation_type="single_joint", vel_limit=limit, effort_limit=limit
)
articulation, _ = generate_articulation(
articulation_cfg=articulation_cfg, num_articulations=num_articulations, device=device
)
# Play sim
sim.reset()
if limit is not None:
# Expected gains
expected_velocity_limit = torch.full(
(articulation.num_instances, articulation.num_joints),
limit,
device=articulation.device,
)
# Check that gains are loaded from USD file
torch.testing.assert_close(
articulation.actuators["joint"].velocity_limit, expected_velocity_limit
)
torch.testing.assert_close(
articulation.data.joint_velocity_limits, expected_velocity_limit
)
torch.testing.assert_close(
articulation.root_physx_view.get_dof_max_velocities().to(device),
expected_velocity_limit,
)
def test_reset(self): def test_reset(self):
"""Test that reset method works properly. """Test that reset method works properly.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment