27 Motion and Environmental Sensor Labs
Key Concepts
- MPU-6050 IMU: A 6-axis inertial measurement unit combining a 3-axis accelerometer and 3-axis gyroscope on a single I2C chip (address 0x68 or 0x69); widely used for motion detection and orientation sensing in IoT
- Accelerometer Output: Measures acceleration in g units along three axes; at rest, reads approximately 0 g on horizontal axes and +1 g on the vertical axis due to gravity
- Gyroscope Output: Measures angular velocity in degrees per second; integrating over time gives angle, but integration accumulates drift error, making pure gyro integration unsuitable for long-term angle tracking
- Complementary Filter: Sensor fusion combining accelerometer (accurate long-term, noisy short-term) and gyroscope (accurate short-term, drifts long-term): angle = alpha x (angle + gyro x dt) + (1-alpha) x accel_angle
- BME280 Environmental Sensor: Combined temperature, humidity, and barometric pressure sensor with I2C/SPI; temperature +-1 C, humidity +-3% RH, pressure +-1 hPa; can compute altitude from pressure
- Interrupt-Driven Motion Detection: Configuring the MPU-6050 motion threshold interrupt to wake a sleeping microcontroller only when motion exceeds a threshold, dramatically reducing power consumption versus continuous polling
- Gyroscope Drift: The gradual accumulation of error when integrating gyroscope readings; even 0.01 deg/s offset causes 0.6 deg/minute of drift, making long-term orientation tracking unreliable without correction
- Sensor Fusion: Combining data from multiple sensors to produce estimates more accurate than any single sensor alone; accelerometer + gyroscope + magnetometer enables robust 3D orientation tracking
27.1 Learning Objectives
By the end of this chapter, you will be able to:
- Interface the MPU6050 IMU: Configure and read 6-axis accelerometer and gyroscope data via I2C
- Calculate orientation: Derive pitch and roll angles from accelerometer readings
- Implement motion detection: Create algorithms to detect movement using total acceleration
- Measure environmental parameters with BMP280: Read barometric pressure, temperature, and calculate altitude
- Apply sensor calibration: Perform initial calibration to compensate for sensor offsets
For Beginners: Motion and Environmental Sensors
Motion sensors detect movement and orientation, just like the sensor in your phone that knows when you tilt or shake it. Environmental sensors measure things around us like air pressure and temperature. In this lab, you will work with an IMU (a chip that senses acceleration and rotation) and a barometric pressure sensor (which can even estimate your altitude based on air pressure changes).
27.2 Prerequisites
Required Knowledge:
- Temperature Sensor Labs - Basic sensor interfacing
- Electronics Basics - I2C communication fundamentals
- Sensor Circuits - Signal conditioning
Hardware Requirements:
- ESP32 development board
- MPU6050 6-axis IMU module
- BMP280 barometric pressure sensor
- Breadboard and jumper wires
- 4.7kOhm pull-up resistors (for I2C)
Software Requirements:
- Arduino IDE with ESP32 board support
- Libraries: Wire, MPU6050, Adafruit_BMP280
27.3 Motion & Orientation Sensors
27.3.1 MPU6050 (6-Axis IMU)
The MPU6050 combines a 3-axis accelerometer and 3-axis gyroscope in a single chip, making it ideal for motion detection, tilt sensing, and orientation tracking.
Specifications:
- Gyroscope: +/-250, +/-500, +/-1000, +/-2000 deg/s
- Accelerometer: +/-2g, +/-4g, +/-8g, +/-16g
- Interface: I2C (400kHz)
- Built-in DMP (Digital Motion Processor)
- 16-bit ADC for each channel
Inside the MPU6050, a tiny MEMS (Micro-Electro-Mechanical System) structure converts physical acceleration into an electrical signal. A proof mass suspended by microscopic springs deflects under acceleration, and capacitive plates detect the displacement (Figure 27.1).
The proof mass and spring form a second-order mechanical system whose response depends on damping. MEMS accelerometers are designed to be critically or slightly overdamped to avoid oscillation and settle quickly (Figure 27.2).
The underlying physics follows the harmonic oscillator model: the restoring force of the spring is proportional to displacement, balanced by damping and the applied acceleration force (Figure 27.3).
ESP32 Implementation:
#include <Wire.h>
#include <MPU6050.h>
MPU6050 mpu;
// Raw sensor readings
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initializing MPU6050...");
mpu.initialize();
// Verify connection
if (mpu.testConnection()) {
Serial.println("MPU6050 connection successful");
} else {
Serial.println("MPU6050 connection failed");
while(1);
}
// Set sensitivity
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2); // +/-2g
mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250); // +/-250deg/s
// Calibrate (keep sensor still during this)
calibrateMPU();
}
void loop() {
// Read raw accel/gyro measurements
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
// Convert to real-world units
float accelX = ax / 16384.0; // For +/-2g range
float accelY = ay / 16384.0;
float accelZ = az / 16384.0;
float gyroX = gx / 131.0; // For +/-250deg/s range
float gyroY = gy / 131.0;
float gyroZ = gz / 131.0;
// Calculate pitch and roll
float pitch = atan2(-accelX, sqrt(accelY*accelY + accelZ*accelZ)) * 180/PI;
float roll = atan2(accelY, accelZ) * 180/PI;
// Detect motion
float totalAccel = sqrt(accelX*accelX + accelY*accelY + accelZ*accelZ);
bool isMoving = fabs(totalAccel - 1.0) > 0.1; // Threshold for motion
Serial.print("Accel(g): ");
Serial.print(accelX, 2); Serial.print(", ");
Serial.print(accelY, 2); Serial.print(", ");
Serial.print(accelZ, 2);
Serial.print(" | Gyro(deg/s): ");
Serial.print(gyroX, 2); Serial.print(", ");
Serial.print(gyroY, 2); Serial.print(", ");
Serial.print(gyroZ, 2);
Serial.print(" | Pitch: ");
Serial.print(pitch, 1);
Serial.print(" Roll: ");
Serial.print(roll, 1);
Serial.print(" | Moving: ");
Serial.println(isMoving ? "YES" : "NO");
delay(100);
}
void calibrateMPU() {
Serial.println("Calibrating MPU6050... Keep sensor still!");
long axSum = 0, aySum = 0, azSum = 0;
long gxSum = 0, gySum = 0, gzSum = 0;
int samples = 100;
for(int i = 0; i < samples; i++) {
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
axSum += ax; aySum += ay; azSum += az;
gxSum += gx; gySum += gy; gzSum += gz;
delay(10);
}
// Set offsets (simplified approach for educational purposes;
// production code should account for offset register scaling)
mpu.setXAccelOffset(-(axSum / samples));
mpu.setYAccelOffset(-(aySum / samples));
mpu.setZAccelOffset(16384 - (azSum / samples)); // 1g offset for Z
mpu.setXGyroOffset(-(gxSum / samples));
mpu.setYGyroOffset(-(gySum / samples));
mpu.setZGyroOffset(-(gzSum / samples));
Serial.println("Calibration complete!");
}
Learning Points: MPU6050
Understanding the Readings:
When the sensor is stationary on a level surface, you should see: - Accelerometer: [0, 0, 1] g (gravity pulling down on Z-axis) - Gyroscope: [0, 0, 0] deg/s (no rotation)
Accelerometer Sensitivity:
| Range | Sensitivity | Use Case |
|---|---|---|
| +/-2g | 16384 LSB/g | Tilt sensing, gentle motion |
| +/-4g | 8192 LSB/g | General purpose |
| +/-8g | 4096 LSB/g | Sports, vehicles |
| +/-16g | 2048 LSB/g | High-impact detection |
Gyroscope Sensitivity:
| Range | Sensitivity | Use Case |
|---|---|---|
| +/-250 deg/s | 131 LSB/(deg/s) | Slow rotation, stabilization |
| +/-500 deg/s | 65.5 LSB/(deg/s) | General purpose |
| +/-1000 deg/s | 32.8 LSB/(deg/s) | Fast rotation |
| +/-2000 deg/s | 16.4 LSB/(deg/s) | Rapid spinning |
Common Applications:
- Step counters (detect walking vibrations)
- Fall detection (sudden acceleration spike followed by stationary)
- Tilt sensors (measure gravity direction)
- Gesture recognition (wave patterns)
- Vehicle tracking (acceleration, braking, turning)
27.4 Environmental Sensors
27.4.1 BMP280 (Pressure & Temperature)
The BMP280 is a precision barometric pressure sensor that also measures temperature. It is commonly used for weather monitoring and altitude estimation.
Specifications:
- Pressure Range: 300-1100 hPa (+/-1 hPa absolute, +/-0.12 hPa relative)
- Temperature Range: -40C to 85C (+/-0.5C typical, +/-1C max)
- Interface: I2C or SPI
- Altitude calculation from pressure
- Power: 2.7uA @ 1Hz (weather monitoring mode)
ESP32 Implementation:
#include <Wire.h>
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp; // I2C interface
// Sea level pressure for altitude calculation
#define SEALEVELPRESSURE_HPA (1013.25)
void setup() {
Serial.begin(115200);
if (!bmp.begin(0x76)) { // or 0x77
Serial.println("Could not find BMP280 sensor!");
while (1);
}
// Default settings from datasheet
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, // Operating Mode
Adafruit_BMP280::SAMPLING_X2, // Temp oversampling
Adafruit_BMP280::SAMPLING_X16, // Pressure oversampling
Adafruit_BMP280::FILTER_X16, // Filtering
Adafruit_BMP280::STANDBY_MS_500); // Standby time
}
void loop() {
float temperature = bmp.readTemperature(); // C
float pressure = bmp.readPressure() / 100.0; // hPa
float altitude = bmp.readAltitude(SEALEVELPRESSURE_HPA); // meters
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("C | Pressure: ");
Serial.print(pressure);
Serial.print(" hPa | Altitude: ");
Serial.print(altitude);
Serial.println(" m");
// Simplified weather trend demo (real applications should
// compare readings over 1-3 hours, not 10-second intervals)
static float lastPressure = pressure;
float pressureChange = pressure - lastPressure;
if (pressureChange > 0.5) {
Serial.println("Weather: Improving (pressure rising)");
} else if (pressureChange < -0.5) {
Serial.println("Weather: Worsening (pressure falling)");
} else {
Serial.println("Weather: Stable");
}
lastPressure = pressure;
delay(10000); // 10 seconds
}
Learning Points: BMP280
Altitude from Pressure:
The barometric formula relates pressure to altitude:
\[ h = 44330 \times \left(1 - \left(\frac{P}{P_0}\right)^{0.1903}\right) \]
where \(h\) is altitude in meters, \(P\) is measured pressure in hPa, and \(P_0\) is sea level pressure (1013.25 hPa).
Pressure Varies with:
- Altitude: ~12 Pa per meter (1.2 hPa per 100m)
- Weather: +/-30 hPa due to weather systems
- Temperature: Gas expansion affects pressure readings
Floor Detection Application:
For indoor floor detection, use relative accuracy (+/-0.12 hPa) rather than absolute. Each floor (~3m) produces a 0.36 hPa change – 3x the sensor’s noise floor, making single-floor detection reliable. See the worked example below for a full calculation.
Oversampling Trade-offs:
| Setting | Resolution | Noise | Time |
|---|---|---|---|
| x1 | 16-bit | Higher | 8ms |
| x2 | 17-bit | Lower | 14ms |
| x16 | 20-bit | Lowest | 62ms |
Putting Numbers to It
The barometric formula converts atmospheric pressure to altitude above sea level using an exponential relationship.
Worked example: Your BMP280 measures 900 hPa on a mountain. Calculate the altitude:
\[ h = 44330 \times \left(1 - \left(\frac{900}{1013.25}\right)^{0.1903}\right) \]
\[ h = 44330 \times \left(1 - (0.8882)^{0.1903}\right) = 44330 \times (1 - 0.9777) = 44330 \times 0.0223 \approx 989 \text{ m} \]
Cross-check with rule of thumb: pressure drops ~12 Pa/meter, so \((1013.25 - 900) \text{ hPa} \times 100 \text{ Pa/hPa} \div 12 \text{ Pa/m} \approx 944 \text{ m}\). The difference arises because 12 Pa/m is only accurate near sea level; at higher altitudes the air is thinner and each meter of elevation produces a smaller pressure drop, so the barometric formula gives a higher (more accurate) result.
27.4.2 Altitude Calculator
Use this interactive calculator to explore how measured pressure translates to altitude using the barometric formula. Adjust the sea-level reference pressure to see how weather conditions affect altitude estimates.
27.5 Knowledge Check
Key Takeaway
Both the MPU6050 and BMP280 communicate via I2C and require startup calibration. The critical design principle is choosing the right accuracy metric: for the accelerometer, calibrate against the known 1g gravity reference; for the barometric sensor, use relative accuracy (not absolute) when measuring altitude differences.
For Kids: Meet the Sensor Squad!
Sammy the Sensor got a new friend – an accelerometer named “Accel Amy”! Amy can feel which way is down because gravity is always pulling on her tiny proof mass (like a tiny ball on a spring inside a chip).
“When I sit still on a table,” Amy explained, “I feel gravity pulling down on my Z-axis, so I report [0, 0, 1]g. But tip me sideways, and the numbers change – that is how I know which way is up!”
Max the Microcontroller had another friend too – “Baro Bob” the pressure sensor. “I can tell you how high up you are!” Bob said proudly. “The higher you go, the less air presses down on me. Each floor of a building changes my reading by about 0.36 units.”
Lila the LED blinked excitedly: “So if Amy detects someone walking (bouncy acceleration) and Bob detects they went up a floor (pressure dropped), we can track people going upstairs – without any cameras!”
Bella the Battery nodded: “And Bob only uses about 3 microamps – that is so tiny I could power him for years!”
Worked Example: Calculating Floor Changes with BMP280
Scenario: You are building a smart building elevator tracker using BMP280 sensors to detect which floor occupants are on.
Given Data:
- Ground floor pressure: 1013.25 hPa (sea level)
- Floor 1 pressure: 1012.89 hPa
- Floor 2 pressure: 1012.53 hPa
- Floor 3 pressure: 1012.17 hPa
- BMP280 relative accuracy: +/- 0.12 hPa
Step 1: Calculate pressure change per floor
Floor 0 → Floor 1: 1013.25 - 1012.89 = 0.36 hPa
Floor 1 → Floor 2: 1012.89 - 1012.53 = 0.36 hPa
Floor 2 → Floor 3: 1012.53 - 1012.17 = 0.36 hPa
Average: 0.36 hPa per floor (3 meters vertical)
Step 2: Can BMP280 reliably detect floor changes?
Pressure change: 0.36 hPa per floor
Sensor accuracy: +/- 0.12 hPa
Signal-to-noise ratio: 0.36 / 0.12 = 3:1
Result: YES! The 0.36 hPa change per floor is 3x larger than the sensor’s noise floor (0.12 hPa), making floor detection reliable. You can confidently detect single-floor transitions.
Step 3: Calculate altitude from pressure Using the barometric formula:
float seaLevelPressure = 1013.25; // hPa at ground floor
float currentPressure = bmp.readPressure() / 100.0; // Convert Pa to hPa
// Calculate altitude in meters
float altitude = 44330.0 * (1.0 - pow(currentPressure / seaLevelPressure, 0.1903));
// Estimate floor number (assuming 3m per floor)
int floor = round(altitude / 3.0);Real-World Application:
- Smart elevators: Track user movement patterns
- Emergency response: Locate firefighters in multi-story buildings
- Fitness tracking: Count stair climbing (calories burned)
- Indoor navigation: Guide users to specific floors in large buildings
Key Insight: Use relative accuracy (+/- 0.12 hPa) for altitude differences, not absolute accuracy (+/- 1 hPa). Absolute pressure varies +/- 30 hPa daily due to weather, but relative measurements within a few hours are highly stable.
How It Works: MPU6050 IMU Calibration
When you power on the MPU6050, it has factory-set offsets that may not match your specific chip or mounting orientation. Here is the step-by-step calibration process:
- Place sensor perfectly level - Use a flat, stable surface
- Collect 100 samples - Average out noise (each sample takes ~10ms)
- Calculate offsets - Expected values are: accel [0, 0, 1g], gyro [0, 0, 0]
- Write offsets to registers - MPU6050 has built-in offset registers
- Verify calibration - Check that stationary readings match expectations
Key insight: The Z-axis accelerometer should read exactly 1g (16384 raw units at +/-2g setting) when level because Earth’s gravity pulls on the proof mass. The calibration compensates for the chip being slightly tilted in its package or mounting variations.
27.6 Concept Relationships
| Core Concept | Related Concepts | Why It Matters |
|---|---|---|
| Accelerometer | Gravity Sensing, Tilt Angle, Motion Detection | Measures static orientation and dynamic acceleration |
| Gyroscope | Angular Velocity, Drift, Integration | Tracks rotation rate but accumulates error over time |
| Barometric Pressure | Altitude, Weather Prediction, Floor Detection | Converts pressure to height using barometric formula |
| Sensor Fusion | Complementary Filter, Kalman Filter | Combines accel + gyro for drift-free orientation |
27.7 Summary
This chapter covered motion and environmental sensor implementation:
- MPU6050 IMU combines accelerometer and gyroscope for 6-axis motion sensing
- Accelerometer calibration compensates for factory offsets by measuring at rest
- Pitch and roll calculations derive orientation from gravity vector direction
- Motion detection uses total acceleration magnitude deviation from 1g
- BMP280 provides pressure-based altitude estimation and weather monitoring
- Relative vs absolute accuracy determines suitability for different applications
27.8 See Also
- Temperature Sensor Labs - Temperature sensing fundamentals
- Best Practices & Labs - Implementation guidelines
- Sensor Calibration Lab - Hands-on calibration techniques
Common Pitfalls
1. IMU Mounting Orientation Not Compensated
The MPU-6050 axis orientation is fixed to the chip package. If the chip is mounted at 45 degrees, all axis readings must be rotated mathematically to match the device frame. Always document and compensate for the physical mounting orientation in firmware.
2. I2C Address Conflict in Multi-Sensor Designs
The MPU-6050 uses address 0x68 or 0x69; the BME280 uses 0x76 or 0x77. Both can coexist on the same bus, but confirm no other sensors in your design share these addresses before ordering PCBs.
3. Gyroscope Full-Scale Range Mismatch
Integrating raw gyroscope readings without applying the correct sensitivity conversion for the configured full-scale range (+-250, +-500, +-1000, or +-2000 deg/s) produces angles scaled by factors of 2, 4, or 8. Always read the full-scale register and apply the correct LSB-to-deg/s conversion factor.
4. Humidity Reading Before Warm-Up
The BME280 humidity sensor requires 1-2 seconds after power-on for the humidity cell to stabilize. Reading humidity immediately after power-on produces low readings that do not reflect actual ambient humidity.
27.9 What’s Next?
| Chapter | Focus Area |
|---|---|
| Light & Proximity Sensors | Photodiode, LDR, IR proximity, and touch sensing labs |
| Sensor Calibration Lab | Hands-on calibration techniques with Wokwi simulation |
| Best Practices & Labs | Production-quality sensor implementation guidelines |
| Sensor Data Processing | Filtering, smoothing, and fusion of sensor readings |
| Sensor Power Management | Low-power techniques for battery-operated sensor nodes |