> Documentation index: https://nao-rs.lukaloehr.com/llms.txt, a list of every page in this documentation.

# Robot API

> The TCP API on port 7700 that the brain and other clients use today - framing, handshake, heartbeat and watchdog, every message and its fields.

`hulk` serves one API on **TCP port 7700**, on every network interface of the
robot. A client (the "brain" on a computer, the simulator app, your own
program) connects, says hello, subscribes to what it wants and sends commands.
The message types are defined in the `nao_rs_api` crate; a client in another
language needs only TCP and MessagePack.

> **Warning:** No authentication
>
> Anyone who can reach port 7700 can control the robot. Use it only on a network
> you trust. Authentication for this API is **planned**. The [REST
> API](https://nao-rs.lukaloehr.com/reference/rest-api.md) on port 7702 already needs a token and answers the
> local network only. The death switch doesn't depend on this API: the UDP stop
> and `naoctl` work without it.

## Framing

Each message is one frame: a big-endian `u32` byte count, then one MessagePack
value encoded **with field names**. Frames above 8 MiB are rejected.

Enums are externally tagged, as `rmp-serde` writes them:

| Rust | MessagePack, shown as JSON |
| --- | --- |
| `ToRobot::Heartbeat` (unit variant) | `"Heartbeat"` |
| `ToRobot::Power(Power::Wake)` (newtype variant) | `{"Power": "Wake"}` |
| `ToRobot::Hello { version: 1, client: "me" }` (struct variant) | `{"Hello": {"version": 1, "client": "me"}}` |
| `Option` | the value, or `nil` |
| `Rgb(255, 0, 0)` | `[255, 0, 0]` |
| JPEG bytes | MessagePack `bin` |

## Connection

1. **Hello.** Within 2 seconds of connecting, send
   `{"Hello": {"version": 1, "client": "<your name>"}}`. The robot answers
   `{"Hello": {"version": 1, "robot": {"body_id", "head_id", "simulated"}}}`
   and closes the connection if the versions differ.
2. **One controller at a time.** A new connection replaces the previous
   client, and its subscription starts empty.
3. **Heartbeat.** Send something at least every **100 ms**; `"Heartbeat"` is
   enough. When the client goes quiet, the watchdog takes over: after
   **0.5 s** the robot stands still, after **3 s** it sits down. A `Watchdog`
   event reports both changes.

## To the robot

| Message | Fields | Effect |
| --- | --- | --- |
| `Hello` | `version: u32`, `client: string` | Handshake (first message only) |
| `Heartbeat` | none | Keeps the watchdog quiet |
| `Power` | `"Wake"` or `"Rest"` | Stiff and ready, or limp |
| `Motion` | see below | What the body does until the next command; falling and getting up always win |
| `Leds` | `Leds` or `nil` | Overrides LED groups; `nil` hands all of them back. See [LEDs](https://nao-rs.lukaloehr.com/hardware/leds.md) |
| `Speaker` | `samples: [i16]` | Mono 16-bit PCM at 16 kHz, queued and played back to back |
| `SpeakerClear` | none | Drops the queued audio |
| `Volume` | `percent: u8?` (0 to 100, larger is clamped), `muted: bool?` | Speaker volume. Fields left out keep their value; a percent above 0 also unmutes unless `muted` is given. Changes only the mixer, so it never pops. Not persistent: every boot starts at 65 % |
| `Subscribe` | `state: bool`, `cameras: ["Top" \\| "Bottom"]`, `camera_fps: f32`, `microphone: bool` | Which streams the robot sends |
| `Stop` | none | **Death switch.** All motors off, latched until re-armed on the robot. The robot writes the switch page directly (reason `Api`) and also sends the guard's UDP stop, so it works even when the motion code is stuck or the guard is gone |

> **Info:** Motors on nao-rs
>
> `Power` and `Motion` act through `hulk`'s motion code. On nao-rs the motor
> boards are not accepted yet (**planned**), so these commands change `hulk`'s
> state but no joint moves.

### Motion

| Variant | Fields | Meaning |
| --- | --- | --- |
| `Stand` | `head` | Stand still |
| `WalkTo` | `x`, `y` (m; x forward, y left), `turn_to` (rad, left positive, or `nil`), `speed`, `head` | Walk to a point relative to the robot, then stop there |
| `WalkToward` | `x`, `y`, `speed`, `head` | Keep walking toward a point that stays at this offset, like a joystick: `(1, 0)` straight on, `(0.5, 0.5)` a circle, `(0.02, 0.5)` turning on the spot. Send it again to steer, `Stand` to stop |
| `SitDown` | none | Sit down |
| `ArmsUp` | none | Arms up |
| `Squat` | none | Squat |

`speed` is `"Slow"`, `"Normal"` or `"Fast"`. `head` is `"Center"`,
`"LookAround"` or `{"LookAt": {"x", "y"}}` (a point on the ground relative to
the robot, in metres).

### Leds

All fields are optional; a field set to `nil` keeps the robot's own status
for that group.

| Field | Type |
| --- | --- |
| `left_eye`, `right_eye` | 8 × `Rgb`: segment 0 at the top, then clockwise as seen from the front |
| `left_ear`, `right_ear` | 10 × `f32`, brightness 0..1 |
| `chest`, `left_foot`, `right_foot` | `Rgb` |

## From the robot

| Message | Fields | When |
| --- | --- | --- |
| `Hello` | `version`, `robot: {body_id, head_id, simulated, echo_cancellation}` | Answer to the client's hello. `simulated` is true in Webots, which has no microphones or speakers. `echo_cancellation` is true when the robot removes its own voice from the microphones, so a client can keep listening while it speaks; false (the default) means the robot's microphones are muted while it speaks ([Its own voice](https://nao-rs.lukaloehr.com/brain.md#its-own-voice)) |
| `State` | see below | At 20 Hz while subscribed |
| `Event` | `Touch {sensor, pressed}`, `Fall {state}`, `Watchdog {active}` | When it happens |
| `Image` | `camera`, `time` (s since the Unix epoch), `width`, `height`, `jpeg` | Per subscribed camera, throttled to `camera_fps` |
| `Microphone` | `time`, `samples: [i16]` | Mono 16-bit PCM at 16 kHz, all four microphones mixed |

### State

| Field | Content |
| --- | --- |
| `time` | Seconds since the Unix epoch |
| `primary_state` | `Unstiff`, `Animation`, `Initial`, `Playing` or `Finished` |
| `fall_state` | `Upright`, `Falling`, `Fallen`, `StandingUp` or `Sitting` |
| `motion` | The motion being executed: `Stand`, `Walk`, `SitDown`, `StandUpFront`, … |
| `battery` | `charge`, `current`, `temperature`, `charging` |
| `imu` | `linear_acceleration`, `angular_velocity`, `roll_pitch` |
| `sonar` | Distance to the nearest obstacle, left and right |
| `left_foot_pressure`, `right_foot_pressure` | 4 values each |
| `touch` | `chest_button`, `head_front`, `head_middle`, `head_rear`, `left_hand`, `right_hand`, `left_foot`, `right_foot` |
| `joint_positions`, `joint_temperatures`, `joint_currents` | 26 values each, in the order below |

Units are on [Body sensors and units](https://nao-rs.lukaloehr.com/hardware/sensors.md#the-robot-apis-units).

Joint order: `head_yaw`, `head_pitch`, `left_shoulder_pitch`,
`left_shoulder_roll`, `left_elbow_yaw`, `left_elbow_roll`, `left_wrist_yaw`,
`left_hand`, `right_shoulder_pitch`, `right_shoulder_roll`, `right_elbow_yaw`,
`right_elbow_roll`, `right_wrist_yaw`, `right_hand`, `left_hip_yaw_pitch`,
`left_hip_roll`, `left_hip_pitch`, `left_knee_pitch`, `left_ankle_pitch`,
`left_ankle_roll`, `right_hip_yaw_pitch`, `right_hip_roll`,
`right_hip_pitch`, `right_knee_pitch`, `right_ankle_pitch`,
`right_ankle_roll`. The NAO's two hip yaw-pitch joints share one motor.

## The Rust client

`nao_rs_api::client::Client` handles framing, the handshake and the
heartbeat:

```text
use nao_rs_api::{client::Client, Head, Motion, Power, Speed, Subscription, ToRobot};

let robot = Client::connect("nao.local:7700", "my-brain")?;
robot.send(&ToRobot::Subscribe(Subscription { state: true, ..Default::default() }))?;
robot.send(&ToRobot::Power(Power::Wake))?;
robot.send(&ToRobot::Motion(Motion::WalkTo {
    x: 1.0, y: 0.0, turn_to: None, speed: Speed::Normal, head: Head::Center,
}))?;
println!("{:?}", robot.state().map(|state| state.battery));
```

## Security

Today's API binds all interfaces and has no authentication or encryption.
The REST API's [security table](https://nao-rs.lukaloehr.com/reference/rest-api.md#security) lists what
exists and what is planned for both APIs.

## Related topics

- [Reference](https://nao-rs.lukaloehr.com/reference.md)
- [Command-line tools](https://nao-rs.lukaloehr.com/reference/cli.md)
- Previous: [Schemas](https://nao-rs.lukaloehr.com/reference/rest-api/schemas.md)
- Next: [Command-line tools](https://nao-rs.lukaloehr.com/reference/cli.md)
