This project implements register-level MPU6050 bring-up, calibration, sensor data acquisition, and roll/pitch attitude estimation.
The repository currently covers two versions of the same project:
- An Arduino Nano Every version used for initial bring-up, calibration, validation, and attitude-estimation development
- An STM32 version used to port the same pipeline to a more industry-standard embedded platform, now running on a FreeRTOS task-based architecture with improved timing control and a cleaner path toward higher-rate sampling
Rather than relying on third-party MPU6050 libraries, all sensor communication, configuration, calibration, and attitude estimation are implemented from scratch using direct I2C register access and the MPU6050 datasheet.
Current capabilities include:
- Register-level MPU6050 configuration
- Accelerometer calibration
- Gyroscope calibration
- Raw sensor data acquisition
- Physical unit conversion
- Roll and pitch estimation
- Gyroscope attitude integration
- Complementary filtering
- Fixed-rate sampling and timing control
- FreeRTOS task-based architecture (STM32)
- Modular software organization
Active development.
- Arduino Nano Every
- MPU6050 IMU Module
- Breadboard
- Jumper Wires
- STM32 Development Board
- MPU6050 IMU Module
- Breadboard
- Jumper Wires
| MPU6050 | Arduino Nano Every | STM32 Version |
|---|---|---|
| VCC | 3.3V | 3.3V |
| GND | GND | GND |
| SDA | SDA | I2C SDA |
| SCL | SCL | I2C SCL |
The accelerometer is configured for a ±2 g measurement range.
During startup, the system:
- Collects 500 stationary samples.
- Computes average offsets for each axis.
- Accounts for gravity on the Z-axis.
- Stores calibration biases.
- Converts readings into g and m/s².
The gyroscope is configured for a ±250 °/s measurement range.
During startup, the system:
- Collects 500 stationary samples.
- Computes average bias values.
- Stores the offsets.
- Converts readings into degrees per second.
Values close to zero while stationary indicate successful calibration.
Roll and pitch are estimated from accelerometer measurements using trigonometric relationships.
A gyroscope attitude estimate is maintained by integrating angular velocity over time.
A complementary filter combines both estimates:
Filtered Angle = α × Gyroscope Estimate + (1 - α) × Accelerometer Estimate
This provides:
- Short-term stability from the gyroscope
- Long-term drift correction from the accelerometer
| Setting | Value |
|---|---|
| Full Scale Range | ±2 g |
| Sensitivity | 16384 LSB/g |
| Setting | Value |
|---|---|
| Full Scale Range | ±250 °/s |
| Sensitivity | 131 LSB/(°/s) |
| Register | Value |
|---|---|
| DLPF_CFG | 3 |
| Sample Rate Divider | 9 |
| Effective Sample Rate | 100 Hz |
The current firmware outputs one compact CSV telemetry line per sample over the serial/UART interface. This format is intended for logging, plotting, and host-side parsing.
time_MS,accel.roll,accel.pitch,gyro.roll,gyro.pitch,filtered.roll,filtered.pitch
Each field represents:
time_MS— loop timestamp in millisecondsaccel.roll— roll estimate from the accelerometeraccel.pitch— pitch estimate from the accelerometergyro.roll— roll estimate from gyroscope integration onlygyro.pitch— pitch estimate from gyroscope integration onlyfiltered.roll— complementary-filtered roll estimatefiltered.pitch— complementary-filtered pitch estimate
1250,0.842,-1.316,0.905,-1.271,0.904,-1.272
1260,0.851,-1.308,0.914,-1.262,0.913,-1.263
1270,0.847,-1.311,0.923,-1.254,0.921,-1.255
- Open the
Arduino/project in PlatformIO. - Build and upload the firmware to the Arduino Nano Every.
- Open the serial monitor to view the telemetry stream.
- Open the
STM32_Nucleo_F446RE/project in your STM32 development environment. - Build and flash the firmware to the STM32 board.
- Open the configured serial/UART output to view the telemetry stream.
The STM32 firmware runs on FreeRTOS, with sensor acquisition, attitude estimation, and telemetry output implemented as separate tasks.
Arduino/
docs/
architecture.md
attitude_estimation.md
calibration.md
roadmap.md
testing.md
include/
Attitude.h
Calibration.h
MPU6050.h
src/
Attitude.cpp
Calibration.cpp
main.cpp
MPU6050.cpp
.gitignore
platformio.ini
STM32_Nucleo_F446RE/
Core/
Inc/
attitude.h
calibration.h
main.h
mpu6050.h
stm32f4xx_hal_conf.h
stm32f4xx_it.h
Src/
attitude.c
calibration.c
main.c
mpu6050.c
stm32f4xx_hal_msp.c
stm32f4xx_it.c
syscalls.c
sysmem.c
system_stm32f4xx.c
.gitignore
README.md
This project provided practical experience with:
- Reading technical datasheets
- Register-level embedded programming
- I2C communication
- Sensor calibration techniques
- Noise reduction and filtering
- Converting raw digital measurements into physical units
- Debugging embedded hardware and software systems
- Organizing embedded software into reusable modules
It also served as a foundation for future projects involving sensor fusion, attitude estimation, STM32-based embedded development, and real-time control software.
- Improved attitude initialization
- Real-time roll and pitch visualization
- Data logging
- Higher-rate sampling and performance optimization
- STM32 refinement and cleanup
- Quaternion attitude representation
- Madgwick or Mahony sensor fusion
- Kalman filtering
- 3D orientation tracking
- Motor control integration
MPU6050 Product Specification:
https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf
MPU6050 Register Map:
https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
Arduino Wire Library Documentation:
https://www.arduino.cc/reference/en/language/functions/communication/wire/