mp_yam_code / source /bimanual /yam /tasks /drawer_open.py
yqi19's picture
YAM bimanual task suite: env, solvers, tasks, converters
7399b6f verified
Raw
History Blame Contribute Delete
3.19 kB
"""Pull a cabinet drawer open (RoboTwin 036_cabinet, three prismatic drawers).
A slider, not a hinge: the drawer front travels in a straight line, so the pull must stay on that
line. The same "follow the joint's own path" idea as microwave_door, with the arc replaced by a
line -- which is exactly why the two share one solver.
"""
from ..registry import register_task
from ..envs import YamTaskEnv
from ..solvers import articulate
from .. import conditions as C
@register_task("drawer_open")
class DrawerOpenTask(YamTaskEnv):
title = "PULL THE DRAWER OPEN"
tags = ["articulated", "slider", "constrained-motion", "robotwin-asset"]
instruction = {"default": "Open the drawer."}
rw_articulations = {"rw_cabinet": "036_cabinet/46653_clean.usd:0.20"}
body_xy = (-0.02, -0.24)
# Derived from the asset, not guessed: after the Y-up roll the drawer front sits at
# sim y = -0.093 and stands 1.6 cm proud of the cabinet body, and joint 0 drives the
# BOTTOM drawer, whose top edge is 10.7 cm above the table.
front_dy = -0.085
grip_z = 0.100
press_down = 0.0
# lean the wrist most of the way to horizontal so the fingers straddle the drawer's lip
grip_tilt = 62.0
pull_distance = 0.13
gripper_effort, gripper_damping = 80, 90
def _load_scene(self):
self._placed = []
self.scene.place_articulation({"name": "rw_cabinet", "bbox": [[-0.4283, -0.8033, -0.4334], [0.426, 0.8112, 0.4655]], "scale": 0.2, "xy": self.body_xy, "half": 0.14,
"xy_jitter": (0.015, 0.012)})
art = self.scene.articulations.get("rw_cabinet")
if art is not None:
print(f"[task] cabinet joints={list(art.data.joint_names)} "
f"limits={art.data.joint_pos_limits[0].cpu().numpy().round(3).tolist()}", flush=True)
for i, nm in enumerate(art.data.body_names):
print(f"[task] link {i} {nm}: {self.scene.link_pos('rw_cabinet', i).round(3)}",
flush=True)
def _initialize_episode(self):
for _ in range(60):
self.step()
def solve(self):
bx, by = self.scene.regions["rw_cabinet"]["xy"]
# Take the drawer front from the MEASURED body, not a guessed offset: every link of a
# closed cabinet reports the body origin, so there is nothing to read off the links, and
# a hardcoded -9 cm was simply not where this cabinet's face is.
print(f"[task] drawer lip at dy={self.front_dy:+.3f}, grip_z={self.grip_z:.3f}, "
f"press {self.press_down*1000:.0f} mm", flush=True)
return articulate.solve(self, fixture="rw_cabinet", kind="slider",
grip_xy=(bx, by+self.front_dy), grip_z=self.grip_z,
press=self.press_down, grip_tilt=self.grip_tilt,
open_jaw=False, jaw="x",
direction=(0.0, -1.0), distance=self.pull_distance,
approach_from=(0.0, -1.0))
def evaluate(self):
return self.check(
C.labelled("drawer drawn out", C.joint_driven("rw_cabinet", 0, by=0.05)))