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

# Signals

> Any named time series: declaration, types, wire format, units and recognised names.

A **signal** is one named, typed, timestamped series: vehicle speed, a joint-angle vector, a
gripper opening, a heart rate, a turn-signal state. Signal names are free. There is no registry
and no approval: declare `heart_rate` and it is ingested.

## Declaration

Each signal is one entry in the overlay's `signals` array:

```json theme={null}
{"channel": "/sig/speed", "name": "speed", "type": "float", "unit": "m/s", "rate_hz": 50}
```

| Field | Type | Required | Rule |
| - | - | - | - |
| `channel` | string | yes | The channel carrying the samples. One channel carries exactly one signal. |
| `name` | string | yes | Free, non-empty, unique in the recording. Parts reference signals by this name. |
| `type` | string | yes | One of `bool`, `int`, `float`, `string`, `enum`, `vector`. |
| `unit` | string | no | The unit of the values. See [Units](#units). |
| `dim` | integer | `vector` only | The vector length, ≥ 1. MUST be present for a `vector` and MUST NOT be present otherwise. |
| `components` | array of strings | no | Per-axis labels for a `vector`, exactly `dim` entries. SHOULD be declared. |
| `values` | array | `enum` only | The permitted values, non-empty. |
| `rate_hz` | number | no | The nominal sample rate, > 0. Used for sanity checks only, never for resampling; an observed rate more than 20% off is warned. |
| `note` | string | no | Free text, e.g. what the signal measures or where its unit comes from. |

The `type` set is closed on purpose: it is what lets any name work.

## Wire format

Signal channels carry **`nomadic.Signal`** protobuf messages, **one message per sample**:

```proto theme={null}
message Signal {
  google.protobuf.Timestamp timestamp = 1;
  oneof value {
    double number = 2;   // float / int
    bool flag = 3;       // bool
    string text = 4;     // string / enum
    Vector vector = 5;   // vector
  }
}
message Vector { repeated double values = 1; }
```

| Declared `type` | Set field |
| - | - |
| `float`, `int` | `number` |
| `bool` | `flag` |
| `string`, `enum` | `text` (for `enum`, one of the declared `values`; others are warned) |
| `vector` | `vector.values`, exactly `dim` numbers in `components` order |

* Each message is one timestamp and one value. Do not batch samples into arrays: one value per
  message is what lets the same file plot directly in Foxglove (numeric signals in the Plot panel,
  categorical ones in State Transitions). MCAP chunk compression absorbs the overhead.
* The sample time is the message's MCAP `log_time`. See
  [Clock](/mcap-spec/recording#clock).
* The signal's name, type and unit come from the overlay, never from the message.

The full `.proto` files are on the [Schemas](/mcap-spec/schemas) page.

## Units

* `unit` is a free-form string, **not converted** for you. SI is strongly recommended.
* Where a [profile](#profiles) or a [part slot](/mcap-spec/body-and-parts#slots) specifies a unit,
  that exact unit string is required.
* If your source does not document a unit, **omit `unit`** and say so in `note`. An invented unit
  is worse than an absent one, because it will be believed.

## Orientation

Publish orientation as **derived angles**, `yaw`, `pitch` and `roll` in `rad`, rather than raw
quaternion components. A series of `q[2]` is meaningless to a reader. Full poses belong in
`foxglove.PoseInFrame` messages (see [Frames, poses and units](/mcap-spec/frames-and-units)).

## Recognised names

Any name is accepted. These names have a defined meaning; when you have the quantity, use the name.

### Vehicle

| Name | Type | Unit | Meaning |
| - | - | - | - |
| `speed` | `float` | `m/s` (also accepted: `km/h`, `mph`) | ground speed |
| `accelx`, `accely`, `accelz` | `float` | `m/s^2` (also accepted: `g`) | acceleration along x, y, z of the `vehicle` frame |
| `gyroz` | `float` | `rad/s` (also accepted: `deg/s`) | yaw rate |
| `roll`, `pitch`, `yaw` | `float` | `rad` (also accepted: `deg`) | attitude |
| `brake_pressed`, `gas_pressed` | `bool` | | pedal state |
| `steering_angle_deg` | `float` | `deg` | the commanded or model steering angle, not the measured wheel angle |
| `steering_torque` | `float` | | steering torque |
| `adas_engaged` | `bool` | | driver assistance engaged |
| `lead_dist_m` | `float` | `m` | distance to the lead vehicle |
| `lead_rel_speed_mps` | `float` | `m/s` | speed relative to the lead vehicle |
| `a_target_mps2` | `float` | `m/s^2` | the planner's target acceleration |
| `lane_prob_left`, `lane_prob_right` | `float` | | lane-line confidence, 0 to 1 |

Publish every other vehicle-bus signal too (steering-wheel angle, brake pressure, gear, turn
signals, wheel speeds) under any name, with its unit.

### Navigation instructions

An instruction that changes during the recording, such as turn-by-turn navigation, is a `string`
signal named **`navigation_instruction`** (or an `enum` when the instructions come from a fixed
set), with one message whenever the instruction changes:

```json theme={null}
{"channel": "/sig/navigation_instruction", "name": "navigation_instruction", "type": "string"}
```

An empty `text` ends the current instruction. One instruction for the whole recording goes in
[`recording.task`](/mcap-spec/recording#task) instead.

### Machines and robots

* Publish machine joint angles and operator commands of heavy equipment as ordinary signals, each
  with its unit and a `note` saying which it is. A joystick command is not a joint angle.
* Publish all robot proprioception that no [part slot](/mcap-spec/body-and-parts#slots) covers
  (commanded joints, joint velocities, motor torques, battery state) as ordinary signals.

## Profiles

A **profile**, declared in the top-level `profile` field, fixes the names and units of a set of
signals so they can be interpreted, not just stored. Profiles are opt-in. Signals outside the
profile stay generic, and an unrecognised profile is ignored. Declare a profile only if your source
can honestly fill its required fields.

| Profile | Body | Fields |
| - | - | - |
| `nomadic.driving.v1` | `vehicle` | scalar `float` kinematics, below |
| `nomadic.yam_bimanual.v1` | `manipulator` (1.0: `robot_arm`) | two arms by signal-name prefix (spec 1.0). Superseded by `parts` in 1.1. |

### `nomadic.driving.v1`

Scalar `float` signals with these names and **exactly** these `unit` strings (compared
case-insensitively; `m/s²`, `rad/sec`, `deg/s` and `km/h` do not match):

| Fields | Unit |
| - | - |
| `speed`, `vx`, `vy`, `vz` | `m/s` |
| `accelx`, `accely`, `accelz` | `m/s^2` |
| `gyrox`, `gyroy`, `gyroz` | `rad/s` |
| `roll`, `pitch`, `yaw` | `rad` |

`speed` and `gyroz` are required. Every other field is optional and is used when its unit matches
and it covers the same time span as `speed` and `gyroz`.

## Spec 1.0 arm signals

Before parts, spec 1.0 described a robot arm by signal names. They remain valid in 1.0 overlays:

| Name | Type | Unit | Meaning |
| - | - | - | - |
| `joint_positions` | `vector`, `dim` = joint count | `rad` | measured joint angles, in the robot's joint order |
| `ee_x`, `ee_y`, `ee_z` | `float` | `m` | end-effector position in the robot base frame |
| `gripper_position` | `float` | none, or documented in `note` | gripper state |

For two arms, declare `profile: "nomadic.yam_bimanual.v1"` and prefix every name with the side:
`left_joint_positions`, `left_ee_x`, …, `right_gripper_position`.

In a 1.1 overlay, declare [parts](/mcap-spec/body-and-parts#parts) instead. Once parts are declared,
these names and the bimanual profile have no further meaning, and preflight warns where you still
use them.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.