Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
fan-ziqi committed Dec 16, 2024
2 parents 4642888 + b6a7729 commit 503bd1d
Show file tree
Hide file tree
Showing 35 changed files with 2,274 additions and 91 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ repos:
- id: pyupgrade
args: ["--py310-plus"]
# FIXME: This is a hack because Pytorch does not like: torch.Tensor | dict aliasing
exclude: "source/extensions/omni.isaac.lab/omni/isaac/lab/envs/common.py"
exclude: "source/extensions/omni.isaac.lab/omni/isaac/lab/envs/common.py|source/extensions/omni.isaac.lab/omni/isaac/lab/ui/widgets/image_plot.py"
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
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.27.26"
version = "0.29.1"

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

0.29.1 (2024-12-15)
~~~~~~~~~~~~~~~~~~~

Changed
^^^^^^^

* Added call to update articulation kinematics after reset to ensure states are updated for non-rendering sensors. Previously, some changes in reset such as modifying joint states would not be reflected in the rigid body states immediately after reset.


0.29.0 (2024-12-15)
~~~~~~~~~~~~~~~~~~~

Added
^^^^^

* Added UI interface to the Managers in the ManagerBasedEnv and MangerBasedRLEnv classes.
* Added UI widgets for :class:`LiveLinePlot` and :class:`ImagePlot`.
* Added ``ManagerLiveVisualizer/Cfg``: Given a ManagerBase (i.e. action_manager, observation_manager, etc) and a config file this class creates the the interface between managers and the UI.
* Added :class:`EnvLiveVisualizer`: A 'manager' of ManagerLiveVisualizer. This is added to the ManagerBasedEnv but is only called during the initialization of the managers in load_managers
* Added ``get_active_iterable_terms`` implementation methods to ActionManager, ObservationManager, CommandsManager, CurriculumManager, RewardManager, and TerminationManager. This method exports the active term data and labels for each manager and is called by ManagerLiveVisualizer.
* Additions to :class:`BaseEnvWindow` and :class:`RLEnvWindow` to register ManagerLiveVisualizer UI interfaces for the chosen managers.


0.28.0 (2024-12-15)
~~~~~~~~~~~~~~~~~~~

Added
^^^^^

* Added observation history computation to :class:`omni.isaac.lab.manager.observation_manager.ObservationManager`.
* Added ``history_length`` and ``flatten_history_dim`` configuration parameters to :class:`omni.isaac.lab.manager.manager_term_cfg.ObservationTermCfg`
* Added ``history_length`` and ``flatten_history_dim`` configuration parameters to :class:`omni.isaac.lab.manager.manager_term_cfg.ObservationGroupCfg`
* Added full buffer property to :class:`omni.isaac.lab.utils.buffers.circular_buffer.CircularBuffer`


0.27.29 (2024-12-15)
~~~~~~~~~~~~~~~~~~~~

Added
^^^^^

* Added action clip to all :class:`omni.isaac.lab.envs.mdp.actions`.


0.27.28 (2024-12-14)
~~~~~~~~~~~~~~~~~~~~

Changed
^^^^^^^

* Added check for error below threshold in state machines to ensure the state has been reached.


0.27.27 (2024-12-13)
~~~~~~~~~~~~~~~~~~~~

Fixed
^^^^^

* Fixed the shape of ``quat_w`` in the ``apply_actions`` method of :attr:`~omni.isaac.lab.env.mdp.NonHolonomicAction` (previously (N,B,4), now (N,4) since the number of root bodies B is required to be 1). Previously ``apply_actions`` errored because ``euler_xyz_from_quat`` requires inputs of shape (N,4).


0.27.26 (2024-12-11)
~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -54,7 +116,7 @@ Changed


0.27.21 (2024-12-06)
~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~

Fixed
^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ def reset(self, seed: int | None = None, options: dict[str, Any] | None = None)
indices = torch.arange(self.num_envs, dtype=torch.int64, device=self.device)
self._reset_idx(indices)

# update articulation kinematics
self.scene.write_data_to_sim()
self.sim.forward()

# if sensors are added to the scene, make sure we render to reflect changes in reset
if self.sim.has_rtx_sensors() and self.cfg.rerender_on_reset:
self.sim.render()
Expand Down Expand Up @@ -346,6 +350,9 @@ def step(self, action: torch.Tensor) -> VecEnvStepReturn:
reset_env_ids = self.reset_buf.nonzero(as_tuple=False).squeeze(-1)
if len(reset_env_ids) > 0:
self._reset_idx(reset_env_ids)
# update articulation kinematics
self.scene.write_data_to_sim()
self.sim.forward()
# if sensors are added to the scene, make sure we render to reflect changes in reset
if self.sim.has_rtx_sensors() and self.cfg.rerender_on_reset:
self.sim.render()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from omni.isaac.lab.managers import ActionManager, EventManager, ObservationManager, RecorderManager
from omni.isaac.lab.scene import InteractiveScene
from omni.isaac.lab.sim import SimulationContext
from omni.isaac.lab.ui.widgets import ManagerLiveVisualizer
from omni.isaac.lab.utils.timer import Timer

from .common import VecEnvObs
Expand Down Expand Up @@ -148,6 +149,8 @@ def __init__(self, cfg: ManagerBasedEnvCfg):
# we need to do this here after all the managers are initialized
# this is because they dictate the sensors and commands right now
if self.sim.has_gui() and self.cfg.ui_window_class_type is not None:
# setup live visualizers
self.setup_manager_visualizers()
self._window = self.cfg.ui_window_class_type(self, window_name="IsaacLab")
else:
# if no window, then we don't need to store the window
Expand Down Expand Up @@ -233,6 +236,14 @@ def load_managers(self):
if self.__class__ == ManagerBasedEnv and "startup" in self.event_manager.available_modes:
self.event_manager.apply(mode="startup")

def setup_manager_visualizers(self):
"""Creates live visualizers for manager terms."""

self.manager_visualizers = {
"action_manager": ManagerLiveVisualizer(manager=self.action_manager),
"observation_manager": ManagerLiveVisualizer(manager=self.observation_manager),
}

"""
Operations - MDP.
"""
Expand Down Expand Up @@ -269,15 +280,17 @@ def reset(

# reset state of scene
self._reset_idx(env_ids)
self.scene.write_data_to_sim()

# trigger recorder terms for post-reset calls
self.recorder_manager.record_post_reset(env_ids)

# update articulation kinematics
self.scene.write_data_to_sim()
self.sim.forward()
# if sensors are added to the scene, make sure we render to reflect changes in reset
if self.sim.has_rtx_sensors() and self.cfg.rerender_on_reset:
self.sim.render()

# trigger recorder terms for post-reset calls
self.recorder_manager.record_post_reset(env_ids)

# compute observations
self.obs_buf = self.observation_manager.compute()

Expand Down Expand Up @@ -317,13 +330,16 @@ def reset_to(
# set the state
self.scene.reset_to(state, env_ids, is_relative=is_relative)

# trigger recorder terms for post-reset calls
self.recorder_manager.record_post_reset(env_ids)
# update articulation kinematics
self.sim.forward()

# if sensors are added to the scene, make sure we render to reflect changes in reset
if self.sim.has_rtx_sensors() and self.cfg.rerender_on_reset:
self.sim.render()

# trigger recorder terms for post-reset calls
self.recorder_manager.record_post_reset(env_ids)

# compute observations
self.obs_buf = self.observation_manager.compute()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from omni.isaac.version import get_version

from omni.isaac.lab.managers import CommandManager, CurriculumManager, RewardManager, TerminationManager
from omni.isaac.lab.ui.widgets import ManagerLiveVisualizer

from .common import VecEnvStepReturn
from .manager_based_env import ManagerBasedEnv
Expand Down Expand Up @@ -132,6 +133,18 @@ def load_managers(self):
if "startup" in self.event_manager.available_modes:
self.event_manager.apply(mode="startup")

def setup_manager_visualizers(self):
"""Creates live visualizers for manager terms."""

self.manager_visualizers = {
"action_manager": ManagerLiveVisualizer(manager=self.action_manager),
"observation_manager": ManagerLiveVisualizer(manager=self.observation_manager),
"command_manager": ManagerLiveVisualizer(manager=self.command_manager),
"termination_manager": ManagerLiveVisualizer(manager=self.termination_manager),
"reward_manager": ManagerLiveVisualizer(manager=self.reward_manager),
"curriculum_manager": ManagerLiveVisualizer(manager=self.curriculum_manager),
}

"""
Operations - MDP
"""
Expand Down Expand Up @@ -204,9 +217,9 @@ def step(self, action: torch.Tensor) -> VecEnvStepReturn:
self.recorder_manager.record_pre_reset(reset_env_ids)

self._reset_idx(reset_env_ids)

# this is needed to make joint positions set from reset events effective
# update articulation kinematics
self.scene.write_data_to_sim()
self.sim.forward()

# if sensors are added to the scene, make sure we render to reflect changes in reset
if self.sim.has_rtx_sensors() and self.cfg.rerender_on_reset:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ class BinaryJointAction(ActionTerm):

cfg: actions_cfg.BinaryJointActionCfg
"""The configuration of the action term."""

_asset: Articulation
"""The articulation asset on which the action term is applied."""
_clip: torch.Tensor
"""The clip applied to the input action."""

def __init__(self, cfg: actions_cfg.BinaryJointActionCfg, env: ManagerBasedEnv) -> None:
# initialize the action term
Expand Down Expand Up @@ -83,6 +84,17 @@ def __init__(self, cfg: actions_cfg.BinaryJointActionCfg, env: ManagerBasedEnv)
)
self._close_command[index_list] = torch.tensor(value_list, device=self.device)

# parse clip
if self.cfg.clip is not None:
if isinstance(cfg.clip, dict):
self._clip = torch.tensor([[-float("inf"), float("inf")]], device=self.device).repeat(
self.num_envs, self.action_dim, 1
)
index_list, _, value_list = string_utils.resolve_matching_names_values(self.cfg.clip, self._joint_names)
self._clip[:, index_list] = torch.tensor(value_list, device=self.device)
else:
raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.")

"""
Properties.
"""
Expand Down Expand Up @@ -115,6 +127,10 @@ def process_actions(self, actions: torch.Tensor):
binary_mask = actions < 0
# compute the command
self._processed_actions = torch.where(binary_mask, self._close_command, self._open_command)
if self.cfg.clip is not None:
self._processed_actions = torch.clamp(
self._processed_actions, min=self._clip[:, :, 0], max=self._clip[:, :, 1]
)

def reset(self, env_ids: Sequence[int] | None = None) -> None:
self._raw_actions[env_ids] = 0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class JointAction(ActionTerm):
"""The scaling factor applied to the input action."""
_offset: torch.Tensor | float
"""The offset applied to the input action."""
_clip: torch.Tensor
"""The clip applied to the input action."""

def __init__(self, cfg: actions_cfg.JointActionCfg, env: ManagerBasedEnv) -> None:
# initialize the action term
Expand Down Expand Up @@ -94,6 +96,16 @@ def __init__(self, cfg: actions_cfg.JointActionCfg, env: ManagerBasedEnv) -> Non
self._offset[:, index_list] = torch.tensor(value_list, device=self.device)
else:
raise ValueError(f"Unsupported offset type: {type(cfg.offset)}. Supported types are float and dict.")
# parse clip
if self.cfg.clip is not None:
if isinstance(cfg.clip, dict):
self._clip = torch.tensor([[-float("inf"), float("inf")]], device=self.device).repeat(
self.num_envs, self.action_dim, 1
)
index_list, _, value_list = string_utils.resolve_matching_names_values(self.cfg.clip, self._joint_names)
self._clip[:, index_list] = torch.tensor(value_list, device=self.device)
else:
raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.")

"""
Properties.
Expand All @@ -120,6 +132,11 @@ def process_actions(self, actions: torch.Tensor):
self._raw_actions[:] = actions
# apply the affine transformations
self._processed_actions = self._raw_actions * self._scale + self._offset
# clip actions
if self.cfg.clip is not None:
self._processed_actions = torch.clamp(
self._processed_actions, min=self._clip[:, :, 0], max=self._clip[:, :, 1]
)

def reset(self, env_ids: Sequence[int] | None = None) -> None:
self._raw_actions[env_ids] = 0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class JointPositionToLimitsAction(ActionTerm):
"""The articulation asset on which the action term is applied."""
_scale: torch.Tensor | float
"""The scaling factor applied to the input action."""
_clip: torch.Tensor
"""The clip applied to the input action."""

def __init__(self, cfg: actions_cfg.JointPositionToLimitsActionCfg, env: ManagerBasedEnv):
# initialize the action term
Expand Down Expand Up @@ -76,6 +78,16 @@ def __init__(self, cfg: actions_cfg.JointPositionToLimitsActionCfg, env: Manager
self._scale[:, index_list] = torch.tensor(value_list, device=self.device)
else:
raise ValueError(f"Unsupported scale type: {type(cfg.scale)}. Supported types are float and dict.")
# parse clip
if self.cfg.clip is not None:
if isinstance(cfg.clip, dict):
self._clip = torch.tensor([[-float("inf"), float("inf")]], device=self.device).repeat(
self.num_envs, self.action_dim, 1
)
index_list, _, value_list = string_utils.resolve_matching_names_values(self.cfg.clip, self._joint_names)
self._clip[:, index_list] = torch.tensor(value_list, device=self.device)
else:
raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.")

"""
Properties.
Expand All @@ -102,6 +114,10 @@ def process_actions(self, actions: torch.Tensor):
self._raw_actions[:] = actions
# apply affine transformations
self._processed_actions = self._raw_actions * self._scale
if self.cfg.clip is not None:
self._processed_actions = torch.clamp(
self._processed_actions, min=self._clip[:, :, 0], max=self._clip[:, :, 1]
)
# rescale the position targets if configured
# this is useful when the input actions are in the range [-1, 1]
if self.cfg.rescale_to_limits:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import omni.log

import omni.isaac.lab.utils.string as string_utils
from omni.isaac.lab.assets.articulation import Articulation
from omni.isaac.lab.managers.action_manager import ActionTerm
from omni.isaac.lab.utils.math import euler_xyz_from_quat
Expand Down Expand Up @@ -59,6 +60,8 @@ class NonHolonomicAction(ActionTerm):
"""The scaling factor applied to the input action. Shape is (1, 2)."""
_offset: torch.Tensor
"""The offset applied to the input action. Shape is (1, 2)."""
_clip: torch.Tensor
"""The clip applied to the input action."""

def __init__(self, cfg: actions_cfg.NonHolonomicActionCfg, env: ManagerBasedEnv):
# initialize the action term
Expand Down Expand Up @@ -104,6 +107,16 @@ def __init__(self, cfg: actions_cfg.NonHolonomicActionCfg, env: ManagerBasedEnv)
# save the scale and offset as tensors
self._scale = torch.tensor(self.cfg.scale, device=self.device).unsqueeze(0)
self._offset = torch.tensor(self.cfg.offset, device=self.device).unsqueeze(0)
# parse clip
if self.cfg.clip is not None:
if isinstance(cfg.clip, dict):
self._clip = torch.tensor([[-float("inf"), float("inf")]], device=self.device).repeat(
self.num_envs, self.action_dim, 1
)
index_list, _, value_list = string_utils.resolve_matching_names_values(self.cfg.clip, self._joint_names)
self._clip[:, index_list] = torch.tensor(value_list, device=self.device)
else:
raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.")

"""
Properties.
Expand All @@ -129,10 +142,15 @@ def process_actions(self, actions):
# store the raw actions
self._raw_actions[:] = actions
self._processed_actions = self.raw_actions * self._scale + self._offset
# clip actions
if self.cfg.clip is not None:
self._processed_actions = torch.clamp(
self._processed_actions, min=self._clip[:, :, 0], max=self._clip[:, :, 1]
)

def apply_actions(self):
# obtain current heading
quat_w = self._asset.data.body_quat_w[:, self._body_idx]
quat_w = self._asset.data.body_quat_w[:, self._body_idx].view(self.num_envs, 4)
yaw_w = euler_xyz_from_quat(quat_w)[2]
# compute joint velocities targets
self._joint_vel_command[:, 0] = torch.cos(yaw_w) * self.processed_actions[:, 0] # x
Expand Down
Loading

0 comments on commit 503bd1d

Please sign in to comment.