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
- Sensor Fusion - Combining IMU with other sensors
- Complementary Filter - Fusing gyro and accelerometer
- Bosch BMI160 Datasheet - Your robot's IMU specifications