Skip to content

IMU Orientation

GOB edited this page Oct 26, 2026 · 1 revision

IMU orientation

Axis-orientation reference images for M5Stack IMU units and for the hosts with a built-in IMU. Use them to set the correct axis remap (ahrs.writeAxisOrder / m5::imu::presets::*).

Raw chip axes and corrected axes

  • Raw chip axes: what the unit drivers (UnitBMI270, UnitMPU6886, UnitBMM150, ...) return -- the IMU chip's own axes, as mounted on the board.
  • Corrected axes: what AhrsController uses after a preset (m5::imu::presets::<board>()) is applied. The board presets apply the same per-board correction as M5Unified, so for a built-in IMU these are also the axes M5.Imu returns.

Where the two differ, both are shown side by side. Elsewhere one image is shown: no correction is applied and the raw chip axes are used as they are.

Notes

  • Several classic hosts (Gray, Fire, the original StickC) shipped earlier IMU generations (MPU6050 + MAG3110, MPU9250 + AK8963, SH200Q + BMM150) that the current product pages no longer illustrate. Those revisions are listed below text-only (no orientation image); their axis remap must be confirmed on the original hardware before a preset is committed.
  • Some hosts changed their IMU chip across hardware revisions without changing what M5.getBoard() reports (Core2 v1.1 MPU6886 → v1.3 BMI270; ATOM Matrix → v1.1 BMI270). AhrsDemo probes the internal bus (m5::unit::imu::detectBuiltinImu) to pick the accel/gyro driver, while the axis remap is still selected by board (the mounting orientation is a board property).
  • Images are © M5Stack.

Units (external, GROVE)

UnitMiniIMU (U095) — MPU6886 (0x68)

UnitMiniIMU orientation

Source

Unit Mini IMU-Pro (U171) — BMI270 (0x68) + BMM150 (0x10) + BMP280 (0x76)

The predecessor of the DoF series: BMI270 + BMM150 + BMP280 directly on the GROVE main bus (driver: UnitMiniIMUPro composite). Pressure is read directly via UnitMiniIMUPro::baro() (not part of the attitude AHRS; the UnitBMP280 driver comes from M5Unit-ENV).

Unit Mini IMU-Pro orientation

Source

Unit DoF6 (U228) — BMI270 (0x68)

The axis mark printed on the label shows the BMI270 axes: with the label facing up and the GROVE connector nearest to you, +X points right, +Y away from the connector, +Z up out of the label face. No preset is needed.

No correction: the raw chip axes are used as they are.

Unit DoF6 orientation

Source

Unit DoF9 / DoF10 (U229 / U230) — BMI270 (0x68) + BMM350 (0x14)

DoF9 and DoF10 share DoF6's PCB layout: the label mark (BMI270 axes) is the same, and the BMI270 needs no correction. The BMM350 is mounted rotated 180 degrees about X -- its own axes are X right, Y toward the GROVE connector, Z down (the same mounting as Unit BMM350). m5::imu::presets::unitDoF() corrects it to the BMI270's axes.

BMI270 (accel/gyro): No correction: the raw chip axes are used as they are.

Unit DoF9 orientation

BMM350 (magnetometer):

Raw chip axes Corrected axes (presets::unitDoF())
Unit DoF9 BMM350 raw axes Unit DoF9 BMM350 corrected axes

Source DoF9 · Source DoF10

Unit BMM350 (U231) — BMM350 (0x14)

A standalone magnetometer, typically paired with a UnitMiniIMU for 9-axis. The label mark shows the BMM350's own axes: X right, Y toward the GROVE connector, Z down -- rotated 180 degrees about X relative to the unit's frame. m5::imu::presets::unitBMM350() corrects it (body = (mag_x, -mag_y, -mag_z)), and AhrsDemo calls that preset. Orient this unit the same way as its accel/gyro partner (label up, GROVE connector nearest, +X right); a UnitMiniIMU partner needs no correction of its own.

Raw chip axes Corrected axes (presets::unitBMM350())
Unit BMM350 raw axes Unit BMM350 corrected axes

Source

Built-in hosts

Core2 — MPU6886 (0x68)

No correction: the raw chip axes are used as they are.

Core2 IMU orientation

Source

Core2 for AWS — MPU6886 (0x68)

No correction: the raw chip axes are used as they are.

Core2 for AWS IMU orientation

Source

Core2 v1.1 — MPU6886 (0x68)

No correction: the raw chip axes are used as they are.

Core2 v1.1 IMU orientation

Source

Core2 v1.3 — BMI270 (0x68)

Note: v1.3 switched the IMU from MPU6886 to a 6-axis BMI270 (still no magnetometer).

No correction: the raw chip axes are used as they are.

Core2 v1.3 IMU orientation

Source

Station — MPU6886 (0x68)

6-axis MPU6886 (no magnetometer). M5Unified applies no axis correction (identity remap).

No correction: the raw chip axes are used as they are.

M5Station IMU orientation

Source

CoreS3 / CoreS3-Lite — BMI270 (0x69) + BMM150 (0x10, AUX)

No correction for accel/gyro. presets::coreS3() inverts the AUX BMM150's Y and Z (the magnetometer axes are not drawn).

CoreS3 IMU orientation

Source

Fire — MPU6886 (0x68) + BMM150 (0x10)

Applies to the 2019.8–2021.7 generation. From v2.6 (2021.8) the BMM150 magnetometer was removed; v2.6/v2.7 are 6-axis MPU6886 only (see below).

Same layout as Gray.

Raw chip axes

Fire raw chip axes

Corrected axes (presets::m5stackCoreFire(), same as M5Unified)

Fire AhrsController axes

Source

Fire v2.6 / v2.7 — MPU6886 (0x68), 6-axis only (no magnetometer)

v2.6 (2021.8) removed the BMM150; v2.6 and v2.7 share the same 6-axis MPU6886 configuration (the v2.6 page has no orientation image, so the v2.7 diagram applies to both).

No correction: the raw chip axes are used as they are.

Fire v2.6/v2.7 IMU orientation

Source

Fire — early revisions (no orientation image)

The diagrams above cover the 2019.8+ MPU6886 generation. Earlier Fire hardware used different chips and the current product page carries no orientation diagram for them:

  • original (≤ 2019.6) — MPU9250 (0x68, WHO_AM_I 0x71) + internal AK8963 (0x0C, reached via the MPU9250 aux bypass). Driver: UnitMPU9250 composite (its mag() is the AK8963). Same generation as the 2017.12–2019.6 Gray.
  • 2019.7 — SH200Q (0x6C) + BMM150 (0x10). Driver: UnitSH200Q + UnitBMM150.

Axis remap for both is unverified (no image, no M5Unified reference table); confirm on original hardware before committing a preset.

Gray — MPU6886 (0x68) + BMM150 (0x10)

The MPU6886 needs no correction: X right, Y away from the A/B/C buttons, Z up out of the screen. The BMM150 gets X and Z inverted, so its corrected axes match the MPU6886's.

Raw chip axes

Gray raw chip axes

Corrected axes (presets::m5stackCoreFire(), same as M5Unified)

Gray AhrsController axes

Source

Gray — early revisions (no orientation image)

The diagram above is the 2019.6+ MPU6886 + BMM150 layout. Per the Gray update history, earlier Gray hardware used different chips, for which the current product page carries no orientation diagram:

  • 2017 (original) — MPU6050 (0x68) + MAG3110 (0x0E). Two separate chips on the internal bus (no aux bypass). Driver: UnitMPU6050 + UnitMAG3110.
  • 2017.12 – 2019.6 — MPU9250 (0x68, WHO_AM_I 0x71) + internal AK8963 (0x0C via the MPU9250 aux bypass). Driver: UnitMPU9250 composite. Same generation as the original Fire.

Axis remap for both is unverified; confirm on original hardware before committing a preset.

AtomMatrix — MPU6886 (0x68); v1.1 — BMI270 (0x68)

Note: ATOM Matrix v1.1 switched the IMU from MPU6886 to a 6-axis BMI270 (still no magnetometer, same 0x68 address and same mounting orientation, so the axis remap is unchanged across the swap). Because M5.getBoard() cannot tell the generations apart, AhrsDemo probes the chip on the internal bus (m5::unit::imu::detectBuiltinImu) to construct the right driver.

presets::atomMatrix() inverts X and Z, as M5Unified does. Checked on an MPU6886 unit; v1.1 (BMI270) is assumed to be the same.

Raw chip axes Corrected axes (presets::atomMatrix(), same as M5Unified)
AtomMatrix raw chip axes AtomMatrix AhrsController axes

Source · v1.1

AtomS3 — MPU6886 (0x68)

No correction: the raw chip axes are used as they are.

AtomS3 IMU orientation

Source

AtomS3R (+CAM/Ext/M12) — BMI270 (0x68)

presets::atomS3R() swaps X/Y and inverts Y for accel/gyro, as M5Unified does. (The AUX BMM150 gets its own X/Z inversion; it is not drawn.)

Raw chip axes Corrected axes (presets::atomS3R(), same as M5Unified)
AtomS3R raw chip axes AtomS3R AhrsController axes

Source

StickC (original) — SH200Q (0x6C) → MPU6886 (0x68) (no orientation image)

The original M5StickC changed its IMU across production runs; the current product page shows no per-generation orientation diagram:

  • 2019.3 — SH200Q (0x6C). Driver: UnitSH200Q.
  • 2019.8+ — MPU6886 (0x68). Driver: UnitMPU6886.

Axis remap for the SH200Q generation is unverified -- field reports even suggest its accel and gyro axis systems may not agree with each other, so it stays at identity until confirmed on 2019 hardware. (StickC-Plus / StickC-Plus2 below are MPU6886 throughout.)

StickC-Plus — MPU6886 (0x68)

No correction: the raw chip axes are used as they are.

StickC-Plus IMU orientation

Source

StickC-Plus2 — MPU6886 (0x68)

No correction: the raw chip axes are used as they are.

StickC-Plus2 IMU orientation

Source

StickS3 — BMI270 (0x68)

presets::stickS3() swaps X/Y and inverts Y, as M5Unified does.

Raw chip axes Corrected axes (presets::stickS3(), same as M5Unified)
StickS3 raw chip axes StickS3 AhrsController axes

Source

Capsule — BMI270 (0x69)

No correction: the raw chip axes are used as they are.

Capsule IMU orientation

Source

Cardputer-Adv — BMI270 (0x68)

6-axis BMI270 (no magnetometer). M5Unified applies no axis correction (identity remap).

No correction: the raw chip axes are used as they are.

Cardputer-Adv IMU orientation

Source

PaperS3 — BMI270 (0x68)

No correction: the raw chip axes are used as they are.

PaperS3 IMU orientation

Source

Nesso N1 (Arduino) — BMI270 (0x68)

ESP32-C6 host; 6-axis BMI270 on the internal system bus (no magnetometer). M5Unified applies no axis correction on the C6, so AhrsDemo uses the identity remap (the BMI270 default path). The product page has no dedicated IMU-orientation diagram.

Source

Tab5 — BMI270 (0x68)

ESP32-P4 host; 6-axis BMI270 on the internal system bus (no magnetometer). M5Unified applies no axis correction on the P4, so AhrsDemo uses the identity remap. Note that +Z points out of the back, not out of the screen.

No correction: the raw chip axes are used as they are.

Tab5 IMU orientation

Source