Skip to content

Pickup action support upright#352

Open
matafela wants to merge 6 commits into
mainfrom
cj/make-upright
Open

Pickup action support upright#352
matafela wants to merge 6 commits into
mainfrom
cj/make-upright

Conversation

@matafela

@matafela matafela commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Description

Pickup action support upright.

  1. example: scripts/tutorials/atomic_action/move_held_object.py
  2. PickUpCfg add attribute obj_upright_direction and rotate_upright
  3. MoveHeldObjectCfg add attribute obj_upright_direction and pick_rotate_upright
  4. If rotate_upright is set, pick pose will be rotated around gripper y axis with radian rotate_upright
  5. If pick_rotate_upright is set, rotation of target object pose will be automatically calculated.

Type of change

  • Enhancement (non-breaking change which improves an existing functionality)

Screenshots

2026.07.03.19.41.15.webm

Checklist

  • I have run the black . command to format the code base.
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • Dependencies have been updated, if applicable.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds “upright” support to the PickUp atomic action by allowing an optional post-grasp rotation bias, plus a math utility to build rotation matrices from axis-angle and a tutorial update demonstrating the new knobs.

Changes:

  • Extend PickUpCfg with obj_upright_direction and rotate_upright, and apply an optional grasp-frame rotation offset during PickUp.execute().
  • Add axis_angle_to_rotation_matrix() utility in embodichain.utils.math.
  • Update the atomic-action tutorial script to use the new upright parameters and adjust target pose / lift height.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
scripts/tutorials/atomic_action/move_held_object.py Updates tutorial configuration/target pose to exercise upright-capable pickup.
embodichain/utils/math.py Adds axis-angle → rotation-matrix conversion helper.
embodichain/lab/sim/atomic_actions/actions.py Adds new PickUp config options and applies an optional upright-oriented rotation offset.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +811 to +827
# apply grasp yr rotation offset if specified
if self.cfg.rotate_upright is not None:
if self.cfg.obj_upright_direction is None:
upright_direction = torch.tensor([0, 0, 1], device=self.device)
else:
upright_direction = self.cfg.obj_upright_direction.to(self.device)
obj_pose = sem.entity.get_local_pose(to_matrix=True)
obj_upright = (upright_direction * obj_pose[:, :3, :3]).sum(axis=1)
grasp_ry = grasp_xpos[:, :3, 1]
dot_result = (grasp_ry * obj_upright).sum(axis=1)
# revert flag is -1 if the dot product is negative, 1 if positive
revert_flag = torch.where(dot_result < 0, 1.0, -1.0)
grasp_rx = grasp_xpos[:, :3, 0]
rota_axis_angle = self.cfg.rotate_upright * revert_flag * grasp_rx
rota_offset = axis_angle_to_rotation_matrix(rota_axis_angle)
upright_grasp_rota = torch.bmm(grasp_xpos[:, :3, :3], rota_offset)
grasp_xpos[:, :3, :3] = upright_grasp_rota
Comment on lines +114 to +118
obj_upright_direction: torch.Tensor | None = None
"""Optional object local direction to align with world up after grasping. By dafault we will use (0, 0, 1)."""

rotate_upright: float | None = None
"""Optional rotation (radians) about the grasp y-axis to apply to the grasp pose"""
Comment on lines +811 to +813
# apply grasp yr rotation offset if specified
if self.cfg.rotate_upright is not None:
if self.cfg.obj_upright_direction is None:
matafela added 2 commits July 6, 2026 18:28
Copilot AI review requested due to automatic review settings July 6, 2026 10:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.

Comment on lines +114 to +118
obj_upright_direction: torch.Tensor | None = None
"""Optional object local direction to align with world up after grasping. By dafault we will use (0, 0, 1)."""

rotate_upright: float | None = None
"""Optional rotation (radians) about the grasp y-axis to apply to the grasp pose"""
Comment on lines +129 to +133
pick_rotate_upright: float | None = None
"""Optional rotation (radians) about the grasp y-axis to apply to the grasp pose"""

obj_upright_direction: torch.Tensor | None = None
"""Optional object local direction to align with world up after grasping. By dafault we will use (0, 0, 1)."""
Comment on lines +824 to +828
obj_upright = (upright_direction * obj_pose[:, :3, :3]).sum(axis=2)
grasp_ry = grasp_xpos[:, :3, 1]
dot_result = (grasp_ry * obj_upright).sum(axis=1)
# revert flag is -1 if the dot product is negative, 1 if positive
revert_flag = torch.where(dot_result < 0, 1.0, -1.0)
Comment on lines +1042 to +1045
obj_upright = (upright_direction * held_obj_xpos[:, :3, :3]).sum(axis=2)

grasp_ry = held_eef_xpos[:, :3, 1]
dot_result = (grasp_ry * obj_upright).sum(axis=1)
Comment on lines +1049 to +1050
# rotate util upright
rota_axis_angle = -0.5 * torch.pi * revert_flag * grasp_rx
Comment thread embodichain/utils/math.py
Comment on lines +546 to +550
Args:
axis_angle: Axis-angle representation, radian * axis. Shape is (N, 3).

Returns:
Rotation matrices. Shape is (N, 3, 3).

is_success, grasp_xpos = self._resolve_grasp_pose(sem)

# apply grasp yr rotation offset if specified
Comment on lines +819 to +822
if self.cfg.obj_upright_direction is None:
upright_direction = torch.tensor([0, 0, 1], device=self.device)
else:
upright_direction = self.cfg.obj_upright_direction.to(self.device)
Comment on lines +1038 to +1041
if self.cfg.obj_upright_direction is None:
upright_direction = torch.tensor([0, 0, 1], device=self.device)
else:
upright_direction = self.cfg.obj_upright_direction.to(self.device)
Comment on lines +817 to +819
# apply grasp yr rotation offset if specified
if self.cfg.rotate_upright is not None:
if self.cfg.obj_upright_direction is None:
Copilot AI review requested due to automatic review settings July 6, 2026 11:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

Comment on lines +131 to +135
is_success, grasp_xpos = self._resolve_grasp_pose(sem, start_arm_qpos)

# apply grasp yr rotation offset if specified
if self.cfg.rotate_upright is not None:
if self.cfg.obj_upright_direction is None:
Comment on lines +77 to +79
obj_upright_direction: torch.Tensor | None = None
"""Optional object local direction to align with world up after grasping. By dafault we will use (0, 0, 1)."""

Comment on lines +80 to +81
rotate_upright: float | None = None
"""Optional rotation (radians) about the grasp y-axis to apply to the grasp pose"""
Comment on lines +113 to +126
obj_upright = (upright_direction * held_obj_xpos[:, :3, :3]).sum(axis=2)

grasp_ry = held_eef_xpos[:, :3, 1]
dot_result = (grasp_ry * obj_upright).sum(axis=1)
# revert flag is -1 if the dot product is negative, 1 if positive
revert_flag = torch.where(dot_result < 0, 1.0, -1.0)
grasp_rx = held_eef_xpos[:, :3, 0]
# rotate util upright
rota_axis_angle = -0.5 * torch.pi * revert_flag * grasp_rx
gripper_rotate_offset = axis_angle_to_rotation_matrix(rota_axis_angle)
# modified target xpos rotation
object_target_pose[:, :3, :3] = torch.bmm(
gripper_rotate_offset, held_obj_xpos[:, :3, :3]
)
Comment on lines +56 to +60
obj_upright_direction: torch.Tensor | None = None
"""Optional object local direction to align with world up after grasping. By dafault we will use (0, 0, 1)."""

pick_rotate_upright: float | None = None
"""Optional rotation (radians) about the grasp y-axis to apply to the grasp pose"""
Comment thread embodichain/utils/math.py
Comment on lines +544 to +551
"""Convert axis-angle representation to rotation matrix.

Args:
axis_angle: Axis-angle representation, radian * axis. Shape is (N, 3).

Returns:
Rotation matrices. Shape is (N, 3, 3).
"""
Comment on lines +133 to +135
# apply grasp yr rotation offset if specified
if self.cfg.rotate_upright is not None:
if self.cfg.obj_upright_direction is None:
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.

3 participants