grasping-short-axis

SkillDev tools

Deterministic short-axis-aligned grasp with CuRobo. The grasp

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the grasping-short-axis skill

What this skill tells your AI

The instructions your AI receives, as published by graph-robots/open-robot-skills in skills/grasping-short-axis/SKILL.md and read by ahel’s review.

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_obb for 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.
  • curobo not 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:

  1. opentype: tool, tool: "robot.open_gripper", inputs: { settle_steps: 40 }.
  2. compute_grasptype: script, file scripts/<sg>/short_axis_grasp_pose.py (canonical — do NOT re-emit a ```python block; the bundle materializes it). Inputs: target_obb = Ref("in.target_obb"). Optional z_offset (default −0.04: descend the fingertip 4 cm into the OBB top). Returns {grasp_pose: Se3Pose}.
  3. offset_from_basetype: script, file scripts/<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 and base_obb declared as a subgraph input — base_obb = Ref("in.base_obb"). Returns {adjusted_grasp: Se3Pose}. Safe no-op when base_obb is absent.
  4. approachtype: script, file scripts/<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").
  5. observetype: tool, tool: "robot.get_observation".
  6. build_worldtype: script, file scripts/<sg>/build_world.py (canonical). Inputs: observation = Ref("observe"), target_mask = Ref("in.target_mask"), target_obb = Ref("in.target_obb"), target_name = "target".
  7. plantype: script, file scripts/<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.py auto-wraps the single bare Se3Pose into a one-element list. All four inputs are required.
  8. executetype: tool, tool: "robot.execute_trajectory", inputs: { trajectory: Ref("plan.trajectory"), subsample: 4 }.
  9. finalizetype: script, file scripts/<sg>/finalize_trajectory.py (canonical). Inputs: trajectory = Ref("plan.trajectory"). MANDATORY — see the execute → finalize → close hard_rule. Edges: execute → finalize, finalize → close.
  10. closetype: tool, tool: "robot.close_gripper", inputs: { settle_steps: 60 }. Edge directly from close to the grasped success 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 stateMeaning
graspedGripper has closed on the object after the descend. Route to the next subgraph (typically transporting-objects).
failedAny 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 its approach/build_world/plan/finalize tail (the scripts are bundled here so the skill is self-contained).

Signals

GitHub stars
41
Forks
7
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
grasping-short-axis
Source
github.com/graph-robots/open-robot-skills