🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
NEWSLIVESearch All Content
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

IMU & Motion Sensors: The Drone's Inner Ear

🟢 Free Lesson

Advertisement

What Is an IMU?

Sponsored

An Inertial Measurement Unit (IMU) is like a drone's inner ear — it tells the drone how it's moving through space without needing external references. Just as your inner ear helps you balance and know which way is up, an IMU provides the orientation and motion data a drone needs to stay stable.

A typical drone IMU contains three types of sensors:

  • Accelerometer — measures linear acceleration (how fast speed is changing)
  • Gyroscope — measures angular velocity (how fast it's rotating)
  • Magnetometer — measures magnetic field direction (compass heading)

The 6-Axis IMU

A 6-axis IMU combines a 3-axis accelerometer and a 3-axis gyroscope into a single chip. The 7th and 8th axes come from the magnetometer.

6-Axis IMU ArchitectureIMU ChipMPU-6050 / ICM-20948Accelerometer±2/4/8/16gGyroscope±250-2000°/s16-bit ADCXYZSignal Flow PipelineRaw SensorCalibrationFilterFusionOrientationSensor readingBias/Scale fixNoise reduceCombine dataEuler anglesX (Roll)Y (Pitch)Z (Yaw)

Accelerometer Deep Dive

An accelerometer measures proper acceleration — the acceleration relative to freefall. When sitting on a table, it reads +9.81 m/s² upward (countering gravity). Think of it like the feeling you get in an elevator: you feel heavier accelerating up, lighter when accelerating down.

Key characteristics:

  • Great for detecting gravity direction (tilt sensing)
  • Noisy during fast movements (motor vibrations)
  • Drift-free over long periods for gravity reference
python

# Simulated accelerometer reading
ax, ay, az = 0.12, -0.05, 9.78  # m/s²

# Calculate roll and pitch from accelerometer
roll = np.arctan2(ay, az)   # ~ -0.005 rad (-0.3°)
pitch = np.arctan2(-ax, np.sqrt(ay**2 + az**2))  # ~ 0.012 rad (0.7°)

print(f"Roll:  {np.degrees(roll):.1f}°")
print(f"Pitch: {np.degrees(pitch):.1f}°")

Gyroscope Deep Dive

Sponsored

A gyroscope measures how fast something is spinning around each axis. Think of a spinning top — the faster it spins, the higher the angular velocity reading. Unlike the accelerometer, gyroscopes are clean during fast motion but slowly drift over time due to bias errors.

Key characteristics:

  • Excellent for short-term rotation tracking
  • Low noise during dynamic maneuvers
  • Suffers from bias drift (integrates error over time)
python
# Simulated gyroscope reading (degrees per second)
gx, gy, gz = 15.2, -3.8, 0.5  # °/s

# Integrate to get angle change over dt
dt = 0.01  # 100Hz sampling
angle_change = gz * dt  # 0.005° around Z-axis

print(f"Yaw rate: {gz}°/s")
print(f"Angle change in {dt}s: {angle_change:.4f}°")

Magnetometer: The Digital Compass

The magnetometer detects Earth's magnetic field to provide heading information. It's like a compass in your phone — it tells you which direction you're facing. However, it's sensitive to nearby metal objects and electromagnetic interference from motors.

Sensor Fusion: Combining the Best of Each

No single sensor is perfect. Sensor fusion combines all three to get the best estimate:

SensorStrengthWeakness
AccelerometerStable long-term (gravity)Noisy during motion
GyroscopeClean during motionDrifts over time
MagnetometerProvides headingSensitive to interference
Complementary Filter FusionGyroscopeHigh-freq accurateAccel + MagLow-freq stableIntegrate∫ω dtLow-PassLP filterBlendα·gyro + (1-α)·accOrientationRoll, Pitch, YawFilter Parameter α (alpha)α ≈ 0.96–0.98 → Trust gyro more (smooth but drifts)α ≈ 0.80–0.90 → Trust accelerometer more (noisy but stable)

Complementary Filter

The complementary filter is a simple yet effective fusion approach. It uses a high-pass filter on gyroscope data (trust gyro for fast changes) and a low-pass filter on accelerometer data (trust accel for slow/steady changes).

python
class ComplementaryFilter:
    def __init__(self, alpha=0.96):
        self.alpha = alpha
        self.angle = 0.0

    def update(self, gyro_angle, accel_angle, dt):
        # High-pass on gyro (fast response), low-pass on accel (drift correction)
        self.angle = self.alpha * (self.angle + gyro_angle * dt) + \
                     (1 - self.alpha) * accel_angle
        return self.angle

# Usage
filter = ComplementaryFilter(alpha=0.96)
for gyro, accel in zip(gyro_readings, accel_readings):
    angle = filter.update(gyro, accel, dt=0.01)

Kalman Filter: The Gold Standard

Advertisement

The Kalman filter is more sophisticated — it maintains an estimate of the state and its uncertainty, then optimally combines predictions with measurements.

Kalman Filter: Predict → Update CyclePREDICTx̂⁻ = A·x̂ + B·uP⁻ = A·P·Aᵀ + QUsing gyroscope inputstepUPDATEK = P⁻·Hᵀ·(H·P⁻·Hᵀ+R)⁻¹x̂ = x̂⁻ + K·(z - H·x̂⁻)Correct with accelerometerNext timestepx̂ = state estimate | P = error covariance | K = Kalman gain | Q = process noise | R = measurement noiseA = state transition | B = control input | H = measurement model | z = measurement

When to Use Each Filter

FilterComplexityCPU UsageAccuracyBest For
ComplementaryLowVery LowGoodSimple drones, resource-limited
MadgwickMediumLowVery GoodMost drone applications
KalmanHighMediumExcellentPrecision navigation, GPS-denied

Hands-On Project: IMU Data Logger

Build a basic IMU data logger using an MPU-6050 sensor with Raspberry Pi Pico:

python
from machine import I2C, Pin

class MPU6050:
    def __init__(self, i2c, addr=0x68):
        self.i2c = i2c
        self.addr = addr
        # Wake up sensor
        self.i2c.writeto_mem(self.addr, 0x6B, b'\x00')
        # Set accelerometer range ±2g
        self.i2c.writeto_mem(self.addr, 0x1C, b'\x00')
        # Set gyroscope range ±250°/s
        self.i2c.writeto_mem(self.addr, 0x1B, b'\x00')

    def read_accel(self):
        data = self.i2c.readfrom_mem(self.addr, 0x3B, 6)
        ax, ay, az = struct.unpack('>hhh', data)
        return ax/16384.0, ay/16384.0, az/16384.0

    def read_gyro(self):
        data = self.i2c.readfrom_mem(self.addr, 0x43, 6)
        gx, gy, gz = struct.unpack('>hhh', data)
        return gx/131.0, gy/131.0, gz/131.0

# Initialize
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
mpu = MPU6050(i2c)

# Log data for 10 seconds
print("timestamp,ax,ay,az,gx,gy,gz")
start = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start) < 10000:
    ax, ay, az = mpu.read_accel()
    gx, gy, gz = mpu.read_gyro()
    t = time.ticks_diff(time.ticks_ms(), start) / 1000.0
    print(f"{t:.3f},{ax:.3f},{ay:.3f},{az:.3f},{gx:.1f},{gy:.1f},{gz:.1f}")
    time.sleep_ms(10)

Project Extensions:

  1. Add a simple complementary filter to compute real-time tilt
  2. Log data to SD card for post-flight analysis
  3. Visualize live data using a web dashboard
  4. Compare raw vs filtered readings during aggressive maneuvers

Key Takeaways

  • An IMU provides 6-DOF motion sensing (accelerometer + gyroscope)
  • Accelerometers are stable long-term but noisy; gyroscopes are clean but drift
  • Sensor fusion combines strengths of each sensor for accurate orientation
  • Start with a complementary filter; upgrade to Kalman/Madgwick for precision
  • Calibration (bias removal) is essential before any filtering
—
☆☆☆☆☆
0 ratings

Rate & Feedback

Need Expert Drone AI Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement