| gap | {"allowed_tools":["geometry.build_world_config","robot.get_observation","curobo.plan_to_grasp_poses","curobo.plan_grasp_motion","curobo.plan_directed_linear","robot.execute_trajectory","robot.move_to_joints","robot.get_ee_pose","robot.go_to_pose","robot.go_to_pose_cartesian","robot.open_gripper","robot.close_gripper"],"exit_conditions":{"grasped":"Object held in the gripper after `close`.","failed":"Any failure during the grasp attempt — collision-aware planning failure or trajectory execution error (a raise propagating to `on_error`). Coordinator routes to abort."},"required_inputs":{"target_obb":"OrientedBoundingBox","target_mask":"Mask"},"produces_outputs":{"ee_pose_at_grasp":"Se3Pose","grasp_pose":"Se3Pose"},"hard_rules":["ALWAYS begin with `robot.open_gripper` (settle_steps=40). Skipping this is the #1 silent grasp-failure mode when the gripper starts closed from a previous task step.\n","Use the canonical `compute_grasp` (`scripts/<sg>/short_axis_grasp_pose.py`) — it returns ONE deterministic Se3Pose aligned to the OBB's shorter horizontal axis. Do NOT swap in `geometry.top_down_grasp_candidates` or any sampled/scored generator: the whole point of this skill is that the orientation is geometry-locked, not discriminator-ranked. `plan_grasp` auto-wraps the single pose into a one-element goalset.\n","`offset_from_base` (`scripts/<sg>/offset_grasp_from_base.py`) is the robustness lever for a handle attached to a heavier body (frying pan, pot). It slides the grasp outward along the handle, clear of the body, so the jaws grip the bar — not the rim — and the grip survives the lift. To enable it: (1) author a SECOND perception subgraph that segments the object BODY (e.g. perceiving-object-parts / perceiving-objects with object/subpart name like \"the round base of the frying pan\"), (2) add `base_obb: OrientedBoundingBox` to THIS subgraph's `inputs` and wire it from that body perception, (3) bind `base_obb = Ref(\"in.base_obb\")` on the `offset_from_base` node. If you do NOT author a body perception, KEEP the `offset_from_base` state but bind only `handle_obb` + `grasp_pose` (omit `base_obb`); the script no-ops and returns the grasp unchanged. NEVER write `Ref(\"in.base_obb\")` unless `base_obb` is a declared subgraph input — that is a graph-validation error.\n","When building the collision world, ALWAYS pass `target_mask = Ref(\"in.target_mask\")` AND `target_obb = Ref(\"in.target_obb\")` AND a `target_name`. The mask is the authoritative target silhouette (pixel-accurate); the OBB is a safety fallback. The same `target_name` MUST be passed to `plan` (`plan_grasp.py`) so the planner excludes that mesh from collision.\n","ALWAYS include the `approach` state between `offset_from_base` and `observe`. `plan_grasp` disables CuRobo's `use_grasp_approach` flag on the assumption the gripper is already oriented over the target — skipping `approach` makes the descent start from a wrong wrist rotation and slip. `approach_above.py` lifts to a safe height, translates above the target, then rotates in place to the grasp orientation — all three legs route through `robot.go_to_pose_cartesian` (gap.connector.ik.CuRoboBackend), which uses cuRobo's MotionPlanner for both the linear plan and the plan_to_pose fallback, so the wrist flip succeeds even from the horizontal home pose.\n","ALWAYS insert a `finalize` state (`scripts/<sg>/finalize_trajectory.py`, input `trajectory = Ref(\"plan.trajectory\")`) BETWEEN `execute` and `close`. Edges: `execute → finalize → close`. This is mandatory and is the #1 silent grasp-failure cause: `execute` runs `robot.execute_trajectory` with `subsample=4`, so the body PD is still actively driving toward the last waypoint when control returns. If `robot.close_gripper` fires then, the simulator's action-manager tick silently DROPS the binary close action — the fingers never close, nothing is grasped, and `target_held` fails with no error (the planned-pose checkpoints still pass, masking the cause). `finalize` issues one `robot.move_to_joints` to the trajectory's final waypoint with full convergence so the PD is quiescent before `close`. Never wire `execute → close` directly.\n","Do NOT add a `verify_gripper_grasp` node — there is no such skill. Express \"the gripper is actually holding the target after close\" as a `validate=True` checkpoint (`target_held`). See `## Checkpoints`.\n","OPTIONAL escalation lever — `plan_grasp_motion` (`scripts/<sg>/plan_grasp_motion.py`, cuRobo v0.8 `curobo.plan_grasp_motion`). NOT part of the default 10-state flow and MUST NOT always be used. Consider composing it ONLY as an escalation when the standard `plan` (`plan_grasp.py` / `curobo.plan_to_grasp_poses`) raises \"0/N feasible\" / \"not reachable\" on a FAR / LOW / OCCLUDED handle (the `failed` route fires from `plan`, not from `compute_grasp` — the geometry-locked short-axis pose itself is correct). `curobo.plan_grasp_motion` decomposes the grasp into THREE separate trajectories — a free-space `approach_trajectory` to a pre-grasp offset, a constrained `grasp_trajectory` into the grasp pose, and a constrained `lift_trajectory` away from it — which can be feasible where the single all-in-one IK to the grasp pose is not. When you DO use it, replace the `plan → execute → finalize → close` tail with: execute `approach_trajectory`, execute `grasp_trajectory`, `finalize` its last waypoint, `robot.close_gripper`, THEN execute `lift_trajectory` — the gripper close is interleaved BETWEEN the grasp leg and the lift leg (that interleave is the whole reason the legs are returned separately). Inputs: `observation = Ref(\"observe\")` and a single `grasp_pose = Ref(\"offset_from_base.adjusted_grasp\")` (the script takes one pose, not a goalset). Discoverable, not mandatory — the standard `plan` remains the default path.\n"],"canonical_scripts":[{"compute_grasp":"scripts/short_axis_grasp_pose.py"},{"offset_from_base":"scripts/offset_grasp_from_base.py"},{"approach_above":"scripts/approach_above.py"},{"build_world":"scripts/build_world.py"},{"plan_grasp":"scripts/plan_grasp.py"},{"plan_grasp_motion":"scripts/plan_grasp_motion.py"},{"finalize_trajectory":"scripts/finalize_trajectory.py"}],"references":[{"title":"Why disable use_grasp_approach","path":"references/design_grasp_curobo.md"},{"title":"Gripper settle-step constants","path":"references/gripper_settle_constants.md"}],"streaming":false} |