Unverified Commit 13327b8a authored by Mayank Mittal's avatar Mayank Mittal Committed by GitHub

Simplifies the Articulation initialization by adding some other hacks (#243)

# Description

Earlier we were copying the whole `ArticulationView.initialize()` method
from Isaac Sim since it doesn't work with our initialization callback
hooks. Since this was bulking up the code and requires us to keep
duplicating their function, this MR replaces the current fix with some
tricks that work in a less bulky way.

Additionally, the MR fixes the property name `default_root_state_w` to
`default_root_state` since the latter is more correct (environment
origin instead of world origin).

## Type of change

- Bug fix (non-breaking change which fixes an issue)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./orbit.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
- [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
parent 39a3f8f9
[package]
# Note: Semantic Versioning is used: https://semver.org/
version = "0.9.39"
version = "0.9.40"
# Description
title = "ORBIT framework for Robot Learning"
......
Changelog
---------
0.9.40 (2023-11-09)
~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Simplified the manual initialization of Isaac Sim :class:`ArticulationView` class. Earlier, we basically
copied the code from the Isaac Sim source code. Now, we just call their initialize method.
Changed
^^^^^^^
* Changed the name of attribute :attr:`default_root_state_w` to :attr:`default_root_state`. The latter is
more correct since the data is actually in the local environment frame and not the simulation world frame.
0.9.39 (2023-11-08)
~~~~~~~~~~~~~~~~~~~
......
......@@ -12,7 +12,6 @@ import torch
from typing import TYPE_CHECKING, Sequence
import carb
import omni.physics.tensors
import omni.physics.tensors.impl.api as physx
from omni.isaac.core.articulations import ArticulationView
from omni.isaac.core.prims import RigidPrimView
......@@ -364,35 +363,18 @@ class Articulation(RigidObject):
# -- articulation
self._root_view = ArticulationView(self.cfg.prim_path, reset_xform_properties=False)
# Hacking the initialization of the articulation view.
# we cannot do the following operation and need to manually handle it because of Isaac Sim's implementation.
# self._root_view.initialize()
# reason: The default initialization of the articulation view is not working properly as it tries to create
# default actions that is not possible within the post-play callback.
physics_sim_view = omni.physics.tensors.create_simulation_view(self._root_view._backend)
physics_sim_view.set_subspace_roots("/")
# pyright: ignore [reportPrivateUsage]
self._root_view._physics_sim_view = physics_sim_view
self._root_view._physics_view = physics_sim_view.create_articulation_view(
self._root_view._regex_prim_paths.replace(".*", "*"), self._root_view._enable_dof_force_sensors
)
assert self._root_view._physics_view.is_homogeneous, "Root view's physics view is not homogeneous!"
if not self._root_view._is_initialized:
self._root_view._metadata = self._root_view._physics_view.shared_metatype
self._root_view._num_dof = self._root_view._physics_view.max_dofs
self._root_view._num_bodies = self._root_view._physics_view.max_links
self._root_view._num_shapes = self._root_view._physics_view.max_shapes
self._root_view._num_fixed_tendons = self._root_view._physics_view.max_fixed_tendons
self._root_view._body_names = self._root_view._metadata.link_names
self._root_view._body_indices = dict(
zip(self._root_view._body_names, range(len(self._root_view._body_names)))
)
self._root_view._dof_names = self._root_view._metadata.dof_names
self._root_view._dof_indices = self._root_view._metadata.dof_indices
self._root_view._dof_types = self._root_view._metadata.dof_types
self._root_view._dof_paths = self._root_view._physics_view.dof_paths
self._root_view._prim_paths = self._root_view._physics_view.prim_paths
carb.log_info(f"Articulation Prim View Device: {self._root_view._device}")
self._root_view._is_initialized = True
# We override their internal function that throws an error which is not desired or needed.
dummy_tensor = torch.empty(size=(0, 0), device=self.device)
dummy_joint_actions = ArticulationActions(dummy_tensor, dummy_tensor, dummy_tensor)
current_fn = self._root_view.get_applied_actions
self._root_view.get_applied_actions = lambda *args, **kwargs: dummy_joint_actions
# initialize the root view
self._root_view.initialize()
# restore the function
self._root_view.get_applied_actions = current_fn
# -- link views
# note: we use the root view to get the body names, but we use the body view to get the
# actual data. This is mainly needed to apply external forces to the bodies.
......
......@@ -295,7 +295,7 @@ class RigidObject(AssetBase):
self._data.body_names = self.body_names
# -- root states
self._data.root_state_w = torch.zeros(self.root_view.count, 13, device=self.device)
self._data.default_root_state_w = torch.zeros_like(self._data.root_state_w)
self._data.default_root_state = torch.zeros_like(self._data.root_state_w)
# -- body states
self._data.body_state_w = torch.zeros(self.root_view.count, self.num_bodies, 13, device=self.device)
# -- post-computed
......@@ -320,7 +320,7 @@ class RigidObject(AssetBase):
+ tuple(self.cfg.init_state.ang_vel)
)
default_root_state = torch.tensor(default_root_state, dtype=torch.float, device=self.device)
self._data.default_root_state_w = default_root_state.repeat(self.root_view.count, 1)
self._data.default_root_state = default_root_state.repeat(self.root_view.count, 1)
def _update_common_data(self, dt: float):
"""Update common quantities related to rigid objects.
......
......@@ -24,8 +24,8 @@ class RigidObjectData:
# Default states.
##
default_root_state_w: torch.Tensor = None
"""Default root state ``[pos, quat, lin_vel, ang_vel]`` in simulation world frame. Shape is ``(count, 13)``."""
default_root_state: torch.Tensor = None
"""Default root state ``[pos, quat, lin_vel, ang_vel]`` in local environment frame. Shape is ``(count, 13)``."""
##
# Frame states.
......
......@@ -85,7 +85,7 @@ class TerrainBasedPositionCommandGenerator(CommandGeneratorBase):
# TODO: need to add that here directly
self.pos_command_w[env_ids] = self.terrain.sample_new_targets(env_ids)
# offset the position command by the current root position
self.pos_command_w[env_ids, 2] += self.robot.data.default_root_state_w[env_ids, 2]
self.pos_command_w[env_ids, 2] += self.robot.data.default_root_state[env_ids, 2]
if self.cfg.simple_heading:
# set heading command to point towards target
......
......@@ -192,7 +192,7 @@ def reset_root_state(
# extract the used quantities (to enable type-hinting)
asset: RigidObject | Articulation = env.scene[asset_cfg.name]
# get default root state
root_states = asset.data.default_root_state_w[env_ids].clone()
root_states = asset.data.default_root_state[env_ids].clone()
# positions
pos_offset = torch.zeros_like(root_states[:, 0:3])
......@@ -250,7 +250,7 @@ def reset_scene_to_default(env: BaseEnv, env_ids: torch.Tensor):
# root states
for rigid_object in env.scene.rigid_objects.values() + env.scene.articulations.values():
# obtain default and deal with the offset for env origins
default_root_state = rigid_object.data.default_root_state_w[env_ids].clone()
default_root_state = rigid_object.data.default_root_state[env_ids].clone()
default_root_state[:, 0:3] += env.scene.env_origins[env_ids]
# set into the physics simulation
rigid_object.write_root_state_to_sim(default_root_state, env_ids=env_ids)
......
......@@ -97,7 +97,7 @@ def main():
sim_time = 0.0
count = 0
# reset root state
root_state = robot.data.default_root_state_w.clone()
root_state = robot.data.default_root_state.clone()
root_state[0, :2] = torch.tensor([0.0, -0.5], device=sim.device)
root_state[1, :2] = torch.tensor([0.0, 0.5], device=sim.device)
robot.write_root_state_to_sim(root_state)
......
......@@ -129,7 +129,7 @@ class TestArticulation(unittest.TestCase):
# Now we are ready!
for _ in range(5):
# reset root state
root_state = robot.data.default_root_state_w.clone()
root_state = robot.data.default_root_state.clone()
root_state[0, :2] = torch.tensor([0.0, -0.5], device=self.sim.device)
root_state[1, :2] = torch.tensor([0.0, 0.5], device=self.sim.device)
robot.write_root_state_to_sim(root_state)
......@@ -176,7 +176,7 @@ class TestArticulation(unittest.TestCase):
# Now we are ready!
for _ in range(5):
# reset root state
root_state = robot.data.default_root_state_w.clone()
root_state = robot.data.default_root_state.clone()
root_state[0, :2] = torch.tensor([0.0, -0.5], device=self.sim.device)
root_state[1, :2] = torch.tensor([0.0, 0.5], device=self.sim.device)
robot.write_root_state_to_sim(root_state)
......
......@@ -126,7 +126,7 @@ def main():
sim_time = 0.0
count = 0
# reset root state
root_state = scene.articulations["robot_1"].data.default_root_state_w.clone()
root_state = scene.articulations["robot_1"].data.default_root_state.clone()
root_state[:, :3] += scene.env_origins
joint_pos = scene.articulations["robot_1"].data.default_joint_pos
joint_vel = scene.articulations["robot_1"].data.default_joint_vel
......
......@@ -204,7 +204,7 @@ def main():
sim_time = 0.0
count = 0
# reset root state
root_state = scene.articulations["robot"].data.default_root_state_w.clone()
root_state = scene.articulations["robot"].data.default_root_state.clone()
root_state[:, :3] += scene.env_origins
joint_pos = scene.articulations["robot"].data.default_joint_pos
joint_vel = scene.articulations["robot"].data.default_joint_vel
......
......@@ -119,7 +119,7 @@ def main():
sim_time = 0.0
count = 0
# reset root state
root_state = scene.articulations["robot_1"].data.default_root_state_w.clone()
root_state = scene.articulations["robot_1"].data.default_root_state.clone()
root_state[:, :3] += scene.env_origins
joint_pos = scene.articulations["robot_1"].data.default_joint_pos
joint_vel = scene.articulations["robot_1"].data.default_joint_vel
......
......@@ -95,7 +95,7 @@ def main():
sim_time = 0.0
count = 0
# reset root state
root_state = rigid_object.data.default_root_state_w.clone()
root_state = rigid_object.data.default_root_state.clone()
# -- position
root_state[:, :3] = sample_cylinder(
radius=0.5, h_range=(0.15, 0.25), size=rigid_object.root_view.count, device=rigid_object.device
......
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