Skip to content

Conversation

@rebeccazhang0707
Copy link
Collaborator

@rebeccazhang0707 rebeccazhang0707 commented Dec 16, 2025

Summary

Adds new new affordance: placeable and new atomic task: place upright task

Detailed description

  • What was the reason for the change?
    • Place upright task is a common inhouse task for humanoids. We believe 'placeable' should be a basic affordance to support. So we add related atomic task and example to showcase how to use this affordance.
  • What has been changed?
    • adds new atomic task: place upright task (and a test script for this task)
    • adss new affordance: placeable (placeable object can be placed upright, like mug, bottle, etc.)
    • adds new example: agibot left_arm place upright mug
    • adds a unitest for 'place_upright_task'
  • What is the impact of this change?
    • fixed the bug in agibot.py: since SceneCfg and ActionsCfg cannot accept a new type of property like ArmMode in manager-based workflow

Test Pipeline

  1. Zero Action Policy:
    python isaaclab_arena/examples/policy_runner.py --policy_type zero_action tabletop_place_upright --object mug

  2. Record demos:
    python isaaclab_arena/scripts/imitation_learning/record_demos.py --dataset_file datasets/dataset_agibot_left_arm_rel.hdf5 --num_demos 1 tabletop_place_upright --teleop_device keyboard

  3. Replay demos:
    python isaaclab_arena/scripts/imitation_learning/replay_demos.py --dataset_file datasets/dataset_agibot_left_arm_rel.hdf5 tabletop_place_upright

  4. Test place_upright_mug task:
    pytest isaaclab_arena/tests/test_place_upright_mug.py

@alexmillane alexmillane changed the base branch from main to reb/feature/adds_agibot December 17, 2025 15:19
@rebeccazhang0707 rebeccazhang0707 changed the base branch from reb/feature/adds_agibot to main December 18, 2025 14:35
@rebeccazhang0707 rebeccazhang0707 force-pushed the reb/feature/adds_place_upright_task branch from f89632f to 0d67164 Compare December 19, 2025 09:06
orientation_threshold, device=object_quat.device, dtype=object_quat.dtype
)

success = angle_error < orientation_threshold_tensor
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice

Copy link
Collaborator

Choose a reason for hiding this comment

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

yea this is cool!

- registers retargeter for place_upright_task
- updates background initial_pose and scale
Copy link
Collaborator

@alexmillane alexmillane left a comment

Choose a reason for hiding this comment

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

Thanks for adding this. Look good to me!

I have a few comments. Feel free to merge once you have addressed them.

- The orientation threshold is the threshold for the angle between the upright axis and the world +Z direction.
"""

def __init__(self, upright_axis_name: Literal["x", "y", "z"] = "z", orientation_threshold: float = 0.5, **kwargs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggestion to add a unit to orientation_threshold. For example orientation_threshold_deg (if indeed the unit here is degrees.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

thanks Alex, here is radians actually, and I will revise the default value to math.pi / 18.0 to indict that this is in radians, and adds the unit is radians in the comments of this method.

orientation_threshold, device=object_quat.device, dtype=object_quat.dtype
)

success = angle_error < orientation_threshold_tensor
Copy link
Collaborator

Choose a reason for hiding this comment

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

yea this is cool!

Comment on lines 73 to 77
"""Place the object upright (in all the environments).
This function places the object upright by rotating its upright axis towards the world +Z direction.
The upright percentage is a value in [0, 1] that describes the absolute target angle between the upright axis and the world +Z direction:
0.0 results in a perpendicular orientation (90 degrees) and 1.0 fully aligns the axis with +Z (0 degrees).
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

In the case of upright_percentage = 0.0 which world axis does the object's upright axis point along?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

upright_percentage = 0.0: the target upright axis is perpendicular to world +Z (90°), and the direction with the smallest angle to the object_upright_axis, in the plane spanned by the object_upright_axis and world +Z.

Comment on lines +127 to +131
def _compute_target_quaternions(
object_quat: torch.Tensor,
upright_percentage: float | torch.Tensor,
upright_axis_name: str,
) -> torch.Tensor:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion to add a docstring.

What's the expected shape of upright_percentage if it's a tensor? I would guess: [num_envs, 1]?

Comment on lines 138 to 140
axis_index = {"x": 0, "y": 1, "z": 2}[upright_axis_name]
rotation_mats = math_utils.matrix_from_quat(object_quat)
current_axis = rotation_mats[:, :, axis_index]
Copy link
Collaborator

Choose a reason for hiding this comment

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

This code is repeated from above. Suggestion to move to a function

def get_object_axis_in_world_frame(object_quat: torch.tensor) -> torch.tensor:
    axis_index = {"x": 0, "y": 1, "z": 2}[upright_axis_name]
    rotation_mats = math_utils.matrix_from_quat(object_quat)
    current_axis = rotation_mats[:, :, axis_index]
    return current_axis

Comment on lines 194 to 197
if __name__ == "__main__":
# test_place_upright_mug_single()
test_place_upright_mug_multi()
# test_place_upright_mug_condition()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for adding these tests!

Suggestion to uncommen the lines here.

Comment on lines +37 to +50
randomize_mug_positions = EventTerm(
func=randomize_object_pose,
mode="reset",
params={
"pose_range": {
"x": (-0.05, 0.2),
"y": (-0.10, 0.10),
"z": (0.75, 0.75),
"roll": (-1.57, -1.57),
"yaw": (-0.57, 0.57),
},
"asset_cfgs": [SceneEntityCfg("mug")],
},
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

@viiik-inside I feel like we need to add an option to our objects to add randomness to the poses on reset. I've now seen this pattern in a few MRs where people are overriding the EventCfg coming from the task. This kind of breaks our design. Maybe we could expand our definition of setting an objects pose to take either a Pose or a PoseRange such that object.set_initial_pose(Pose | PoseRange). In the case of a pose range, it would an event to the Cfg.

@rebeccazhang0707 rebeccazhang0707 enabled auto-merge (squash) December 22, 2025 02:46
viiik-inside and others added 2 commits December 23, 2025 11:46
## Summary
We allow addings spawn_cfg_addon and asset_cfg_addon. This exposes and gives possiblitly for a user to create any supported assets with various settings.
- TODO: find why long steps cause the object behavior not stable
@rebeccazhang0707 rebeccazhang0707 merged commit 012dabd into main Dec 23, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants