Grasping with planner
Skill graph-robots/open-robot-skills/skills/grasping-with-planner
Top-down grasping via a fast axis-locked linear descend with a collision-aware cuRobo fallback. A single `grasp_descend_linear` node rises, translates over the target, and descends straight down (Z-locked, orientation held) onto the object; if the straight-line solve is infeasible (far-edge reach, no IK for the fixed wrist) it falls back to the cuRobo planner over the candidate fan. Use when the curobo tool bundle is installed and a perceived object (OBB) must be grasped — the default grasping skill whenever cuRobo is deployed, in clean and cluttered scenes alike.From its SKILL.md
npx -y skills add graph-robots/open-robot-skills --skill grasping-with-plannerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- runs commandsInstructs the agent to run 2 commands, including `export CUDA_HOME=/usr/local/cuda` and 1 more.
SKILL.md
10.7 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
grasping-with-planner
Top-down grasping with a fast axis-locked linear descend and a
collision-aware cuRobo fallback. The primary path rises to a hover height,
translates over the target while rotating to the grasp yaw, and descends
straight down (Z-only, orientation locked) onto the object — which, unlike a
goalset planner, happily grips a flat object by simply lowering onto it. If
the straight-line solve is infeasible, the same node hands off to the cuRobo
planner, which builds a per-observation collision world and searches the whole
candidate fan for a reachable, collision-free wrist. This is the
grocery_packing grasp motion, distilled to the general single-object case.
Install
This skill depends on the curobo tool bundle (curobo.plan_directed_linear,
curobo.plan_to_grasp_poses). cuRobo JIT-compiles CUDA extensions at install
time — build isolation must be off and CUDA_HOME must point at a toolkit
matching your torch build:
export CUDA_HOME=/usr/local/cuda
uv sync --extra curobo # (pip: pip install -e "open-robot-skills[curobo]" --no-build-isolation)
See tools/curobo/SKILL.md for the full recipe and gotchas.
When to use
- Default grasping skill whenever
curobois deployed — clean or cluttered. - Flat / low-profile objects (a butter box, cream cheese) where a goalset planner struggles but a straight lower-on-top succeeds.
When NOT to use
curobonot deployed. Usegrasping-direct-ikinstead.- The graspable region is NOT the OBB centroid — bowl rim, mug / moka-pot /
frying-pan handle, or any off-center grasp. The OBB top-down candidates from
geometry.top_down_grasp_candidatesare centered on the OBB XY, so they slip on hollow centers and miss handles. Usegrasping-short-axisfor elongated handles, where the centroid is graspable but orientation is what matters.
Recommended subgraph state flow
6 states, in order:
open → compute_grasp → goto_grasp → observe → close → grasped
(grasped is the success-marker noop from sg.add_exit("grasped"),
with an edge to END.)
State details:
-
open—type: tool,tool: "robot.open_gripper",inputs: { settle_steps: 40 }. -
compute_grasp—type: tool,tool: "geometry.top_down_grasp_candidates",inputs: { obb: Ref("in.target_obb") }. Returnscandidates: {poses: list[Se3Pose]}— a yaw fan of top-down grasps. -
goto_grasp—type: script, filescripts/<sg>/grasp_descend_linear.pyfrom this bundle's canonical_scripts. Inputs:grasp_pose = Ref("compute_grasp.candidates.poses.0"),candidate_poses = Ref("compute_grasp.candidates.poses"),target_obb = Ref("in.target_obb"),hover_z = 0.2. Rises tohover_z, translates over the target at the grasp yaw, then Z-locked linear-descends onto it (shallow grip near the perceived top, floored a hair above the object base so the fingers never ram the table). On an infeasible cartesian solve it falls back tocurobo.plan_to_grasp_posesovercandidate_poses. -
observe—type: tool,tool: "robot.get_observation",inputs: {}. Captures the arm state AT the grasp (post-descend, pre-close) soee_pose_at_graspreflects the real TCP pose the object was gripped at. -
close—type: tool,tool: "robot.close_gripper",inputs: { settle_steps: 60 }. Edge directly fromcloseto thegraspedsuccess marker; the subgraph'son_error: "failed"catches any raise fromgoto_grasp(both paths failed). Whether the gripper actually closed on the object is checked by thetarget_heldpostcondition checkpoint (see## Checkpoints), NOT by a re-check-and-raise node (none such exists).The subgraph publishes two cross-subgraph outputs:
ee_pose_at_grasp— the live TCP pose captured at theobservestep (which sits between the descend andclose). Downstreamtransporting-objectsuses it to compute a drop height that accounts for the panda hand-to-tcp offset and the held object's geometry.grasp_pose— the computed grasp pose emitted bycompute_grasp, i.e. what the descend is targeting. Distinct fromee_pose_at_grasp(the actual EE pose at grasp time). Exposinggrasp_poselets the checkpoint author write an output-anchored verifier likepredicate=lambda w, o: o["grasp_pose"]["position"]["z"] > 0.01to catch sub-table grasp poses before they cascade into atarget_held=Falsefailure.
Hard rule on the output binding: the
robot.get_observationresponse is anObservation { cameras: list[CameraFrame]; arms: list[ArmState] }. There is no flatee_posefield — the EE pose lives atarms[0].ee_pose. The binding must therefore be exactly:sg.set_outputs( ee_pose_at_grasp=Ref("observe.arms.0.ee_pose"), grasp_pose=Ref("compute_grasp.candidates.poses.0"), )Do not write
Ref("observe.ee_pose")— that path does not exist and the cross-subgraph binding will silently resolve to None, sending the downstreamcompute_drop_pose.pyinto its inferior no-ee_pose_at_graspfallback (drop height too high, placement misses).Cross-subgraph data flow is by name, so any downstream subgraph that declares
ee_pose_at_graspas an input automatically receives it."edges": [ ..., ["close", "grasped"], ["grasped", "END"] ], "conditional_edges": {}, "exit": { "router_field": null, "success_values": ["grasped"] }, "on_error": "failed"The lift onto a safe carry height is handled by the next
transporting-objectssubgraph (itswaypoint_movescript lifts before lateral motion); do NOT add a lift step here.
Optional candidate-reordering state
For a thin/elongated target (frypan handle, screwdriver, spoon, rod) insert ONE
type: script state select_short_axis (scripts/<sg>/select_short_axis.py)
between compute_grasp and goto_grasp. Inputs:
target_obb = Ref("in.target_obb"),
candidate_poses = Ref("compute_grasp.candidates.poses"). It reorders the
candidate fan so poses whose finger-opening axis aligns with the OBB's short
horizontal axis come first (count and pose values preserved — only the ordering
changes), then wire goto_grasp's grasp_pose/candidate_poses against
Ref("select_short_axis.poses...") instead. For a deterministic,
geometry-locked single short-axis pose use the dedicated grasping-short-axis
skill instead.
Required end states
| End state | Meaning |
|---|---|
grasped | Gripper has closed on the object after the descend. Route to next subgraph (typically transporting-objects). |
failed | Grasp-attempt failure: the cartesian descend AND the cuRobo planner fallback both failed (a raise to on_error). Coordinator routes to abort. Lives only in on_error — never declare a failed node. |
See also
references/design_grasp_curobo.md— the Z-locked (fingertip-frame, orientation-LOCK) linear descend and why it beats a blended rotate+descend.references/gripper_settle_constants.md— settle-step tunings.scripts/{grasp_descend_linear,select_short_axis}.py— canonical scripts.
What ships with it: 9 files
35.8 KB alongside SKILL.md, 6 of them executable
examples/
- canonical_subgraph.json1.4 KB
references/
scripts/
- approach_above.pyruns2.4 KB
- build_world.pyruns2.2 KB
- compute_align_pose.pyruns1.0 KB
- grasp_descend_linear.pyruns19.3 KB
- plan_grasp.pyruns2.6 KB
- select_short_axis.pyruns4.0 KB
Gives 0 of the 12 instructions most plan spec skills give in ~1.9k tokens
Counted across 1,360 of the 2,617 authors here whose files we hold, read 2026-09-06
- Ask one question at a timein 73 of 1360
- Write the spec using the templatein 22 of 1360
- Ask clarifying questions if neededin 19 of 1360, across 18 files
- Wait for user confirmation before proceedingin 19 of 1360
- Save plans to the plans directoryin 17 of 1360, across 13 files
- Check for product marketing context firstin 16 of 1360, across 5 files
- Read the plan file completelyin 16 of 1360
- Order tasks by dependencyin 16 of 1360
- Gather context from the conversationin 15 of 1360, across 9 files
- Explore the codebase instead of askingin 15 of 1360, across 13 files
- Wait for explicit user approvalin 14 of 1360, across 13 files
- Quiz the user on the breakdownin 13 of 1360, across 7 files
Said here and by no other author read
- Use curobo tool bundle when deployed
- Open gripper before computing grasp
- Compute top down grasp candidates from object obb
- Execute linear descend onto target
- Capture arm observation at grasp
- Close gripper after descend
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.