Skip to content

Commit

Permalink
Merge branch 'main' into startup_thread
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhoeller19 authored Aug 2, 2024
2 parents 761c327 + 692b177 commit 0232e1c
Show file tree
Hide file tree
Showing 65 changed files with 642 additions and 170 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Guidelines for modifications:
* Johnson Sun
* Kourosh Darvish
* Lorenz Wellhausen
* Masoud Moghani
* Muhong Guo
* Nuralem Abizov
* Özhan Özen
Expand Down
2 changes: 1 addition & 1 deletion source/extensions/omni.isaac.lab/config/extension.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

# Note: Semantic Versioning is used: https://semver.org/
version = "0.20.0"
version = "0.20.4"

# Description
title = "Isaac Lab framework for Robot Learning"
Expand Down
47 changes: 47 additions & 0 deletions source/extensions/omni.isaac.lab/docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,53 @@
Changelog
---------

0.20.4 (2024-08-02)
~~~~~~~~~~~~~~~~~~~

Fixed
^^^^^

* Fixed the caching of terrains when using the :class:`omni.isaac.lab.terrains.TerrainGenerator` class.
Earlier, the random sampling of the difficulty levels led to different hash values for the same terrain
configuration. This caused the terrains to be re-generated even when the same configuration was used.
Now, the numpy random generator is seeded with the same seed to ensure that the difficulty levels are
sampled in the same order between different runs.


0.20.3 (2024-08-02)
~~~~~~~~~~~~~~~~~~~

Fixed
^^^^^

* Fixed the setting of translation and orientation when spawning a mesh prim. Earlier, the translation
and orientation was being applied both on the parent Xform and the mesh prim. This was causing the
mesh prim to be offset by the translation and orientation of the parent Xform, which is not the intended
behavior.


0.20.2 (2024-08-02)
~~~~~~~~~~~~~~~~~~~

Changed
^^^^^^^

* Modified the computation of body acceleration for rigid body data to use PhysX APIs instead of
numerical finite-differencing. This removes the need for computation of body acceleration at
every update call of the data buffer.


0.20.1 (2024-07-30)
~~~~~~~~~~~~~~~~~~~

Fixed
^^^^^

* Fixed the :meth:`omni.isaac.lab.utils.math.wrap_to_pi` method to handle the wrapping of angles correctly.
Earlier, the method was not wrapping the angles to the range [-pi, pi] correctly when the angles were outside
the range [-2*pi, 2*pi].


0.20.0 (2024-07-26)
~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ class ArticulationData(RigidObjectData):
This class extends the :class:`RigidObjectData` class to provide additional data for
an articulation mainly related to the joints and tendons.
An articulation is comprised of multiple rigid bodies or links. For a rigid body, there are two frames
of reference that are used:
- Actor frame: The frame of reference of the rigid body prim. This typically corresponds to the Xform prim
with the rigid body schema.
- Center of mass frame: The frame of reference of the center of mass of the rigid body.
Depending on the settings, the two frames may not coincide with each other. In the robotics sense, the actor frame
can be interpreted as the link frame.
"""

_root_physx_view: physx.ArticulationView
Expand Down Expand Up @@ -211,7 +221,11 @@ def update(self, dt: float):

@property
def root_state_w(self):
"""Root state ``[pos, quat, lin_vel, ang_vel]`` in simulation world frame. Shape is (num_instances, 13)."""
"""Root state ``[pos, quat, lin_vel, ang_vel]`` in simulation world frame. Shape is (num_instances, 13).
The position and quaternion are of the articulation root's actor frame. Meanwhile, the linear and angular
velocities are of the articulation root's center of mass frame.
"""
if self._root_state_w.timestamp < self._sim_timestamp:
# read data from simulation
pose = self._root_physx_view.get_root_transforms().clone()
Expand All @@ -225,7 +239,11 @@ def root_state_w(self):
@property
def body_state_w(self):
"""State of all bodies `[pos, quat, lin_vel, ang_vel]` in simulation world frame.
Shape is (num_instances, num_bodies, 13)."""
Shape is (num_instances, num_bodies, 13).
The position and quaternion are of all the articulation links's actor frame. Meanwhile, the linear and angular
velocities are of the articulation links's center of mass frame.
"""
if self._body_state_w.timestamp < self._sim_timestamp:
# read data from simulation
poses = self._root_physx_view.get_link_transforms().clone()
Expand All @@ -238,7 +256,10 @@ def body_state_w(self):

@property
def body_acc_w(self):
"""Acceleration of all bodies. Shape is (num_instances, num_bodies, 6)."""
"""Acceleration of all bodies. Shape is (num_instances, num_bodies, 6).
This quantity is the acceleration of the articulation links' center of mass frame.
"""
if self._body_acc_w.timestamp < self._sim_timestamp:
# read data from simulation and set the buffer data and timestamp
self._body_acc_w.data = self._root_physx_view.get_link_accelerations()
Expand All @@ -247,12 +268,18 @@ def body_acc_w(self):

@property
def body_lin_acc_w(self) -> torch.Tensor:
"""Linear acceleration of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3)."""
"""Linear acceleration of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3).
This quantity is the linear acceleration of the articulation links' center of mass frame.
"""
return self.body_acc_w[..., 0:3]

@property
def body_ang_acc_w(self) -> torch.Tensor:
"""Angular acceleration of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3)."""
"""Angular acceleration of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3).
This quantity is the angular acceleration of the articulation links' center of mass frame.
"""
return self.body_acc_w[..., 3:6]

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ def write_root_velocity_to_sim(self, root_velocity: torch.Tensor, env_ids: Seque
# note: we need to do this here since tensors are not set into simulation until step.
# set into internal buffers
self._data.root_state_w[env_ids, 7:] = root_velocity.clone()
self._data._previous_body_vel_w[env_ids, 0] = root_velocity.clone()
self._data.body_acc_w[env_ids] = 0.0
# set into simulation
self.root_physx_view.set_velocities(self._data.root_state_w[:, 7:], indices=physx_env_ids)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ class RigidObjectData:
the root rigid body and the state of all the bodies in the object. The data is stored in the simulation
world frame unless otherwise specified.
For a rigid body, there are two frames of reference that are used:
- Actor frame: The frame of reference of the rigid body prim. This typically corresponds to the Xform prim
with the rigid body schema.
- Center of mass frame: The frame of reference of the center of mass of the rigid body.
Depending on the settings of the simulation, the actor frame and the center of mass frame may be the same.
This needs to be taken into account when interpreting the data.
The data is lazily updated, meaning that the data is only updated when it is accessed. This is useful
when the data is expensive to compute or retrieve. The data is updated when the timestamp of the buffer
is older than the current simulation timestamp. The timestamp is updated whenever the data is updated.
Expand Down Expand Up @@ -57,9 +66,6 @@ def __init__(self, root_physx_view: physx.RigidBodyView, device: str):
self.GRAVITY_VEC_W = gravity_dir.repeat(self._root_physx_view.count, 1)
self.FORWARD_VEC_B = torch.tensor((1.0, 0.0, 0.0), device=self.device).repeat(self._root_physx_view.count, 1)

# Initialize buffers for finite differencing
self._previous_body_vel_w = torch.zeros((self._root_physx_view.count, 1, 6), device=self.device)

# Initialize the lazy buffers.
self._root_state_w = TimestampedBuffer()
self._body_acc_w = TimestampedBuffer()
Expand All @@ -71,9 +77,6 @@ def update(self, dt: float):
dt: The time step for the update. This must be a positive value.
"""
self._sim_timestamp += dt
# Trigger an update of the body acceleration buffer at a higher frequency
# since we do finite differencing.
self.body_acc_w

##
# Names.
Expand All @@ -87,7 +90,11 @@ def update(self, dt: float):
##

default_root_state: torch.Tensor = None
"""Default root state ``[pos, quat, lin_vel, ang_vel]`` in local environment frame. Shape is (num_instances, 13)."""
"""Default root state ``[pos, quat, lin_vel, ang_vel]`` in local environment frame. Shape is (num_instances, 13).
The position and quaternion are of the rigid body's actor frame. Meanwhile, the linear and angular velocities are
of the center of mass frame.
"""

default_mass: torch.Tensor = None
""" Default mass provided by simulation. Shape is (num_instances, num_bodies)."""
Expand All @@ -98,7 +105,11 @@ def update(self, dt: float):

@property
def root_state_w(self):
"""Root state ``[pos, quat, lin_vel, ang_vel]`` in simulation world frame. Shape is (num_instances, 13)."""
"""Root state ``[pos, quat, lin_vel, ang_vel]`` in simulation world frame. Shape is (num_instances, 13).
The position and orientation are of the rigid body's actor frame. Meanwhile, the linear and angular
velocities are of the rigid body's center of mass frame.
"""
if self._root_state_w.timestamp < self._sim_timestamp:
# read data from simulation
pose = self._root_physx_view.get_transforms().clone()
Expand All @@ -111,20 +122,24 @@ def root_state_w(self):

@property
def body_state_w(self):
"""State of all bodies `[pos, quat, lin_vel, ang_vel]` in simulation world frame. Shape is (num_instances, 1, 13)."""
"""State of all bodies `[pos, quat, lin_vel, ang_vel]` in simulation world frame. Shape is (num_instances, 1, 13).
The position and orientation are of the rigid bodies' actor frame. Meanwhile, the linear and angular
velocities are of the rigid bodies' center of mass frame.
"""
return self.root_state_w.view(-1, 1, 13)

@property
def body_acc_w(self):
"""Acceleration of all bodies. Shape is (num_instances, 1, 6)."""
"""Acceleration of all bodies. Shape is (num_instances, 1, 6).
This quantity is the acceleration of the rigid bodies' center of mass frame. The acceleration
is computed using finite differencing of the linear and angular velocities of the bodies.
"""
if self._body_acc_w.timestamp < self._sim_timestamp:
# note: we use finite differencing to compute acceleration
self._body_acc_w.data = (self.body_vel_w - self._previous_body_vel_w) / (
self._sim_timestamp - self._body_acc_w.timestamp
)
self._body_acc_w.data = self._root_physx_view.get_accelerations().unsqueeze(1)
self._body_acc_w.timestamp = self._sim_timestamp
# update the previous velocity
self._previous_body_vel_w[:] = self.body_vel_w
return self._body_acc_w.data

@property
Expand All @@ -145,60 +160,98 @@ def heading_w(self):

@property
def root_pos_w(self) -> torch.Tensor:
"""Root position in simulation world frame. Shape is (num_instances, 3)."""
"""Root position in simulation world frame. Shape is (num_instances, 3).
This quantity is the position of the actor frame of the root rigid body.
"""
return self.root_state_w[:, :3]

@property
def root_quat_w(self) -> torch.Tensor:
"""Root orientation (w, x, y, z) in simulation world frame. Shape is (num_instances, 4)."""
"""Root orientation (w, x, y, z) in simulation world frame. Shape is (num_instances, 4).
This quantity is the orientation of the actor frame of the root rigid body.
"""
return self.root_state_w[:, 3:7]

@property
def root_vel_w(self) -> torch.Tensor:
"""Root velocity in simulation world frame. Shape is (num_instances, 6)."""
"""Root velocity in simulation world frame. Shape is (num_instances, 6).
This quantity contains the linear and angular velocities of the root rigid body's center of mass frame.
"""
return self.root_state_w[:, 7:13]

@property
def root_lin_vel_w(self) -> torch.Tensor:
"""Root linear velocity in simulation world frame. Shape is (num_instances, 3)."""
"""Root linear velocity in simulation world frame. Shape is (num_instances, 3).
This quantity is the linear velocity of the root rigid body's center of mass frame.
"""
return self.root_state_w[:, 7:10]

@property
def root_ang_vel_w(self) -> torch.Tensor:
"""Root angular velocity in simulation world frame. Shape is (num_instances, 3)."""
"""Root angular velocity in simulation world frame. Shape is (num_instances, 3).
This quantity is the angular velocity of the root rigid body's center of mass frame.
"""
return self.root_state_w[:, 10:13]

@property
def root_lin_vel_b(self) -> torch.Tensor:
"""Root linear velocity in base frame. Shape is (num_instances, 3)."""
"""Root linear velocity in base frame. Shape is (num_instances, 3).
This quantity is the linear velocity of the root rigid body's center of mass frame with respect to the
rigid body's actor frame.
"""
return math_utils.quat_rotate_inverse(self.root_quat_w, self.root_lin_vel_w)

@property
def root_ang_vel_b(self) -> torch.Tensor:
"""Root angular velocity in base world frame. Shape is (num_instances, 3)."""
"""Root angular velocity in base world frame. Shape is (num_instances, 3).
This quantity is the angular velocity of the root rigid body's center of mass frame with respect to the
rigid body's actor frame.
"""
return math_utils.quat_rotate_inverse(self.root_quat_w, self.root_ang_vel_w)

@property
def body_pos_w(self) -> torch.Tensor:
"""Positions of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3)."""
"""Positions of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3).
This quantity is the position of the rigid bodies' actor frame.
"""
return self.body_state_w[..., :3]

@property
def body_quat_w(self) -> torch.Tensor:
"""Orientation (w, x, y, z) of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 4)."""
"""Orientation (w, x, y, z) of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 4).
This quantity is the orientation of the rigid bodies' actor frame.
"""
return self.body_state_w[..., 3:7]

@property
def body_vel_w(self) -> torch.Tensor:
"""Velocity of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 6)."""
"""Velocity of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 6).
This quantity contains the linear and angular velocities of the rigid bodies' center of mass frame.
"""
return self.body_state_w[..., 7:13]

@property
def body_lin_vel_w(self) -> torch.Tensor:
"""Linear velocity of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3)."""
"""Linear velocity of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3).
This quantity is the linear velocity of the rigid bodies' center of mass frame.
"""
return self.body_state_w[..., 7:10]

@property
def body_ang_vel_w(self) -> torch.Tensor:
"""Angular velocity of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3)."""
"""Angular velocity of all bodies in simulation world frame. Shape is (num_instances, num_bodies, 3).
This quantity is the angular velocity of the rigid bodies' center of mass frame.
"""
return self.body_state_w[..., 10:13]
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,21 @@ class ContactSensor(SensorBase):
in the asset.
The sensor can be configured to report the contact forces on a set of bodies with a given
filter pattern. Please check the documentation on `RigidContactView`_ for more details.
filter pattern using the :attr:`ContactSensorCfg.filter_prim_paths_expr`. This is useful
when you want to report the contact forces between the sensor bodies and a specific set of
bodies in the scene. The data can be accessed using the :attr:`ContactSensorData.force_matrix_w`.
Please check the documentation on `RigidContactView`_ for more details.
The reporting of the filtered contact forces is only possible as one-to-many. This means that only one
sensor body in an environment can be filtered against multiple bodies in that environment. If you need to
filter multiple sensor bodies against multiple bodies, you need to create separate sensors for each sensor
body.
As an example, suppose you want to report the contact forces for all the feet of a robot against an object
exclusively. In that case, setting the :attr:`ContactSensorCfg.prim_path` and
:attr:`ContactSensorCfg.filter_prim_paths_expr` with ``{ENV_REGEX_NS}/Robot/.*_FOOT`` and ``{ENV_REGEX_NS}/Object``
respectively will not work. Instead, you need to create a separate sensor for each foot and filter
it against the object.
.. _PhysX ContactReporter: https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/104.2/class_physx_schema_physx_contact_report_a_p_i.html
.. _RigidContactView: https://docs.omniverse.nvidia.com/py/isaacsim/source/extensions/omni.isaac.core/docs/index.html#omni.isaac.core.prims.RigidContactView
Expand Down Expand Up @@ -321,11 +335,13 @@ def _update_buffers_impl(self, env_ids: Sequence[int]):
force_matrix_w = self.contact_physx_view.get_contact_force_matrix(dt=self._sim_physics_dt)
force_matrix_w = force_matrix_w.view(-1, self._num_bodies, num_filters, 3)
self._data.force_matrix_w[env_ids] = force_matrix_w[env_ids]

# obtain the pose of the sensor origin
if self.cfg.track_pose:
pose = self.body_physx_view.get_transforms().view(-1, self._num_bodies, 7)[env_ids]
pose[..., 3:] = convert_quat(pose[..., 3:], to="wxyz")
self._data.pos_w[env_ids], self._data.quat_w[env_ids] = pose.split([3, 4], dim=-1)

# obtain the air time
if self.cfg.track_air_time:
# -- time elapsed since last update
Expand Down
Loading

0 comments on commit 0232e1c

Please sign in to comment.