Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions isaaclab_arena/assets/object_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(
self.prim_path = prim_path
self.object_type = object_type
self.initial_pose: Pose | PoseRange | None = None
self.initial_velocity: tuple[float, float, float] | None = None
self.object_cfg = None
self.event_cfg = None
self.relations: list[RelationBase] = []
Expand Down Expand Up @@ -80,6 +81,21 @@ def set_initial_pose(self, pose: Pose | PoseRange) -> None:
self.object_cfg.init_state.rot = initial_pose.rotation_wxyz
self.event_cfg = self._init_event_cfg()

def set_initial_velocity(self, linear_velocity: tuple[float, float, float]) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe set_initial_linear_velocity is better

"""Set / override the initial linear velocity and rebuild derived configs.

The velocity is applied as the ``init_state.lin_vel`` on the underlying
config (``RigidObjectCfg`` or ``ArticulationCfg``) and is also restored
on every environment reset via the reset event.

Args:
linear_velocity: Linear velocity ``(vx, vy, vz)`` in the world frame.
"""
self.initial_velocity = linear_velocity
if self.object_cfg is not None and hasattr(self.object_cfg.init_state, "lin_vel"):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these two conditions possible to be false?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because self.object_cfg can exist but not have "lin_vel" attribure (e.g. the walls). Only articulated and rigid objects have it

self.object_cfg.init_state.lin_vel = linear_velocity
self.event_cfg = self._init_event_cfg()

def _requires_reset_pose_event(self) -> bool:
"""Whether a reset-event for the initial pose should be generated.

Expand All @@ -91,7 +107,7 @@ def _requires_reset_pose_event(self) -> bool:
)

def _init_event_cfg(self) -> EventTermCfg | None:
"""Build the ``EventTermCfg`` for resetting this object's pose."""
"""Build the ``EventTermCfg`` for resetting this object's pose and velocity."""
if not self._requires_reset_pose_event():
return None

Expand All @@ -106,13 +122,16 @@ def _init_event_cfg(self) -> EventTermCfg | None:
},
)
else:
params: dict = {
"pose": initial_pose,
"asset_cfg": SceneEntityCfg(self.name),
}
if self.initial_velocity is not None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we anyway set the velocity to none. So we wont need this check. I see None is being handled in the event function

params["velocity"] = self.initial_velocity
return EventTermCfg(
func=set_object_pose,
mode="reset",
params={
"pose": initial_pose,
"asset_cfg": SceneEntityCfg(self.name),
},
params=params,
)

def get_relations(self) -> list[RelationBase]:
Expand Down
56 changes: 56 additions & 0 deletions isaaclab_arena/assets/object_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

if TYPE_CHECKING:
from isaaclab_arena.assets.hdr_image import HDRImage
from isaaclab.assets import RigidObjectCfg
from isaaclab.sim.spawners.from_files.from_files_cfg import GroundPlaneCfg
from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR, ISAACLAB_NUCLEUS_DIR

Expand Down Expand Up @@ -419,6 +420,61 @@ def __init__(
super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose)


@register_asset
class Sphere(LibraryObject):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!!

"""
A sphere with rigid body physics (dynamic by default).
"""

name = "sphere"
tags = ["object"]
object_type = ObjectType.SPAWNER
scale = (1.0, 1.0, 1.0)
default_spawner_cfg = sim_utils.SphereCfg(
radius=0.1,
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.8, 0.2, 0.2)),
collision_props=sim_utils.CollisionPropertiesCfg(),
rigid_props=sim_utils.RigidBodyPropertiesCfg(
solver_position_iteration_count=16,
solver_velocity_iteration_count=1,
max_angular_velocity=1000.0,
max_linear_velocity=1000.0,
max_depenetration_velocity=5.0,
disable_gravity=False,
),
mass_props=sim_utils.MassPropertiesCfg(mass=0.25),
)
Comment on lines +437 to +446
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some reason we need to change these RigidBodyPropertiesCfg. Could we leave them at the default values?


def __init__(
self,
instance_name: str | None = None,
prim_path: str | None = None,
initial_pose: Pose | None = None,
scale: tuple[float, float, float] | None = None,
spawner_cfg: sim_utils.SphereCfg = default_spawner_cfg,
):
self.spawner_cfg = spawner_cfg
super().__init__(
instance_name=instance_name,
prim_path=prim_path,
initial_pose=initial_pose,
scale=scale,
)

def _generate_spawner_cfg(self) -> RigidObjectCfg:
object_cfg = RigidObjectCfg(
prim_path=self.prim_path,
spawn=self.spawner_cfg,
)
object_cfg = self._add_initial_pose_to_cfg(object_cfg)
if self.initial_velocity is not None:
object_cfg.init_state.lin_vel = self.initial_velocity
return object_cfg

def _requires_reset_pose_event(self) -> bool:
return self.get_initial_pose() is not None and self.reset_pose
Comment on lines +464 to +475
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit messy. We don't want to define these functions per object in the library.

The problem you're trying to get around here is that the spawner object type only supports AssetBaseCfg and not RigidObjectCfg.

I think we need to solve this at a level higher in the heirachy though. Solving this per-specific library object is going to lead to a lot of duplication in the future.

I think we need to separate "does something provide a custom spawner?" from "what type of object is this?". Right now they are coupled together through ObjectType.



@register_asset
class DomeLight(LibraryObject):
"""A dome light, optionally textured with an HDR image environment map.
Expand Down
8 changes: 7 additions & 1 deletion isaaclab_arena/terms/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def set_object_pose(
env_ids: torch.Tensor,
asset_cfg: SceneEntityCfg,
pose: Pose,
velocity: tuple[float, float, float] | None = None,
) -> None:
if env_ids is None:
return
Expand All @@ -27,7 +28,12 @@ def set_object_pose(
pose_t_xyz_q_wxyz[:, :3] += env.scene.env_origins[env_ids]
# Set the pose and velocity
asset.write_root_pose_to_sim(pose_t_xyz_q_wxyz, env_ids=env_ids)
asset.write_root_velocity_to_sim(torch.zeros(1, 6, device=env.device), env_ids=env_ids)
if velocity is not None:
vel = torch.zeros(num_envs, 6, device=env.device)
vel[:, :3] = torch.tensor(velocity, device=env.device)
asset.write_root_velocity_to_sim(vel, env_ids=env_ids)
else:
asset.write_root_velocity_to_sim(torch.zeros(1, 6, device=env.device), env_ids=env_ids)


def set_object_pose_per_env(
Expand Down
2 changes: 1 addition & 1 deletion isaaclab_arena/tests/test_detect_object_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def _test_detect_object_type_for_all_objects(simulation_app):
# the simple RIGID/ARTICULATION classification:
# - For example, the "peg" and "hole" assets have both RigidBodyAPI and ArticulationRootAPI
# applied simultaneously, sometimes in different prim layers.
if object_asset.name not in ("hole", "peg", "small_gear", "medium_gear", "large_gear", "gear_base"):
if object_asset.name not in ("hole", "peg", "small_gear", "medium_gear", "large_gear", "gear_base", "sphere"):
print(f"Automatically classifying: {object_asset.name}")
detected_object_type = detect_object_type(usd_path=object_asset.usd_path)
print(f"database object type: {object_asset.object_type}")
Expand Down
Loading