> ## Documentation Index
> Fetch the complete documentation index at: https://servo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Robots

> Register a robot and connect its sensors and actuators to Servo.

A Servo robot record identifies one physical rig. Your robot application opens its hardware devices,
applies local calibration, and manages motor bus communication. Servo executes policy models, validates
camera frames and joint states across the network boundary, and streams validated joint targets back to
your application.

## Prerequisites

Before registering a robot with Servo, ensure you have:

1. **A Calibrated Robot**: Servo does not communicate directly with motor buses or perform joint zeroing.
   Calibrate your robot using your hardware driver's normal bringup tools before connecting to Servo.
2. **Local Configuration Files**: Have the paths to your robot driver's local configuration files on disk
   (for example, left and right arm configs).
   * Servo uses these files strictly to record a SHA-256 fingerprint (`configuration_digest`). Servo never
     parses, modifies, or uploads them.
   * If developing or testing without physical hardware, create two placeholder files:
     ```bash theme={null}
     mkdir -p /opt/yam/configs
     echo "arm: left" > /opt/yam/configs/yam_left.yaml
     echo "arm: right" > /opt/yam/configs/yam_right.yaml
     ```
3. **A Python Runtime Factory (`open_yam`)**: A zero-argument function in your robot application that opens
   and returns your calibrated `RobotEnv` (implementing `get_obs()`, `step_command_only(joints)`, and `close()`).
   See [Connect sensors and actuators](#connect-sensors-and-actuators) for a complete reference implementation.

## Bimanual YAM contract

```bash theme={null}
servo robot catalog
```

```text theme={null}
Bimanual YAM
  Type: servo.yam.bimanual-joint-position.v1
  Cameras: top, left, right
  State values: 14
  Action values: 14
  Rate: 30 Hz
```

The state and action order is:

```text theme={null}
left joint 0..5, left gripper, right joint 0..5, right gripper
```

Each camera supplies a 360 × 640 RGB frame. Servo checks the role, color format, and dimensions,
then prepares the frame for the selected model.

## Register a physical robot

Run setup on the computer wired to the robot, passing the paths to your local configuration files:

```bash theme={null}
servo robot setup yam-cell-01 \
  --config /opt/yam/configs/yam_left.yaml \
  --config /opt/yam/configs/yam_right.yaml \
  --region us-west-2 \
  --site sf-lab \
  --label line=assembly
```

`--config` accepts the hardware configuration files identified in the prerequisites. Pass the left arm
configuration file first and the right arm configuration file second.

Servo reads their raw bytes and stores a SHA-256 digest (`configuration_digest`) to record an immutable
hardware revision fingerprint. This allows Servo to detect if a physical arm's zero-offsets or motor setup
have changed without coupling Servo core to specific motor or driver tooling.

Bimanual YAM is the default type. Use `--manifest` for a custom robot.

Give every physical rig a unique name. Running setup again with the same name and type keeps its
`rob_*` ID across process restarts, operating-system reinstalls, and robot-computer replacements.
If the configuration changes, run setup again to record the new hash.

View the inventory from any signed-in computer:

```bash theme={null}
servo robot list
```

```text theme={null}
yam-cell-01
  ID: rob_01...
  Type: servo.yam.bimanual-joint-position.v1
  Region: us-west-2
  Site: sf-lab

yam-cell-02
  ID: rob_02...
  Type: servo.yam.bimanual-joint-position.v1
  Region: us-west-2
  Site: sf-lab
```

## Choose a model

Choose the model after registering the robot:

```bash theme={null}
servo model list yam-cell-01
```

```text theme={null}
π0.5
  Slug: pi0.5
  Vendor: Physical Intelligence

MolmoAct2
  Slug: molmoact2
  Vendor: Allen Institute for AI
```

The list contains models that accept the registered camera roles, joint order, and action shape.

## Connect sensors and actuators

Servo accepts a runtime factory from your robot application. A runtime factory is a zero-argument
function that opens and returns the YAM `RobotEnv`:

```python theme={null}
import os

import servo
# Replace with the factory function defined in your robot application:
from my_robot_app import open_yam

sv = servo.Servo(
    base_url=os.environ["SERVO_BASE_URL"],
    api_key=os.environ["SERVO_API_KEY"],
)
robot = sv.robots.attach("yam-cell-01", runtime=open_yam)
```

Each call to `open_yam()` returns a YAM runtime instance implementing three methods:

* `get_obs()`: returns a dictionary containing camera frames and joint positions:
  * `left_rgb`, `front_rgb`, `right_rgb`: 360 × 640 RGB image frames as `numpy.ndarray` (`uint8`); and
  * `joint_positions`: 14 float values in radians (left arm joints 0..5, left gripper, right arm joints 0..5, right gripper).
* `step_command_only(joints)`: applies a 14-value target array in radians to the motor controllers; and
* `close()`: releases the arms, cameras, and communication buses.

A minimal standalone reference implementation looks like:

```python theme={null}
from typing import Any
import numpy as np


class MinimalYamEnv:
    def get_obs(self) -> dict[str, Any]:
        return {
            "left_rgb": np.zeros((360, 640, 3), dtype=np.uint8),
            "front_rgb": np.zeros((360, 640, 3), dtype=np.uint8),
            "right_rgb": np.zeros((360, 640, 3), dtype=np.uint8),
            "joint_positions": np.zeros(14, dtype=np.float32),
        }

    def step_command_only(self, joints: np.ndarray) -> None:
        # Apply validated 14-dim joint target to hardware controllers
        pass

    def close(self) -> None:
        pass


def open_yam() -> MinimalYamEnv:
    return MinimalYamEnv()
```

Servo maps `front_rgb` to the registered `top` camera role, validates all three frames and the
14-value joint state, and passes validated 14-value targets to `step_command_only`. If your runtime
loads local configuration files to configure its motor buses, pass those same files to
`servo robot setup` so Servo can record their configuration fingerprint. Servo never passes files into
the runtime; your robot application owns device discovery, camera role assignment, bus addresses,
and controller setup.

The local controller enforces motor limits and emergency-stop behavior. Servo rejects malformed or
expired action rows and enforces a measured action-jump limit when one exists for the selected
model and robot.

## Calibration

| Concern                                                     | Owner                |
| ----------------------------------------------------------- | -------------------- |
| Motor offsets, limits, and controller setup                 | Robot application    |
| Camera intrinsics, extrinsics, and physical role assignment | Robot application    |
| Calibration procedure and schedule                          | Robot application    |
| Camera names, joint order, units, dimensions, and rate      | Servo robot contract |
| Model input and output validation                           | Servo                |

Calibrate the robot with its normal hardware tools before a Servo run. Servo treats calibration as
a local precondition. Calibration files remain on the robot computer.

## Add a custom robot

Generate a local integration package:

```bash theme={null}
servo robot scaffold lab-arm --output ./lab-arm-servo
cd ./lab-arm-servo
```

The scaffold generates:

* `servo-robot.json`: Starts with type ID `local.lab-arm.v1`. Edit its camera roles, state axes, action axes, units, and control rate, then set `status` to `ready`.
* `integration.py`: Contains `SensorSource` and `ActuatorSink` drivers, plus a `Configuration` Pydantic model defining local settings (such as `port: str`).
* `config.yaml`: Create your local hardware config file containing device settings (for example, `port: /dev/ttyACM0`).

Validate the contract and install the local package:

```bash theme={null}
servo robot validate ./servo-robot.json
pytest
pip install -e .
```

Register the physical robot with the generated manifest:

```bash theme={null}
servo robot setup lab-arm-01 \
  --manifest ./servo-robot.json \
  --config ./config.yaml \
  --region us-west-2
```

`--config` records the cryptographic fingerprint of your local configuration file.

Open the installed integration from the robot application:

```python theme={null}
robot = sv.robots.attach(
    "lab-arm-01",
    manifest="./servo-robot.json",
    configuration={"port": "/dev/ttyACM0"},
)
```

The `configuration` dictionary passed to `sv.robots.attach` is validated against the `Configuration`
schema defined in `integration.py`. Run `sv.models.for_robot(robot)` to list available hosted models.
An empty list means no hosted model matches that robot type yet.
