| """Slide the desk bell onto its coaster, without grasping it. |
| |
| RoboTwin has "Click Bell"; this is deliberately not that. The bell here is a plain rigid mesh |
| with no plunger joint, so a "press" cannot register anything -- a rigid body on a rigid table |
| does not move under a downward push, and the check would be measuring nothing (it read 0.0 mm). |
| What IS measurable is sliding it: the bell is dome-shaped and top-heavy, so it tips easily, and |
| the task is to get it onto the coaster while leaving it standing. |
| """ |
| from ..registry import register_task |
| from ..envs import YamTaskEnv |
| from ..solvers import push |
| from .. import conditions as C |
|
|
|
|
| @register_task("bell_coaster") |
| class BellCoasterTask(YamTaskEnv): |
| title = "SLIDE THE BELL ONTO ITS COASTER" |
| tags = ["push", "no-grasp", "contact-rich", "robotwin-asset"] |
| instruction = {"default": "Push the bell onto the coaster."} |
|
|
| |
| |
| rw_objects = {"rw_bell": "050_bell/base0.usd:0.045:0.40"} |
| |
| |
| |
| bell_spawn = (-0.02, -0.02) |
| spawn_jitter = (0.018, 0.015) |
| coaster_xy = (0.10, 0.02) |
| coaster_size = 0.12 |
|
|
| def _load_scene(self): |
| self.scene.build_marker({"name": "coaster", "xy": self.coaster_xy, |
| "size": self.coaster_size, "color": (0.30, 0.26, 0.22), |
| "xy_jitter": (0.015, 0.015)}) |
| self._placed = [self.scene.place_object( |
| {"name": "rw_bell", "xy": self.bell_spawn, "xy_jitter": self.spawn_jitter})] |
|
|
| def solve(self): |
| e = self.scene.object_size("rw_bell") |
| print(f"[task] bell {e.round(3)} m", flush=True) |
| |
| |
| return push.solve(self, obj="rw_bell", target="coaster", advance=0.005, |
| steps=300, push_z_frac=0.10, |
| stop_dist=self.coaster_size*0.5) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| def evaluate(self): |
| return self.check( |
| C.labelled("bell on the coaster", C.object_moved_to("rw_bell", "coaster", tol=0.06)), |
| C.labelled("bell still standing", C.object_level("rw_bell", 25.0))) |
|
|