> ## Documentation Index
> Fetch the complete documentation index at: https://innateinc-theo-docs-skills-authoring-api.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Body Control Interfaces

export const HeadTiltAnglesTable = () => {
  const rows = [{
    angle: "-25deg",
    view: "Floor and objects below."
  }, {
    angle: "0deg",
    view: "Straight ahead."
  }, {
    angle: "+15deg",
    view: "Faces and shelves above."
  }];
  return <div className="interface-methods-table-wrap">
      <table className="interface-methods-table">
        <thead>
          <tr>
            <th>Angle</th>
            <th>View</th>
          </tr>
        </thead>
        <tbody>
          {rows.map(row => <tr key={row.angle}>
              <td>
                <span className="interface-param-badge">{row.angle}</span>
              </td>
              <td>{row.view}</td>
            </tr>)}
        </tbody>
      </table>
    </div>;
};

export const HeadInterfaceMethods = () => {
  const rows = [{
    method: "set_position()",
    params: [{
      name: "angle",
      type: "int"
    }],
    desc: "Set head tilt angle (from -25deg to +15deg)."
  }];
  return <div className="interface-methods-table-wrap">
      <table className="interface-methods-table">
        <thead>
          <tr>
            <th>Method</th>
            <th>Parameters</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
          {rows.map(row => <tr key={row.method}>
              <td>
                <span className="interface-method-pill">{row.method}</span>
              </td>
              <td>
                {row.params?.length ? <div className="interface-method-params">
                    {row.params.map(param => <span key={`${row.method}-${param.name}`} className="interface-param-badge">
                        {param.name}
                        {param.type ? <span className="interface-param-type">: {param.type}</span> : null}
                      </span>)}
                  </div> : <span className="interface-no-params">None</span>}
              </td>
              <td>{row.desc}</td>
            </tr>)}
        </tbody>
      </table>
    </div>;
};

export const ManipulationDeprecatedMethods = () => {
  const rows = [{
    method: "move_to_cartesian_pose()",
    params: [],
    desc: "Deprecated — use move_to(). Still works; warns once per process."
  }, {
    method: "move_to_joint_positions()",
    params: [],
    desc: "Deprecated — use move_joints()."
  }, {
    method: "move_cartesian_trajectory()",
    params: [],
    desc: "Deprecated — use follow() with Waypoints."
  }, {
    method: "open_gripper()",
    params: [],
    desc: "Deprecated — use gripper_open() (blocking, verifying, raising)."
  }, {
    method: "close_gripper()",
    params: [],
    desc: "Deprecated — use gripper_close()."
  }, {
    method: "get_current_end_effector_pose()",
    params: [],
    desc: "Deprecated — read the pose property (typed Arm value)."
  }, {
    method: "get_current_orientation_rpy()",
    params: [],
    desc: "Deprecated — read pose.rpy / pose.pitch."
  }, {
    method: "solve_ik()",
    params: [],
    desc: "Deprecated — clamp_reach() plus move_to() raising covers reachability."
  }];
  return <div className="interface-methods-table-wrap">
      <table className="interface-methods-table">
        <thead>
          <tr>
            <th>Method</th>
            <th>Parameters</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
          {rows.map(row => <tr key={row.method}>
              <td>
                <span className="interface-method-pill">{row.method}</span>
              </td>
              <td>
                <span className="interface-no-params">unchanged</span>
              </td>
              <td>{row.desc}</td>
            </tr>)}
        </tbody>
      </table>
    </div>;
};

export const ManipulationInterfaceMethods = () => {
  const rows = [{
    method: "move_to()",
    params: [{
      name: "x",
      type: "float"
    }, {
      name: "y",
      type: "float"
    }, {
      name: "z",
      type: "float"
    }, {
      name: "roll",
      type: "float = 0"
    }, {
      name: "pitch",
      type: "float = 0"
    }, {
      name: "yaw",
      type: "float = 0"
    }, {
      name: "duration",
      type: "float = 1.5"
    }, {
      name: "grip",
      type: "float | None"
    }, {
      name: "tolerance_xy",
      type: "float | None = 0.05"
    }, {
      name: "tolerance_z",
      type: "float | None = 0.10"
    }],
    desc: "Move the end-effector to a Cartesian pose (meters, radians), blocking. Verifies the arm tracked the target, auto-recovers once, and returns the settled Arm pose. Raises ArmFailed (unreachable) / ArmUnhealthy (servo fault). Pass tolerance_xy=None and tolerance_z=None for an unverified move."
  }, {
    method: "move_by()",
    params: [{
      name: "dx",
      type: "float = 0"
    }, {
      name: "dy",
      type: "float = 0"
    }, {
      name: "dz",
      type: "float = 0"
    }, {
      name: "duration",
      type: "float = 0.5"
    }],
    desc: "Nudge the end-effector by an offset from its measured pose (not its last commanded one) — the shape a visual-servoing loop wants. Also takes droll/dpitch/dyaw; same verification and tolerances as move_to()."
  }, {
    method: "wait()",
    params: [{
      name: "timeout",
      type: "float | None"
    }],
    desc: "Join an in-flight block=False motion and return the settled Arm pose; raises ArmFailed if it failed or timed out. The `moving` property is True while one is still in flight."
  }, {
    method: "follow()",
    params: [{
      name: "waypoints",
      type: "Sequence[Waypoint]"
    }, {
      name: "grip",
      type: "float | None"
    }],
    desc: "Sweep through Cartesian waypoints as one smooth trajectory (no deceleration at intermediate points), starting from the current pose. Each Waypoint(x, y, z, roll, pitch, yaw, duration) paces its own segment. Returns the settled Arm pose."
  }, {
    method: "move_joints()",
    params: [{
      name: "joints",
      type: "Sequence[float]"
    }, {
      name: "duration",
      type: "float = 3.0"
    }],
    desc: "Move to joint positions (radians), blocking. 5 values command the arm and keep the current grip; 6 values command the gripper too."
  }, {
    method: "rest()",
    params: [{
      name: "duration",
      type: "float = 3.0"
    }],
    desc: "Fold the arm to its rest pose, keeping the grip, and settle."
  }, {
    method: "gripper_open()",
    params: [{
      name: "percent",
      type: "float = 100"
    }, {
      name: "duration",
      type: "float = 0.5"
    }],
    desc: "Open the claw, blocking; verifies it physically opened and reboot-retries a tripped servo once, else raises ArmUnhealthy."
  }, {
    method: "gripper_close()",
    params: [{
      name: "strength",
      type: "float = 0"
    }, {
      name: "duration",
      type: "float = 0.5"
    }],
    desc: "Close the claw, blocking. strength (radians past closed, capped) is the grip preload on an object — it becomes the standing grip target that every following move carries automatically."
  }, {
    method: "pose",
    params: [],
    desc: "Property: the live end-effector pose as an Arm value (position, quaternion, .rpy / .pitch, .gripper). Raises ArmFailed if the FK feed is down."
  }, {
    method: "torque_on() / torque_off()",
    params: [],
    desc: "Enable or disable arm servo torque (returns bool). A torque-disabled arm is limp, for manual positioning."
  }, {
    method: "recover()",
    params: [],
    desc: "Reboot the servos, re-enable torque, and settle (~2.5 s) — clears overcurrent trips and brownouts, keeping the standing grip target."
  }, {
    method: "clamp_reach()",
    params: [{
      name: "x",
      type: "float"
    }, {
      name: "y",
      type: "float"
    }],
    desc: "Clamp an (x, y) floor target into the arm's graspable reach box."
  }];
  return <div className="interface-methods-table-wrap">
      <table className="interface-methods-table">
        <thead>
          <tr>
            <th>Method</th>
            <th>Parameters</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
          {rows.map(row => <tr key={row.method}>
              <td>
                <span className="interface-method-pill">{row.method}</span>
              </td>
              <td>
                {row.params?.length ? <div className="interface-method-params">
                    {row.params.map(param => <span key={`${row.method}-${param.name}`} className="interface-param-badge">
                        {param.name}
                        {param.type ? <span className="interface-param-type">: {param.type}</span> : null}
                      </span>)}
                  </div> : <span className="interface-no-params">None</span>}
              </td>
              <td>{row.desc}</td>
            </tr>)}
        </tbody>
      </table>
    </div>;
};

The `Manipulation` and `Head` interfaces give you direct control over the robot's arm and head. Use these for manipulation tasks, gestures, and camera positioning.

## Manipulation

Declare the interface with a class-level type annotation — it's injected and guaranteed before `execute()` starts:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
from innate import Manipulation, Skill

class MySkill(Skill):
    manipulation: Manipulation
```

Every motion method blocks until the arm settles and raises on failure — no return codes to check:

| Exception      | Means                                                                                                                  |
| -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `ArmFailed`    | The command was rejected or impossible — an unreachable pose, a failed IK solve, a trajectory the driver refused.      |
| `ArmUnhealthy` | The arm accepted the command but didn't get there, and a reboot-and-retry didn't fix it. The hardware needs attention. |

Import them from `innate` (or `innate.exceptions`, which groups every exception a skill raises or catches) when you want to handle them. If you don't, the run reports `FAILURE` with the message, which is usually what you want:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
from innate import ArmFailed, ArmUnhealthy, Manipulation, Waypoint
```

### Methods

<ManipulationInterfaceMethods />

### Cartesian Control

Move the end-effector to a position and orientation (meters and radians, relative to `base_link`):

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
settled = self.manipulation.move_to(0.30, 0.0, 0.10, pitch=1.45, duration=2.0)
self.logger.info(f"landed at z={settled.z:.3f}")
```

`move_to` verifies by forward kinematics that the arm actually tracked the target, recovers (servo reboot + torque on) and retries once if it didn't, and returns the settled pose. A z shortfall usually means the fingers met the object or floor early — loosen or skip that axis with `tolerance_z=None` on expected-contact descents, or pass `tolerance_xy=None, tolerance_z=None` for a fully unverified move.

`move_by` nudges from the arm's **measured** pose rather than its last commanded one, which is what a visual-servoing loop wants:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
self.manipulation.move_by(dx=0.01, dy=-0.005, duration=0.3)
```

### Doing something else while the arm moves

Pass `block=False` to return as soon as the command is accepted, then join with `wait()`:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
self.manipulation.move_to(0.30, 0.0, 0.25, duration=2.0, block=False)

while self.manipulation.moving:
    self.mobility.send_cmd_vel(linear_x=0.05, duration=0.3)
    self.sleep(0.1)

settled = self.manipulation.wait()   # raises if the motion failed
```

A non-blocking motion is **unverified until you join it** — `wait()` is what surfaces a failure. Issuing a new command supersedes a motion you never joined.

### Trajectories

Sweep through several poses as one smooth motion — the arm interpolates between waypoints without decelerating at each one:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
from innate import Waypoint

self.manipulation.follow([
    Waypoint(0.30, 0.0, 0.20, pitch=1.45, duration=0.8),
    Waypoint(0.30, 0.0, 0.12, pitch=1.45, duration=0.6),
    Waypoint(0.30, 0.0, 0.06, pitch=1.45, duration=0.6),
])
```

Each waypoint's `duration` paces the segment that reaches it, and the trajectory starts from wherever the arm currently is.

### Joint Control

Move directly to joint angles (radians):

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
# 6 values command all joints including the gripper (j6)
self.manipulation.move_joints([0, -0.5, 1.5, -1.0, 0, 0], duration=2.0)

# 5 values move the arm and leave the gripper as it is — safe while holding
self.manipulation.move_joints([0, -0.5, 1.5, -1.0, 0], duration=2.0)

# Fold to the built-in rest pose (keeps the grip)
self.manipulation.rest()
```

### Gripper

The claw is joint 6, driven under current-based position control: grip force is enforced in hardware, so a deep close squeezes any object at a constant, safe force.

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
self.manipulation.gripper_open()             # fully open, verified (self-heals a tripped servo)
self.manipulation.gripper_open(percent=50)   # half
self.manipulation.gripper_close(0.4)         # close with 0.4 rad of grip preload
```

`strength` is radians of preload past the closed stop, capped at `GRIPPER_MAX_STRENGTH` (0.6) — beyond that the servo overcurrent-trips on a real object.

The strength you close with becomes the **standing grip target**: every following `move_to` / `follow` / 5-joint `move_joints` carries it automatically, so a gripped object stays gripped with no extra bookkeeping. Grip once, then move freely — you never thread a `gripper=` argument through a trajectory.

### Reading State

The `pose` property returns the live end-effector pose as a typed `Arm` value:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
pose = self.manipulation.pose
pose.position   # (x, y, z) in meters
pose.rpy        # (roll, pitch, yaw) in radians — also pose.pitch etc.
pose.gripper    # gripper joint (j6) position, radians
```

For ambient arm state on a 50 Hz feed, declare `arm: Arm` instead — same type, pushed to you — see [Robot State](/software/skills/code-defined-skills/robot-state).

### Reachability

`clamp_reach(x, y)` pulls a floor target into the arm's graspable reach box; a pose IK can't solve raises `ArmFailed` from `move_to`, so an explicit pre-check is rarely needed:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
x, y = self.manipulation.clamp_reach(x, y)
try:
    self.manipulation.move_to(x, y, 0.06, pitch=1.45)
except ArmFailed:
    self.fail("Target out of reach")
```

### Deprecated methods

Skills written against the 0.6.0 API keep working — the old methods delegate to the new core and log a one-time deprecation warning per process:

<ManipulationDeprecatedMethods />

Migration is mechanical: `move_to_cartesian_pose(...) → move_to(...)`, `move_to_joint_positions(...) → move_joints(...)`, `move_cartesian_trajectory(...) → follow([...])`, `open_gripper/close_gripper → gripper_open/gripper_close`, `get_current_end_effector_pose()/get_current_orientation_rpy() → pose`. Note the new methods raise instead of returning `False`, and block by default.

## Head

Control camera tilt:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
from innate import Head, Skill

class MySkill(Skill):
    head: Head
```

### Methods

<HeadInterfaceMethods />

### Tilt Angles

<HeadTiltAnglesTable />

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
self.head.set_position(-15)  # Look down at objects
self.head.set_position(0)    # Look straight ahead
self.head.set_position(10)   # Look up at faces
```

## Example: Wave

A skill that waves the arm, with `guidelines()` written out explicitly:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
from innate import Manipulation, Skill, SkillReturn

class Wave(Skill):
    manipulation: Manipulation

    def guidelines(self) -> str:
        return "Use to wave at someone in greeting."

    def execute(self, times: int = 3) -> SkillReturn:
        # Wave positions (5 values: the gripper stays as it is)
        wave_left = [0.5, -0.3, 1.0, -0.5, 0.5]
        wave_right = [0.5, -0.3, 1.0, -0.5, -0.5]

        for _ in range(times):
            self.manipulation.move_joints(wave_left, duration=0.5)
            self.manipulation.move_joints(wave_right, duration=0.5)

        return f"Waved {times} times"
```

## Example: LookAtObject

A skill that adjusts head to look at objects:

```innatepy theme={"languages":{"custom":["/languages/python-typed.json"]}}
from innate import Head, Skill, SkillReturn

class LookAtObject(Skill):
    head: Head

    def guidelines(self) -> str:
        return "Use to tilt camera to look at objects on the floor or shelves."

    def execute(self, location: str = "floor") -> SkillReturn:
        angles = {
            "floor": -25,
            "table": -10,
            "ahead": 0,
            "face": 10,
            "shelf": 15
        }

        angle = angles.get(location, 0)
        self.head.set_position(angle)

        return f"Looking at {location}"
```
