Grasping short axis
Skill graph-robots/open-robot-skills/skills/grasping-short-axis
Skill and tool bundles for gap (graph as policy) — Anthropic Agent Skills format, discovered by path
npx -y skills add graph-robots/open-robot-skills --skill grasping-short-axisAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Deterministic short-axis-aligned grasp with CuRobo. The grasp pose is computed geometrically (NOT sampled/scored) — the gripper approaches straight down with its finger-opening axis locked to the OBB's SHORTER horizontal axis, so the jaws close ACROSS the narrow dimension of an elongated target. Use for pan/pot handles, bottles, tools, utensils — anywhere the OBB centroid is graspable but orientation is the thing that matters. An optional offset_from_base node slides the grasp outward along the handle, clear of the heavier object body, when a second OBB of that body is wired in. A scored/sampled pose often holds at close but shears out under the lift; the short-axis pose grips the bar squarely so it survives lift + transport.
SKILL.md
13.5 KB, as published. Nobody here has run it
grasping-short-axis
Deterministic, geometry-locked grasping with CuRobo. The grasp pose is computed directly from the target OBB — the gripper descends along world −Z with its finger-opening axis snapped to the OBB's shorter horizontal axis, so the jaws close across the narrow dimension of the bar. An optional node then slides the grasp outward along the handle, clear of a heavier attached body. The subgraph builds a per-observation collision world (target excluded), plans a CuRobo trajectory, executes it, finalizes the last waypoint, closes the gripper, and outputs the EE pose at grasp.
Install
This skill depends on the curobo and geometry tool bundles:
export CUDA_HOME=/usr/local/cuda
uv sync --extra curobo --extra geometry # (pip: pip install -e "open-robot-skills[curobo,geometry]" --no-build-isolation)
When to use
- Elongated targets where grasp orientation matters: pan / pot handles, bottles, tools, utensils.
- A subpart (handle) that protrudes from a heavier body — wire
base_obbfor the outward slide. - When a sampled/scored grasp pose holds at close but the object slips during the lift (marginal off-axis contact patch).
When NOT to use
- Symmetric objects (boxes, cans) where any yaw works — use
grasping-with-planner. curobonot deployed.- You genuinely want multiple sampled candidates for the planner to
choose from — use
grasping-with-planner.
Recommended subgraph state flow
10 states, in order:
open → compute_grasp → offset_from_base → approach → observe
→ build_world → plan → execute → finalize → 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: script, filescripts/<sg>/short_axis_grasp_pose.py(canonical — do NOT re-emit a```pythonblock; the bundle materializes it). Inputs:target_obb = Ref("in.target_obb"). Optionalz_offset(default −0.04: descend the fingertip 4 cm into the OBB top). Returns{grasp_pose: Se3Pose}.offset_from_base—type: script, filescripts/<sg>/offset_grasp_from_base.py(canonical). Inputs:handle_obb = Ref("in.target_obb"),grasp_pose = Ref("compute_grasp.grasp_pose"), and — ONLY when a body perception was authored andbase_obbdeclared as a subgraph input —base_obb = Ref("in.base_obb"). Returns{adjusted_grasp: Se3Pose}. Safe no-op whenbase_obbis absent.approach—type: script, filescripts/<sg>/approach_above.py(canonical). Inputs:target_position = Ref("offset_from_base.adjusted_grasp.position"),rotation = Ref("offset_from_base.adjusted_grasp.rotation"),target_obb = Ref("in.target_obb").observe—type: tool,tool: "robot.get_observation".build_world—type: script, filescripts/<sg>/build_world.py(canonical). Inputs:observation = Ref("observe"),target_mask = Ref("in.target_mask"),target_obb = Ref("in.target_obb"),target_name = "target".plan—type: script, filescripts/<sg>/plan_grasp.py(canonical). Inputs:world_config = Ref("build_world.config"),observation = Ref("observe"),grasp_poses = Ref("offset_from_base.adjusted_grasp"),target_name = "target".plan_grasp.pyauto-wraps the single bare Se3Pose into a one-element list. All four inputs are required.execute—type: tool,tool: "robot.execute_trajectory",inputs: { trajectory: Ref("plan.trajectory"), subsample: 4 }.finalize—type: script, filescripts/<sg>/finalize_trajectory.py(canonical). Inputs:trajectory = Ref("plan.trajectory"). MANDATORY — see theexecute → finalize → closehard_rule. Edges:execute → finalize,finalize → close.close—type: tool,tool: "robot.close_gripper",inputs: { settle_steps: 60 }. Edge directly fromcloseto thegraspedsuccess marker.
The cross-subgraph output binding:
sg.set_outputs(
ee_pose_at_grasp=Ref("observe.arms.0.ee_pose"),
grasp_pose=Ref("offset_from_base.adjusted_grasp"),
)
Wire the exit:
sg.add_edge("close", "grasped")
sg.add_edge("grasped", END)
sg.add_exit("grasped")
sg.set_on_error("failed")
Required end states
| End state | Meaning |
|---|---|
grasped | Gripper has closed on the object after the descend. Route to the next subgraph (typically transporting-objects). |
failed | Any grasp-attempt failure: collision-aware planning failure or trajectory execution error (a raise to on_error). Lives only in on_error — never declare a failed node. |
Checkpoints
Express grasp success as a validate=True postcondition checkpoint
target_held on the close state (the gripper is holding the target
after close). Do not add a re-check-and-raise node.
See also
../grasping-with-planner/SKILL.md— the sampled-candidate OBB counterpart; this skill mirrors itsapproach/build_world/plan/finalizetail (the scripts are bundled here so the skill is self-contained).