Skip to content

IMU (Inertial Measurement Unit)

Try it in Lab 04

Use the gyroscope for precise turns by integrating angular velocity to track heading. Learn about bias, drift, and calibration. → Precise Turns tutorial

The robot includes a BMI160 IMU that measures acceleration and rotation — the same principle used in smartphones, drones, and vehicle stability systems.


What's Inside an IMU?

An IMU typically contains:

Sensor Measures Units Use Case
Accelerometer Linear acceleration (3-axis) g or m/s² Tilt, vibration, impact
Gyroscope Angular velocity (3-axis) °/s or rad/s Rotation, heading
Magnetometer Magnetic field (3-axis) µT Compass heading

Your BMI160 has accelerometer + gyroscope. No magnetometer.


How MEMS Sensors Work

Accelerometer (Capacitive)

        ┌─────────────────────────┐
        │    Fixed electrodes     │
        │  ═══════   ═══════      │
        │     ║         ║         │
        │  ───╫─────────╫───      │ ← Proof mass (moves)
        │     ║         ║         │
        │  ═══════   ═══════      │
        │    Fixed electrodes     │
        └─────────────────────────┘

At rest: Equal capacitance on both sides
Accelerating: Mass shifts → capacitance changes → voltage output

The "proof mass" is a tiny silicon structure (micrometers scale) that moves when accelerated. Capacitance change is measured and converted to acceleration.

Gyroscope (Coriolis Effect)

Vibrating mass
    ↕ (driven oscillation)

When rotated: Coriolis force deflects mass perpendicular
              to both vibration and rotation axis

Deflection ∝ Angular velocity

MEMS gyros use vibrating structures. When the device rotates, the Coriolis effect creates a measurable deflection.


MicroPython Implementation

Basic Reading (BMI160)

from machine import I2C, Pin
from bmi160 import BMI160

# Setup I2C and create IMU instance
i2c = I2C(1, scl=Pin(15), sda=Pin(14), freq=400000)
imu = BMI160(i2c)

# Read sensor data
ax, ay, az = imu.get_accel()  # Returns g units
gx, gy, gz = imu.get_gyro()   # Returns °/s

print(f"Accel: {ax:.2f}, {ay:.2f}, {az:.2f} g")
print(f"Gyro: {gx:.1f}, {gy:.1f}, {gz:.1f} °/s")
Note

The BMI160 uses little-endian byte order (unlike the older MPU6050 which uses big-endian). The bmi160 driver handles this internally — you just call get_accel() and get_gyro().

Heading Integration

import time

heading = 0.0
last_time = time.ticks_ms()

def update_heading():
    global heading, last_time

    now = time.ticks_ms()
    dt = time.ticks_diff(now, last_time) / 1000.0
    last_time = now

    _, _, gz = imu.get_gyro()
    heading += gz * dt  # Integrate angular velocity

    return heading

Common Issues

Gyroscope Drift

Gyros have bias - a small offset even when stationary:

Stationary robot, reading gz every 100ms:
Reading:  0.15, 0.12, 0.18, 0.14, 0.16 °/s
Actual:   0.00, 0.00, 0.00, 0.00, 0.00 °/s

After 60 seconds: 0.15 °/s × 60s = 9° error!

Solutions: - Calibrate bias at startup (average readings when stationary) - Use complementary filter with accelerometer - Periodically reset when robot is known to be stationary

Accelerometer Noise

Accelerometers pick up vibration from motors:

Robot stationary: ax ≈ 0.00, ay ≈ 0.00, az ≈ 1.00
Robot moving:     ax ≈ ±0.3, ay ≈ ±0.2, az ≈ 0.8-1.2
                  (motor vibration dominates!)

Solutions: - Low-pass filter for tilt measurement - High-pass filter for vibration measurement (useful for speed estimation!) - Mount IMU with vibration isolation

Axis Orientation

IMU axes depend on mounting orientation:

BMI160 on your robot (check YOUR mounting!):
  +X = forward
  +Y = left
  +Z = up

May need to:
- Swap axes
- Negate values
- Rotate coordinate frame

Specifications Comparison

Parameter MPU6050 BMI160
Accel range ±2/4/8/16 g ±2/4/8/16 g
Gyro range ±250/500/1000/2000 °/s ±125/250/500/1000/2000 °/s
Accel noise 400 µg/√Hz 180 µg/√Hz
Gyro noise 0.005 °/s/√Hz 0.007 °/s/√Hz
Interface I2C (400kHz) I2C/SPI
Sample rate Up to 1kHz Up to 1.6kHz
Price ~$2 ~$5

Professional Context: Automotive & Aerospace IMUs

Your BMI160 is a consumer-grade MEMS sensor — better than the older MPU6050, but still far from industrial grade. Professional applications use significantly more sophisticated IMUs. Here's how they compare:

IMU Comparison

Feature BMI160 (Your Robot) Automotive (ESC/ADAS) Aerospace/Navigation
Price ~$3 $20-200 $1,000-50,000+
Gyro bias stability 5-10 °/hr 1-5 °/hr 0.001-0.1 °/hr
Accel bias 60 mg 1-10 mg 0.01-1 mg
Temperature range -40 to +85°C -40 to +125°C -55 to +125°C
Vibration tolerance Basic 20g+ shock rated Mil-spec
Self-test Basic Continuous Redundant + voting
Redundancy None Often dual Triple+
Interface I2C CAN/SPI ARINC 429 / MIL-STD
Calibration User (if any) Factory + temp comp Individual unit calibration
MTBF Not specified 100k+ hours 500k+ hours

Why Automotive IMUs Are Different

1. Bias Stability Matters

Your robot: 5°/hr drift → 5° error per hour of operation

Automotive ESC: Needs to detect 0.1° vehicle roll angle to prevent rollover

Navigation grade: Submarine navigates underwater for weeks using only IMU

2. Temperature Compensation

Consumer IMU bias vs temperature:
20°C: gz_bias = 0.15 °/s
40°C: gz_bias = 0.35 °/s  ← 130% change!

Automotive IMU: Internal temp sensor + factory calibration curve
→ Compensated output stable across -40 to +125°C

3. Functional Safety

Our Robot Automotive ESC IMU
IMU fails → robot wobbles IMU fails → car rolls over
No redundancy Dual sensors, plausibility check
No self-test Continuous built-in test
"It seems to work" ISO 26262 ASIL-D certified

What the Industry Uses

Manufacturer Example Application
Bosch SMI230 Vehicle stability, ADAS
STMicro ASM330LHH Automotive-grade 6-axis
Analog Devices ADIS16470 Industrial/navigation
Honeywell HG1700 Aircraft navigation
Northrop Grumman LN-200 Missile/spacecraft guidance

Key Takeaway

Hardware Has Physical Limits

What software CAN fix: - Bias → calibration routine at startup - Noise → filtering (averaging, EMA, complementary filter) - Drift over short term → sensor fusion with accelerometer - Temperature drift → if you measure temperature and have calibration data

What software CANNOT fix: - Long-term drift → need better gyro (fiber optic, ring laser) - Vibration sensitivity → need mechanical isolation or better sensor - Bias repeatability → need factory calibration + temperature curves - No magnetometer → cannot get absolute heading (only relative)

The lesson: With calibration and filtering, you can get 1-2° heading accuracy from the BMI160 over a few minutes. For 0.1° accuracy over hours, you need fundamentally different (and expensive) hardware.

Real Example: Heading Accuracy

Scenario BMI160 Automotive IMU Navigation Grade
10 second maneuver < 1° error < 0.1° error < 0.01° error
1 minute operation 2-5° error 0.1-0.5° error < 0.01° error
1 hour operation 30-60° error 1-5° error 0.1° error
Without GPS reset Unusable Needs reset Works standalone

Your robot operates for seconds to minutes, making the BMI160 perfectly adequate. A self-driving car needs the expensive stuff.


Further Reading