| """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) |
| |
| |
| |
| front_dy = -0.085 |
| grip_z = 0.100 |
| press_down = 0.0 |
| |
| 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"] |
| |
| |
| |
| 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))) |
|
|