Commit 30d03e07 authored by Mayank Mittal's avatar Mayank Mittal Committed by Kelly Guo

Fixes interval event resets and deprecation of `attach_yaw_only` flag (#2958)

Just a friendly cleanup. Noticed some issues that crept up in some
previous MR. Still digging through some of the other MRs and
understanding why certain things changed.

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

- [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
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] 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

---------
Signed-off-by: 's avatarMayank Mittal <12863862+Mayankm96@users.noreply.github.com>
Co-authored-by: 's avatarKelly Guo <kellyg@nvidia.com>
Co-authored-by: 's avatarKelly Guo <kellyguo123@hotmail.com>
Co-authored-by: 's avatarooctipus <zhengyuz@nvidia.com>
parent a1bf2c82
...@@ -101,7 +101,7 @@ For this tutorial, the ray-cast based height scanner is attached to the base fra ...@@ -101,7 +101,7 @@ For this tutorial, the ray-cast based height scanner is attached to the base fra
The pattern of rays is specified using the :attr:`~sensors.RayCasterCfg.pattern` attribute. For The pattern of rays is specified using the :attr:`~sensors.RayCasterCfg.pattern` attribute. For
a uniform grid pattern, we specify the pattern using :class:`~sensors.patterns.GridPatternCfg`. a uniform grid pattern, we specify the pattern using :class:`~sensors.patterns.GridPatternCfg`.
Since we only care about the height information, we do not need to consider the roll and pitch Since we only care about the height information, we do not need to consider the roll and pitch
of the robot. Hence, we set the :attr:`~sensors.RayCasterCfg.attach_yaw_only` to true. of the robot. Hence, we set the :attr:`~sensors.RayCasterCfg.ray_alignment` to "yaw".
For the height-scanner, you can visualize the points where the rays hit the mesh. This is done For the height-scanner, you can visualize the points where the rays hit the mesh. This is done
by setting the :attr:`~sensors.SensorBaseCfg.debug_vis` attribute to true. by setting the :attr:`~sensors.SensorBaseCfg.debug_vis` attribute to true.
......
...@@ -63,7 +63,7 @@ class RaycasterSensorSceneCfg(InteractiveSceneCfg): ...@@ -63,7 +63,7 @@ class RaycasterSensorSceneCfg(InteractiveSceneCfg):
update_period=1 / 60, update_period=1 / 60,
offset=RayCasterCfg.OffsetCfg(pos=(0, 0, 0.5)), offset=RayCasterCfg.OffsetCfg(pos=(0, 0, 0.5)),
mesh_prim_paths=["/World/Ground"], mesh_prim_paths=["/World/Ground"],
attach_yaw_only=True, ray_alignment="yaw",
pattern_cfg=patterns.LidarPatternCfg( pattern_cfg=patterns.LidarPatternCfg(
channels=100, vertical_fov_range=[-90, 90], horizontal_fov_range=[-90, 90], horizontal_res=1.0 channels=100, vertical_fov_range=[-90, 90], horizontal_fov_range=[-90, 90], horizontal_res=1.0
), ),
......
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.44.7" version = "0.44.8"
# Description # Description
title = "Isaac Lab framework for Robot Learning" title = "Isaac Lab framework for Robot Learning"
......
This diff is collapsed.
...@@ -39,9 +39,15 @@ class ArticulationCfg(AssetBaseCfg): ...@@ -39,9 +39,15 @@ class ArticulationCfg(AssetBaseCfg):
class_type: type = Articulation class_type: type = Articulation
articulation_root_prim_path: str | None = None articulation_root_prim_path: str | None = None
"""Path to the articulation root prim in the USD file. """Path to the articulation root prim under the :attr:`prim_path`. Defaults to None, in which case the class
will search for a prim with the USD ArticulationRootAPI on it.
If not provided will search for a prim with the ArticulationRootAPI. Should start with a slash. This path should be relative to the :attr:`prim_path` of the asset. If the asset is loaded from a USD file,
this path should be relative to the root of the USD stage. For instance, if the loaded USD file at :attr:`prim_path`
contains two articulations, one at `/robot1` and another at `/robot2`, and you want to use `robot2`,
then you should set this to `/robot2`.
The path must start with a slash (`/`).
""" """
init_state: InitialStateCfg = InitialStateCfg() init_state: InitialStateCfg = InitialStateCfg()
......
...@@ -1146,8 +1146,14 @@ def reset_nodal_state_uniform( ...@@ -1146,8 +1146,14 @@ def reset_nodal_state_uniform(
asset.write_nodal_state_to_sim(nodal_state, env_ids=env_ids) asset.write_nodal_state_to_sim(nodal_state, env_ids=env_ids)
def reset_scene_to_default(env: ManagerBasedEnv, env_ids: torch.Tensor): def reset_scene_to_default(env: ManagerBasedEnv, env_ids: torch.Tensor, reset_joint_targets: bool = False):
"""Reset the scene to the default state specified in the scene configuration.""" """Reset the scene to the default state specified in the scene configuration.
If :attr:`reset_joint_targets` is True, the joint position and velocity targets of the articulations are
also reset to their default values. This might be useful for some cases to clear out any previously set targets.
However, this is not the default behavior as based on our experience, it is not always desired to reset
targets to default values, especially when the targets should be handled by action terms and not event terms.
"""
# rigid bodies # rigid bodies
for rigid_object in env.scene.rigid_objects.values(): for rigid_object in env.scene.rigid_objects.values():
# obtain default and deal with the offset for env origins # obtain default and deal with the offset for env origins
...@@ -1168,9 +1174,11 @@ def reset_scene_to_default(env: ManagerBasedEnv, env_ids: torch.Tensor): ...@@ -1168,9 +1174,11 @@ def reset_scene_to_default(env: ManagerBasedEnv, env_ids: torch.Tensor):
default_joint_pos = articulation_asset.data.default_joint_pos[env_ids].clone() default_joint_pos = articulation_asset.data.default_joint_pos[env_ids].clone()
default_joint_vel = articulation_asset.data.default_joint_vel[env_ids].clone() default_joint_vel = articulation_asset.data.default_joint_vel[env_ids].clone()
# set into the physics simulation # set into the physics simulation
articulation_asset.write_joint_state_to_sim(default_joint_pos, default_joint_vel, env_ids=env_ids)
# reset joint targets if required
if reset_joint_targets:
articulation_asset.set_joint_position_target(default_joint_pos, env_ids=env_ids) articulation_asset.set_joint_position_target(default_joint_pos, env_ids=env_ids)
articulation_asset.set_joint_velocity_target(default_joint_vel, env_ids=env_ids) articulation_asset.set_joint_velocity_target(default_joint_vel, env_ids=env_ids)
articulation_asset.write_joint_state_to_sim(default_joint_pos, default_joint_vel, env_ids=env_ids)
# deformable objects # deformable objects
for deformable_object in env.scene.deformable_objects.values(): for deformable_object in env.scene.deformable_objects.values():
# obtain default and set into the physics simulation # obtain default and set into the physics simulation
......
...@@ -114,12 +114,14 @@ def body_pose_w( ...@@ -114,12 +114,14 @@ def body_pose_w(
asset_cfg: The SceneEntity associated with this observation. asset_cfg: The SceneEntity associated with this observation.
Returns: Returns:
The poses of bodies in articulation [num_env, 7*num_bodies]. Pose order is [x,y,z,qw,qx,qy,qz]. Output is The poses of bodies in articulation [num_env, 7 * num_bodies]. Pose order is [x,y,z,qw,qx,qy,qz].
stacked horizontally per body. Output is stacked horizontally per body.
""" """
# extract the used quantities (to enable type-hinting) # extract the used quantities (to enable type-hinting)
asset: Articulation = env.scene[asset_cfg.name] asset: Articulation = env.scene[asset_cfg.name]
pose = asset.data.body_state_w[:, asset_cfg.body_ids, :7]
# access the body poses in world frame
pose = asset.data.body_pose_w[:, asset_cfg.body_ids, :7]
pose[..., :3] = pose[..., :3] - env.scene.env_origins.unsqueeze(1) pose[..., :3] = pose[..., :3] - env.scene.env_origins.unsqueeze(1)
return pose.reshape(env.num_envs, -1) return pose.reshape(env.num_envs, -1)
......
...@@ -135,7 +135,7 @@ class EventManager(ManagerBase): ...@@ -135,7 +135,7 @@ class EventManager(ManagerBase):
# when the episode starts. otherwise the counter will start from the last time # when the episode starts. otherwise the counter will start from the last time
# for that environment # for that environment
if "interval" in self._mode_term_cfgs: if "interval" in self._mode_term_cfgs:
for index, term_cfg in enumerate(self._mode_class_term_cfgs["interval"]): for index, term_cfg in enumerate(self._mode_term_cfgs["interval"]):
# sample a new interval and set that as time left # sample a new interval and set that as time left
# note: global time events are based on simulation time and not episode time # note: global time events are based on simulation time and not episode time
# so we do not reset them # so we do not reset them
......
...@@ -19,6 +19,7 @@ from isaacsim.core.simulation_manager import SimulationManager ...@@ -19,6 +19,7 @@ from isaacsim.core.simulation_manager import SimulationManager
from pxr import UsdGeom, UsdPhysics from pxr import UsdGeom, UsdPhysics
import isaaclab.sim as sim_utils import isaaclab.sim as sim_utils
import isaaclab.utils.math as math_utils
from isaaclab.markers import VisualizationMarkers from isaaclab.markers import VisualizationMarkers
from isaaclab.terrains.trimesh.utils import make_plane from isaaclab.terrains.trimesh.utils import make_plane
from isaaclab.utils.math import convert_quat, quat_apply, quat_apply_yaw from isaaclab.utils.math import convert_quat, quat_apply, quat_apply_yaw
...@@ -117,10 +118,11 @@ class RayCaster(SensorBase): ...@@ -117,10 +118,11 @@ class RayCaster(SensorBase):
r = torch.empty(num_envs_ids, 3, device=self.device) r = torch.empty(num_envs_ids, 3, device=self.device)
self.drift[env_ids] = r.uniform_(*self.cfg.drift_range) self.drift[env_ids] = r.uniform_(*self.cfg.drift_range)
# resample the height drift # resample the height drift
r = torch.empty(num_envs_ids, device=self.device) range_list = [self.cfg.ray_cast_drift_range.get(key, (0.0, 0.0)) for key in ["x", "y", "z"]]
self.ray_cast_drift[env_ids, 0] = r.uniform_(*self.cfg.ray_cast_drift_range["x"]) ranges = torch.tensor(range_list, device=self.device)
self.ray_cast_drift[env_ids, 1] = r.uniform_(*self.cfg.ray_cast_drift_range["y"]) self.ray_cast_drift[env_ids] = math_utils.sample_uniform(
self.ray_cast_drift[env_ids, 2] = r.uniform_(*self.cfg.ray_cast_drift_range["z"]) ranges[:, 0], ranges[:, 1], (num_envs_ids, 3), device=self.device
)
""" """
Implementation. Implementation.
...@@ -249,6 +251,21 @@ class RayCaster(SensorBase): ...@@ -249,6 +251,21 @@ class RayCaster(SensorBase):
self._data.pos_w[env_ids] = pos_w self._data.pos_w[env_ids] = pos_w
self._data.quat_w[env_ids] = quat_w self._data.quat_w[env_ids] = quat_w
# check if user provided attach_yaw_only flag
if self.cfg.attach_yaw_only is not None:
msg = (
"Raycaster attribute 'attach_yaw_only' property will be deprecated in a future release."
" Please use the parameter 'ray_alignment' instead."
)
# set ray alignment to yaw
if self.cfg.attach_yaw_only:
self.cfg.ray_alignment = "yaw"
msg += " Setting ray_alignment to 'yaw'."
else:
self.cfg.ray_alignment = "base"
msg += " Setting ray_alignment to 'base'."
# log the warning
omni.log.warn(msg)
# ray cast based on the sensor poses # ray cast based on the sensor poses
if self.cfg.ray_alignment == "world": if self.cfg.ray_alignment == "world":
# apply horizontal drift to ray starting position in ray caster frame # apply horizontal drift to ray starting position in ray caster frame
...@@ -257,14 +274,7 @@ class RayCaster(SensorBase): ...@@ -257,14 +274,7 @@ class RayCaster(SensorBase):
ray_starts_w = self.ray_starts[env_ids] ray_starts_w = self.ray_starts[env_ids]
ray_starts_w += pos_w.unsqueeze(1) ray_starts_w += pos_w.unsqueeze(1)
ray_directions_w = self.ray_directions[env_ids] ray_directions_w = self.ray_directions[env_ids]
elif self.cfg.ray_alignment == "yaw" or self.cfg.attach_yaw_only: elif self.cfg.ray_alignment == "yaw":
if self.cfg.attach_yaw_only:
self.cfg.ray_alignment = "yaw"
omni.log.warn(
"The `attach_yaw_only` property will be deprecated in a future release. Please use"
" `ray_alignment='yaw'` instead."
)
# apply horizontal drift to ray starting position in ray caster frame # apply horizontal drift to ray starting position in ray caster frame
pos_w[:, 0:2] += quat_apply_yaw(quat_w, self.ray_cast_drift[env_ids])[:, 0:2] pos_w[:, 0:2] += quat_apply_yaw(quat_w, self.ray_cast_drift[env_ids])[:, 0:2]
# only yaw orientation is considered and directions are not rotated # only yaw orientation is considered and directions are not rotated
......
...@@ -44,22 +44,32 @@ class RayCasterCfg(SensorBaseCfg): ...@@ -44,22 +44,32 @@ class RayCasterCfg(SensorBaseCfg):
offset: OffsetCfg = OffsetCfg() offset: OffsetCfg = OffsetCfg()
"""The offset pose of the sensor's frame from the sensor's parent frame. Defaults to identity.""" """The offset pose of the sensor's frame from the sensor's parent frame. Defaults to identity."""
attach_yaw_only: bool = False attach_yaw_only: bool | None = None
"""Whether the rays' starting positions and directions only track the yaw orientation. """Whether the rays' starting positions and directions only track the yaw orientation.
Defaults to None, which doesn't raise a warning of deprecated usage.
This is useful for ray-casting height maps, where only yaw rotation is needed. This is useful for ray-casting height maps, where only yaw rotation is needed.
.. warning:: .. deprecated:: 2.1.1
This attribute is deprecated and will be removed in the future. Please use
:attr:`ray_alignment` instead.
To get the same behavior as setting this parameter to ``True`` or ``False``, set
:attr:`ray_alignment` to ``"yaw"`` or "base" respectively.
This attribute is deprecated. Use :attr:`~isaaclab.sensors.ray_caster.ray_caster_cfg.ray_alignment` instead.
To get the same behavior, set `ray_alignment` to `"yaw"`.
""" """
ray_alignment: Literal["base", "yaw", "world"] = "yaw" ray_alignment: Literal["base", "yaw", "world"] = "base"
"""Specify in what frame the rays are projected onto the ground. Default is `world`. """Specify in what frame the rays are projected onto the ground. Default is "base".
* `base` if the rays' starting positions and directions track the full root position and orientation.
* `yaw` if the rays' starting positions and directions track root position and only yaw component of orientation. This is useful for ray-casting height maps. The options are:
* `world` if rays' starting positions and directions are always fixed. This is useful in combination with the grid map package.
* ``base`` if the rays' starting positions and directions track the full root position and orientation.
* ``yaw`` if the rays' starting positions and directions track root position and only yaw component of orientation.
This is useful for ray-casting height maps.
* ``world`` if rays' starting positions and directions are always fixed. This is useful in combination with a mapping
package on the robot and querying ray-casts in a global frame.
""" """
pattern_cfg: PatternBaseCfg = MISSING pattern_cfg: PatternBaseCfg = MISSING
...@@ -75,7 +85,8 @@ class RayCasterCfg(SensorBaseCfg): ...@@ -75,7 +85,8 @@ class RayCasterCfg(SensorBaseCfg):
""" """
ray_cast_drift_range: dict[str, tuple[float, float]] = {"x": (0.0, 0.0), "y": (0.0, 0.0), "z": (0.0, 0.0)} ray_cast_drift_range: dict[str, tuple[float, float]] = {"x": (0.0, 0.0), "y": (0.0, 0.0), "z": (0.0, 0.0)}
"""The range of drift (in meters) to add to the projected ray points in local projection frame. Defaults to (0.0, 0.0) for x, y, and z drift. """The range of drift (in meters) to add to the projected ray points in local projection frame. Defaults to
a dictionary with zero drift for each x, y and z axis.
For floating base robots, this is useful for simulating drift in the robot's pose estimation. For floating base robots, this is useful for simulating drift in the robot's pose estimation.
""" """
......
...@@ -138,7 +138,7 @@ class AnymalCRoughEnvCfg(AnymalCFlatEnvCfg): ...@@ -138,7 +138,7 @@ class AnymalCRoughEnvCfg(AnymalCFlatEnvCfg):
height_scanner = RayCasterCfg( height_scanner = RayCasterCfg(
prim_path="/World/envs/env_.*/Robot/base", prim_path="/World/envs/env_.*/Robot/base",
offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)), offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)),
attach_yaw_only=True, ray_alignment="yaw",
pattern_cfg=patterns.GridPatternCfg(resolution=0.1, size=[1.6, 1.0]), pattern_cfg=patterns.GridPatternCfg(resolution=0.1, size=[1.6, 1.0]),
debug_vis=False, debug_vis=False,
mesh_prim_paths=["/World/ground"], mesh_prim_paths=["/World/ground"],
......
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