# Grasping Short Axis

> 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: `graph-robots/grasping-short-axis` (Agent Skill, multi-file: 10 files)
- Install (CLI): `npx skillmds@latest add graph-robots/grasping-short-axis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/graph-robots/grasping-short-axis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: graph-robots (https://skillmd.com/u/graph-robots)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/graph-robots/grasping-short-axis

---


# 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:

```bash
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:

```text
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. **`open`** — `type: tool`, `tool: "robot.open_gripper"`,
   `inputs: { settle_steps: 40 }`.
2. **`compute_grasp`** — `type: 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_base`** — `type: 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. **`approach`** — `type: 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. **`observe`** — `type: tool`, `tool: "robot.get_observation"`.
6. **`build_world`** — `type: 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. **`plan`** — `type: 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. **`execute`** — `type: tool`,
   `tool: "robot.execute_trajectory"`,
   `inputs: { trajectory: Ref("plan.trajectory"), subsample: 4 }`.
9. **`finalize`** — `type: 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. **`close`** — `type: tool`, `tool: "robot.close_gripper"`,
    `inputs: { settle_steps: 60 }`. Edge directly from `close` to the
    `grasped` success marker.

The cross-subgraph output binding:

```python
sg.set_outputs(
    ee_pose_at_grasp=Ref("observe.arms.0.ee_pose"),
    grasp_pose=Ref("offset_from_base.adjusted_grasp"),
)
```

Wire the exit:

```python
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 its
  `approach`/`build_world`/`plan`/`finalize` tail (the scripts are
  bundled here so the skill is self-contained).

