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

# IMU

> Accelerometer and gyroscope data: retrieval, timestamps, and motion state

The M1 streams IMU samples alongside video on the same transport.
`retrieve_imu()` drains the queued samples in chronological order after a
successful `grab()`. At typical rates, a frame interval contains several IMU
samples.

Leave `InitParameters::enable_imu` enabled, then use a USB or WiFi/UDP data
plane. A control-only Bluetooth LE (BLE) session cannot deliver IMU samples.

```cpp theme={null}
SensorsData sensors;
while (dev.grab() == ERROR_CODE::SUCCESS) {
    if (dev.retrieve_imu(sensors) != ERROR_CODE::SUCCESS) continue;

    for (const ImuSample& s : sensors.samples) {
        // s.acceleration[3]      m/s^2
        // s.angular_velocity[3]  rad/s
        // s.temperature_c        die temperature
        // s.timestamp            device clock, ns
        // s.sequence             monotonic; gaps = wire loss
    }
    if (sensors.motion_state == MOTION_STATE::FALLING) {
        // free-fall detected
    }
}
```

## SensorsData

| Field          | Meaning                                                                            |
| -------------- | ---------------------------------------------------------------------------------- |
| `samples`      | every `ImuSample` since the last drain, in order                                   |
| `dropped`      | ring-overrun count (host consumed too slowly)                                      |
| `motion_state` | `STATIC` / `MOVING` / `FALLING`, classified by the host SDK from the newest sample |

## Timestamps and ordering

Sample timestamps are on the device clock, the same timebase as
`Mat::getTimestamp()`, so associating IMU windows to frames is a direct
comparison. `sequence` increments per sample; a gap means samples were lost
in transit (lossy UDP) or overrun (`dropped`).

`retrieve_imu(data, TIME_REFERENCE::IMAGE)` is the default and returns the
queued batch aligned to the grabbed frame. Samples arriving between calls
queue for the next drain. Passing `TIME_REFERENCE::CURRENT` keeps only the
newest available sample.

`flip_mode` and `coordinate_system` are applied when samples are delivered.
Recordings preserve the raw `IMAGE`-frame data.

## Sensor configuration

Noise densities and the camera↔IMU extrinsic transform ship on the device and
are cached at `open()`:

```cpp theme={null}
SensorsConfiguration sc = dev.get_device_information().sensors_configuration;
// sc.accelerometer.sampling_rate   Hz
// sc.accelerometer.range           +/- g (accel) or +/- deg/s (gyro)
// sc.accelerometer.noise_density
// sc.gyroscope.noise_density
// sc.camera_imu_transform          4x4, camera frame -> IMU frame
```

Read the rate from `sampling_rate` rather than assuming one. The block also
carries the stored field calibration (`accel_bias`, `gyro_bias`, the two 3×3
scale-misalignment matrices, and `time_offset_ns`), which is what
[Calibration](/device/calibration#imu-calibration) writes.

<Note>
  Disable the IMU with `InitParameters::enable_imu = false` when only video is
  required. This removes the IMU packets from the wire entirely.
</Note>
