← All ivy-nodes
IVYXSTUDIO · IVY NODE
C

Choose a grasp

ivy.node.choose-grasp · v0.1.0

ivyx✓

Decides how to take an object from its size: the jaw yaw across its narrow side and the approach height above it. A decision node: it computes, the robotics steps move.

#robotics#grasp#pick#decision

Inputs

FieldTypeDescription
sizerequiredobjectThe object's half extents in metres, as robotics.scene.locate answers them: x, y, z.
poseobjectThe object's pose, passed through.
jawOpeningnumberHow wide the jaws open, metres; the grasp goes across the side that fits.
clearancenumberMetres between the object's top and the jaws on the approach.

Outputs

FieldTypeDescription
yawrequirednumberThe jaw yaw about the vertical, radians: 0 across x, pi/2 across y.
approachrequirednumberMetres above the object's centre the jaws arrive before coming down.
fitsrequiredbooleanTrue when a side of the object fits between the jaws.
poseobjectThe object's pose, passed through.

Source

python

# Input preparation
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]

# Compute
import math

class ChooseGrasp:
    """
    Decides how to take an object from its half extents: the jaw yaw across
    its narrower side and the height above its centre the jaws arrive at.
    """

    def __init__(self, jaw_opening: float = 0.03, clearance: float = 0.03):
        if jaw_opening <= 0:
            raise ValueError("jawOpening must be a positive number of metres")
        if clearance < 0:
            raise ValueError("clearance must be zero or a positive number of metres")
        self.jaw_opening = jaw_opening
        self.clearance = clearance

    def run(self, size: dict) -> dict:
        hx = float(size.get("x", 0.0125))
        hy = float(size.get("y", 0.0125))
        hz = float(size.get("z", 0.0125))
        across_x = 2 * hx
        across_y = 2 * hy
        # The jaws close across the narrower side: a yaw of 0 closes across x, pi/2 across y.
        yaw = 0.0 if across_x <= across_y else math.pi / 2
        return {
            "yaw": yaw,
            "approach": round(hz + self.clearance, 4),
            "fits": min(across_x, across_y) <= self.jaw_opening,
        }

result = ChooseGrasp(float(inp.get("jawOpening", 0.03)), float(inp.get("clearance", 0.03))).run(inp.get("size") or {})
result["pose"] = inp.get("pose")

# Output collection (the runner reads it here)
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out.update(result)

Tests

Requires: python:3.9

  • cube-across-x

    A cube is taken across x, the jaws arriving 4.25 cm above its centre, and it fits.

  • bar-across-y

    A bar wider in x than the jaws is taken across y.

  • too-wide

    A block wider than the jaws on both sides does not fit.