# IMU

IMU ([inertial measurement unit](https://en.wikipedia.org/wiki/Inertial_measurement_unit)) node can be used to receive data from
the IMU chip on the device. Our OAK devices use either:

 * [BNO085](https://www.ceva-ip.com/product/bno-9-axis-imu/) ([datasheet
   here](https://eu.mouser.com/datasheet/2/1480/BNO080_085_Datasheet-3196201.pdf)) 9-axis sensor, combining accelerometer,
   gyroscope, and magnetometer. It also does sensor fusion on the (IMU) chip itself. We have efficiently integrated [this
   driver](https://github.com/hcrest/bno080-driver) into the DepthAI.
 * [BMI270](https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi270/) 6-axis sensor, combining accelerometer and
   gyroscope.

The IMU chip is connected to the [RVC](https://docs.luxonis.com/hardware/platform/rvc/rvc2.md#rvc2) over SPI. See [OAK Hardware
documentation](https://docs.luxonis.com/hardware.md) to check whether your OAK camera has IMU integrated.

## How to place it

#### Python

```python
pipeline = dai.Pipeline()
imu = pipeline.create(dai.node.IMU)
```

#### C++

```cpp
dai::Pipeline pipeline;
auto imu = pipeline.create<dai::node::IMU>();
```

## Inputs and Outputs

## Limitations

 * For BNO086, gyroscope frequency above 400Hz can produce some jitter from time to time due to sensor HW limitation.

> Please take note that all OAK-D-Lite cameras from Kickstarter do not have an IMU on board.

## IMU sensor frequencies

Below are the discrete stable frequencies available for each (raw) IMU sensor. Some maximum IMU frequencies are higher, eg. for
BNO086, maximum frequency for gyroscope is 1000Hz, but up to 400Hz is stable (due to driver limitation).

BNO086:

Note that BNO IMU "rounds up" the input frequency to the next available frequency. For example, if you set the frequency to 101 it
will round it to 200Hz.

 * Accelerometer: 15Hz, 31Hz, 62Hz, 125Hz, 250Hz 500Hz
 * Gyroscope: 25Hz, 33Hz, 50Hz, 100Hz, 200Hz, 400Hz
 * Magnetometer: 100Hz

BNO086 max frequency:

| BNO086 Sensor | Max Frequency |
| --- | --- |
| ACCELEROMETER_RAW | 512 Hz |
| ACCELEROMETER | 512 Hz |
| LINEAR_ACCELERATION | 400 Hz |
| GRAVITY | 400 Hz |
| GYROSCOPE_RAW | 1000 Hz |
| GYROSCOPE_CALIBRATED / GYROSCOPE_UNCALIBRATED | 100 Hz |
| MAGNETOMETER_RAW | 100 Hz |
| MAGNETOMETER_CALIBRATED / MAGNETOMETER_UNCALIBRATED | 100 Hz |
| ROTATION_VECTOR | 400 Hz |
| GAME_ROTATION_VECTOR | 400 Hz |
| GEOMAGNETIC_ROTATION_VECTOR | 100 Hz |
| ARVR_STABILIZED_ROTATION_VECTOR | 100 Hz |
| ARVR_STABILIZED_GAME_ROTATION_VECTOR | 100 Hz |

BMI270:

Note that BMI270 "rounds down" the input frequency to the next available frequency. For example, if you set the frequency to 99 it
will round it to 50Hz. Additionally, the current max frequency of ~250 Hz is set when the input is >400Hz.

 * Accelerometer: 25Hz, 50Hz, 100Hz, 200Hz, 250Hz
 * Gyroscope: 25Hz, 50Hz, 100Hz, 200Hz, 250Hz

## Usage

#### Python

```python
pipeline = dai.Pipeline()
imu = pipeline.create(dai.node.IMU)

# enable ACCELEROMETER_RAW and GYROSCOPE_RAW at 100 hz rate
imu.enableIMUSensor([dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 100)
# above this threshold packets will be sent in batch of X, if the host is not blocked and USB bandwidth is available
imu.setBatchReportThreshold(1)
# maximum number of IMU packets in a batch, if it's reached device will block sending until host can receive it
# if lower or equal to batchReportThreshold then the sending is always blocking on device
# useful to reduce device's CPU load  and number of lost packets, if CPU load is high on device side due to multiple nodes
imu.setMaxBatchReports(10)
```

#### C++

```cpp
dai::Pipeline pipeline;
auto imu = pipeline.create<dai::node::IMU>();

// enable ACCELEROMETER_RAW and GYROSCOPE_RAW at 100 hz rate
imu->enableIMUSensor({dai::IMUSensor::ACCELEROMETER_RAW, dai::IMUSensor::GYROSCOPE_RAW}, 100);
// above this threshold packets will be sent in batch of X, if the host is not blocked and USB bandwidth is available
imu->setBatchReportThreshold(1);
// maximum number of IMU packets in a batch, if it's reached device will block sending until host can receive it
// if lower or equal to batchReportThreshold then the sending is always blocking on device
// useful to reduce device's CPU load  and number of lost packets, if CPU load is high on device side due to multiple nodes
imu->setMaxBatchReports(10);
```

## IMU sensors

When enabling the IMU sensors (imu.enableIMUSensor()), you can select between the following sensors:

 * ACCELEROMETER_RAW
 * ACCELEROMETER
 * LINEAR_ACCELERATION
 * GRAVITY
 * GYROSCOPE_RAW
 * GYROSCOPE_CALIBRATED
 * GYROSCOPE_UNCALIBRATED
 * MAGNETOMETER_RAW
 * MAGNETOMETER_CALIBRATED
 * MAGNETOMETER_UNCALIBRATED
 * ROTATION_VECTOR
 * GAME_ROTATION_VECTOR
 * GEOMAGNETIC_ROTATION_VECTOR
 * ARVR_STABILIZED_ROTATION_VECTOR
 * ARVR_STABILIZED_GAME_ROTATION_VECTOR

Here are descriptions of all sensors:

### depthai.IMUSensor

Kind: Class

Available IMU sensors. More details about each sensor can be found in the
datasheet:

https://www.ceva-dsp.com/wp-content/uploads/2019/10/BNO080_085-Datasheet.pdf

Members:

ACCELEROMETER_RAW : Section 2.1.1

Acceleration of the device without any postprocessing, straight from the sensor.
Units are [m/s^2]

ACCELEROMETER : Section 2.1.1

Acceleration of the device including gravity. Units are [m/s^2]

LINEAR_ACCELERATION : Section 2.1.1

Acceleration of the device with gravity removed. Units are [m/s^2]

GRAVITY : Section 2.1.1

Gravity. Units are [m/s^2]

GYROSCOPE_RAW : Section 2.1.2

The angular velocity of the device without any postprocessing, straight from the
sensor. Units are [rad/s]

GYROSCOPE_CALIBRATED : Section 2.1.2

The angular velocity of the device. Units are [rad/s]

GYROSCOPE_UNCALIBRATED : Section 2.1.2

Angular velocity without bias compensation. Units are [rad/s]

MAGNETOMETER_RAW : Section 2.1.3

Magnetic field measurement without any postprocessing, straight from the sensor.
Units are [uTesla]

MAGNETOMETER_CALIBRATED : Section 2.1.3

The fully calibrated magnetic field measurement. Units are [uTesla]

MAGNETOMETER_UNCALIBRATED : Section 2.1.3

The magnetic field measurement without hard-iron offset applied. Units are
[uTesla]

ROTATION_VECTOR : Section 2.2

The rotation vector provides an orientation output that is expressed as a
quaternion referenced to magnetic north and gravity. It is produced by fusing
the outputs of the accelerometer, gyroscope and magnetometer. The rotation
vector is the most accurate orientation estimate available. The magnetometer
provides correction in yaw to reduce drift and the gyroscope enables the most
responsive performance.

GAME_ROTATION_VECTOR : Section 2.2

The game rotation vector is an orientation output that is expressed as a
quaternion with no specific reference for heading, while roll and pitch are
referenced against gravity. It is produced by fusing the outputs of the
accelerometer and the gyroscope (i.e. no magnetometer). The game rotation vector
does not use the magnetometer to correct the gyroscopes drift in yaw. This is a
deliberate omission (as specified by Google) to allow gaming applications to use
a smoother representation of the orientation without the jumps that an
instantaneous correction provided by a magnetic field update could provide. Long
term the output will likely drift in yaw due to the characteristics of
gyroscopes, but this is seen as preferable for this output versus a corrected
output.

GEOMAGNETIC_ROTATION_VECTOR : Section 2.2

The geomagnetic rotation vector is an orientation output that is expressed as a
quaternion referenced to magnetic north and gravity. It is produced by fusing
the outputs of the accelerometer and magnetometer. The gyroscope is specifically
excluded in order to produce a rotation vector output using less power than is
required to produce the rotation vector of section 2.2.4. The consequences of
removing the gyroscope are: Less responsive output since the highly dynamic
outputs of the gyroscope are not used More errors in the presence of varying
magnetic fields.

ARVR_STABILIZED_ROTATION_VECTOR : Section 2.2

Estimates of the magnetic field and the roll/pitch of the device can create a
potential correction in the rotation vector produced. For applications
(typically augmented or virtual reality applications) where a sudden jump can be
disturbing, the output is adjusted to prevent these jumps in a manner that takes
account of the velocity of the sensor system.

ARVR_STABILIZED_GAME_ROTATION_VECTOR : Section 2.2

While the magnetometer is removed from the calculation of the game rotation
vector, the accelerometer itself can create a potential correction in the
rotation vector produced (i.e. the estimate of gravity changes). For
applications (typically augmented or virtual reality applications) where a
sudden jump can be disturbing, the output is adjusted to prevent these jumps in
a manner that takes account of the velocity of the sensor system. This process
is called AR/VR stabilization.

#### ACCELEROMETER: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### ACCELEROMETER_RAW: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### ARVR_STABILIZED_GAME_ROTATION_VECTOR: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### ARVR_STABILIZED_ROTATION_VECTOR: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### GAME_ROTATION_VECTOR: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### GEOMAGNETIC_ROTATION_VECTOR: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### GRAVITY: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### GYROSCOPE_CALIBRATED: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### GYROSCOPE_RAW: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### GYROSCOPE_UNCALIBRATED: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### LINEAR_ACCELERATION: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### MAGNETOMETER_CALIBRATED: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### MAGNETOMETER_RAW: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### MAGNETOMETER_UNCALIBRATED: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### ROTATION_VECTOR: typing.ClassVar[IMUSensor]

Kind: Class Variable

#### __members__: typing.ClassVar[dict[str, IMUSensor]]

Kind: Class Variable

#### __eq__(self, other: typing.Any) -> bool: bool

Kind: Method

#### __getstate__(self) -> int: int

Kind: Method

#### __hash__(self) -> int: int

Kind: Method

#### __index__(self) -> int: int

Kind: Method

#### __init__(self, value: typing.SupportsInt)

Kind: Method

#### __int__(self) -> int: int

Kind: Method

#### __ne__(self, other: typing.Any) -> bool: bool

Kind: Method

#### __repr__(self) -> str: str

Kind: Method

#### __setstate__(self, state: typing.SupportsInt)

Kind: Method

#### __str__(self) -> str: str

Kind: Method

#### name

Kind: Property

#### value

Kind: Property

## Examples of functionality

 * [IMU Accelerometer & Gyroscope](https://docs.luxonis.com/software/depthai/examples/imu_accelerometer_gyroscope.md)
 * [IMU Rotation Vector](https://docs.luxonis.com/software/depthai/examples/imu_rotation_vector.md)

## Reference

### depthai.node.IMU(depthai.Node)

Kind: Class

IMU node for BNO08X.

#### enableFirmwareUpdate(self, arg0: bool)

Kind: Method

#### enableIMUSensor()

Kind: Method

#### getBatchReportThreshold(self) -> int: int

Kind: Method

Above this packet threshold data will be sent to host, if queue is not blocked

#### getMaxBatchReports(self) -> int: int

Kind: Method

Maximum number of IMU packets in a batch report

#### setBatchReportThreshold(self, batchReportThreshold: typing.SupportsInt)

Kind: Method

Above this packet threshold data will be sent to host, if queue is not blocked

#### setMaxBatchReports(self, maxBatchReports: typing.SupportsInt)

Kind: Method

Maximum number of IMU packets in a batch report

#### out

Kind: Property

Outputs IMUData message that carries IMU packets.

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
