Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Place Feature to Lift State Machine #1334

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,4 @@ def __post_init__(self):
self.sim.physx.bounce_threshold_velocity = 0.01
self.sim.physx.gpu_found_lost_aggregate_pairs_capacity = 1024 * 1024 * 4
self.sim.physx.gpu_total_aggregate_pairs_capacity = 16 * 1024
self.sim.physx.friction_correlation_distance = 0.00625
self.sim.physx.friction_correlation_distance = 0.00625
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
# Copyright (c) 2022-2024, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

from dataclasses import MISSING

import torch
import omni.isaac.lab.sim as sim_utils
from omni.isaac.lab.assets import ArticulationCfg, AssetBaseCfg, RigidObjectCfg
from omni.isaac.lab.envs import ManagerBasedRLEnv
from omni.isaac.lab.envs import ManagerBasedRLEnvCfg
from omni.isaac.lab.managers import CurriculumTermCfg as CurrTerm
from omni.isaac.lab.managers import EventTermCfg as EventTerm
from omni.isaac.lab.managers import ObservationGroupCfg as ObsGroup
from omni.isaac.lab.managers import ObservationTermCfg as ObsTerm
from omni.isaac.lab.managers import RewardTermCfg as RewTerm
from omni.isaac.lab.managers import SceneEntityCfg
from omni.isaac.lab.managers import TerminationTermCfg as DoneTerm
from omni.isaac.lab.scene import InteractiveSceneCfg
from omni.isaac.lab.sensors.frame_transformer.frame_transformer_cfg import FrameTransformerCfg
from omni.isaac.lab.sim.spawners.from_files.from_files_cfg import GroundPlaneCfg, UsdFileCfg
from omni.isaac.lab.utils import configclass
from omni.isaac.lab.utils.assets import ISAAC_NUCLEUS_DIR

from . import mdp

##
# Scene definition
##


@configclass
class ObjectTableSceneCfg(InteractiveSceneCfg):
"""Configuration for the lift scene with a robot and a object.
This is the abstract base implementation, the exact scene is defined in the derived classes
which need to set the target object, robot and end-effector frames
"""

# robots: will be populated by agent env cfg
robot: ArticulationCfg = MISSING
# end-effector sensor: will be populated by agent env cfg
ee_frame: FrameTransformerCfg = MISSING
# target object: will be populated by agent env cfg
object: RigidObjectCfg = MISSING

# Table
table = AssetBaseCfg(
prim_path="{ENV_REGEX_NS}/Table",
init_state=AssetBaseCfg.InitialStateCfg(pos=[0.5, 0, 0], rot=[0.707, 0, 0, 0.707]),
spawn=UsdFileCfg(usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/Mounts/SeattleLabTable/table_instanceable.usd"),
)

# plane
plane = AssetBaseCfg(
prim_path="/World/GroundPlane",
init_state=AssetBaseCfg.InitialStateCfg(pos=[0, 0, -1.05]),
spawn=GroundPlaneCfg(),
)

# lights
light = AssetBaseCfg(
prim_path="/World/light",
spawn=sim_utils.DomeLightCfg(color=(0.75, 0.75, 0.75), intensity=3000.0),
)


##
# MDP settings
##


@configclass
class CommandsCfg:
"""Command terms for the MDP."""

object_pose = mdp.UniformPoseCommandCfg(
asset_name="robot",
body_name="panda_hand",
resampling_time_range=(5.0, 5.0),
debug_vis=True,
ranges=mdp.UniformPoseCommandCfg.Ranges(
pos_x=(0.4, 0.6), pos_y=(-0.25, 0.25), pos_z=(0.25, 0.5), roll=(0.0, 0.0), pitch=(0.0, 0.0), yaw=(0.0, 0.0)
),
)

place_pose = mdp.UniformPoseCommandCfg(
asset_name="robot",
body_name="panda_hand",
resampling_time_range=(5.0, 5.0),
debug_vis=True,
ranges=mdp.UniformPoseCommandCfg.Ranges(
pos_x=(0.4, 0.6), pos_y=(-0.25, 0.25), pos_z=(0.05, 0.05), roll=(0.0, 0.0), pitch=(0.0, 0.0), yaw=(0.0, 0.0)
),
)


@configclass
class ActionsCfg:
"""Action specifications for the MDP."""

# will be set by agent env cfg
arm_action: mdp.JointPositionActionCfg | mdp.DifferentialInverseKinematicsActionCfg = MISSING
gripper_action: mdp.BinaryJointPositionActionCfg = MISSING


@configclass
class ObservationsCfg:
"""Observation specifications for the MDP."""

@configclass
class PolicyCfg(ObsGroup):
"""Observations for policy group."""

joint_pos = ObsTerm(func=mdp.joint_pos_rel)
joint_vel = ObsTerm(func=mdp.joint_vel_rel)
object_position = ObsTerm(func=mdp.object_position_in_robot_root_frame)
target_object_position = ObsTerm(func=mdp.generated_commands, params={"command_name": "object_pose"})
target_place_position = ObsTerm(func=mdp.generated_commands, params={"command_name": "place_pose"})
actions = ObsTerm(func=mdp.last_action)

def __post_init__(self):
self.enable_corruption = True
self.concatenate_terms = True

# observation groups
policy: PolicyCfg = PolicyCfg()


@configclass
class EventCfg:
"""Configuration for events."""

reset_all = EventTerm(func=mdp.reset_scene_to_default, mode="reset")

reset_object_position = EventTerm(
func=mdp.reset_root_state_uniform,
mode="reset",
params={
"pose_range": {"x": (-0.1, 0.1), "y": (-0.25, 0.25), "z": (0.0, 0.0)},
"velocity_range": {},
"asset_cfg": SceneEntityCfg("object", body_names="Object"),
},
)


@configclass
class RewardsCfg:
"""Reward terms for the MDP."""

# Reward for reaching object
reaching_object = RewTerm(
func=mdp.object_ee_distance,
params={"std": 0.1},
weight=1.0
)

# Reward for lifting object
lifting_object = RewTerm(
func=mdp.object_is_lifted,
params={"minimal_height": 0.04, "maximal_height": 0.5},
weight=15.0
)

# Reward for moving object to lifting position
object_goal_tracking = RewTerm(
func=mdp.object_goal_distance,
params={
"std": 0.3,
"minimal_height": 0.04,
"maximal_height": 0.5,
"command_name": "object_pose"
},
weight=16.0
)

# Reward for moving object to placing position
placing_tracking = RewTerm(
func=mdp.object_goal_distance,
params={
"std": 0.1,
"minimal_height": 0.04,
"maximal_height": 0.5,
"command_name": "place_pose"
},
weight=18.0
)

object_placed = RewTerm(
func=mdp.object_is_placed, # Reference the function directly
params={
"distance_threshold": 0.02,
"height_threshold": 0.01,
},
weight=20.0
)


@configclass
class TerminationsCfg:
"""Termination terms for the MDP."""

time_out = DoneTerm(func=mdp.time_out, time_out=True)

object_dropping = DoneTerm(
func=mdp.root_height_below_minimum, params={"minimum_height": -0.05, "asset_cfg": SceneEntityCfg("object")}
)


@configclass
class CurriculumCfg:
"""Curriculum terms for the MDP."""

action_rate = CurrTerm(
func=mdp.modify_reward_weight, params={"term_name": "action_rate", "weight": -1e-1, "num_steps": 10000}
)

joint_vel = CurrTerm(
func=mdp.modify_reward_weight, params={"term_name": "joint_vel", "weight": -1e-1, "num_steps": 10000}
)


##
# Environment configuration
##


@configclass
class LiftEnvCfg(ManagerBasedRLEnvCfg):
"""Configuration for the lifting environment."""

# Scene settings
scene: ObjectTableSceneCfg = ObjectTableSceneCfg(num_envs=4096, env_spacing=2.5)
# Basic settings
observations: ObservationsCfg = ObservationsCfg()
actions: ActionsCfg = ActionsCfg()
commands: CommandsCfg = CommandsCfg()
# MDP settings
rewards: RewardsCfg = RewardsCfg()
terminations: TerminationsCfg = TerminationsCfg()
events: EventCfg = EventCfg()
curriculum: CurriculumCfg = CurriculumCfg()

def __post_init__(self):
"""Post initialization."""
# general settings
self.decimation = 2
self.episode_length_s = 5.0
# simulation settings
self.sim.dt = 0.01 # 100Hz
self.sim.render_interval = self.decimation

self.sim.physx.bounce_threshold_velocity = 0.2
self.sim.physx.bounce_threshold_velocity = 0.01
self.sim.physx.gpu_found_lost_aggregate_pairs_capacity = 1024 * 1024 * 4
self.sim.physx.gpu_total_aggregate_pairs_capacity = 16 * 1024
self.sim.physx.friction_correlation_distance = 0.00625
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,38 @@


def object_is_lifted(
env: ManagerBasedRLEnv, minimal_height: float, object_cfg: SceneEntityCfg = SceneEntityCfg("object")
env: ManagerBasedRLEnv,
minimal_height: float,
maximal_height: float,
object_cfg: SceneEntityCfg = SceneEntityCfg("object"),
) -> torch.Tensor:
"""Reward the agent for lifting the object above the minimal height."""
object: RigidObject = env.scene[object_cfg.name]
return torch.where(object.data.root_pos_w[:, 2] > minimal_height, 1.0, 0.0)
return torch.where(
(object.data.root_pos_w[:, 2] > minimal_height) & (object.data.root_pos_w[:, 2] < maximal_height), 1.0, 0.0
)


def object_is_placed(
env: ManagerBasedRLEnv,
distance_threshold: float,
height_threshold: float,
object_cfg: SceneEntityCfg = SceneEntityCfg("object"),
) -> torch.Tensor:
object: RigidObject = env.scene[object_cfg.name]
place_command = env.command_manager.get_command("place_pose")

object_pos = object.data.root_pos_w
target_pos = place_command[:, :3]

# check xy-distance to target
xy_distance = torch.norm(object_pos[:, :2] - target_pos[:, :2], dim=1)

# check height difference
height_diff = torch.abs(object_pos[:, 2] - target_pos[:, 2])

# return 1.0 if within thresholds, 0.0 otherwise
return torch.where((xy_distance < distance_threshold) & (height_diff < height_threshold), 1.0, 0.0)


def object_ee_distance(
Expand All @@ -49,6 +76,7 @@ def object_goal_distance(
env: ManagerBasedRLEnv,
std: float,
minimal_height: float,
maximal_height: float,
command_name: str,
robot_cfg: SceneEntityCfg = SceneEntityCfg("robot"),
object_cfg: SceneEntityCfg = SceneEntityCfg("object"),
Expand All @@ -64,4 +92,14 @@ def object_goal_distance(
# distance of the end-effector to the object: (num_envs,)
distance = torch.norm(des_pos_w - object.data.root_pos_w[:, :3], dim=1)
# rewarded if the object is lifted above the threshold
return (object.data.root_pos_w[:, 2] > minimal_height) * (1 - torch.tanh(distance / std))

if command_name == "object_pose":
# for lifting - reward when above minimal height
return ((object.data.root_pos_w[:, 2] > minimal_height) & (object.data.root_pos_w[:, 2] < maximal_height)) * (
1 - torch.tanh(distance / std)
)
elif command_name == "place_pose":
# for placing - reward getting close to place position
target_height = des_pos_w[:, 2] # Get height from command
height_diff = torch.abs(object.data.root_pos_w[:, 2] - target_height)
return 1 - torch.tanh((distance + height_diff) / std)
Loading