This project focused on improving orientation estimates from a low-cost IMU using an Extended Kalman Filter (EKF). I worked with Kyle Frith to connect a BNO055 9-axis IMU to an Arduino UNO, bring the data into MATLAB, and use a quaternion-based filter to estimate roll and pitch more cleanly than raw sensor measurements alone.
The hardware was intentionally simple and inexpensive, which made the real question more interesting: how much performance can you get out of modest hardware if the estimation logic is thoughtful? The result was a practical attitude-estimation setup that handled low-frequency motion well, while also making the limits of the sampling rate and sensor responsiveness very clear during faster maneuvers.
Hardware Setup
The physical setup was intentionally lightweight: an Arduino UNO Rev3, a BNO055 9-axis IMU, a mini breadboard, and four jumper wires. That small footprint made it easy to prototype, but it also meant the filter had to do real work if the final orientation estimates were going to look stable and useful.
The I2C wiring was simple and reliable:
| Arduino UNO | BNO055 IMU | Purpose |
|---|---|---|
| A5 | SCL | I2C clock line |
| A4 | SDA | I2C data line |
| GND | GND | Common electrical ground |
| 5V | Vin | Power input to the IMU board |
Why this platform worked well
The Arduino UNO gave the project an easy serial and power interface, while the BNO055 packaged a gyroscope, accelerometer, and magnetometer into one accessible sensor board. It was a practical testbed for attitude-estimation work without turning the build into a larger embedded systems project.
What the setup exposed
Because the hardware was low-cost, noise and responsiveness limits were visible right away. That was actually useful: it made it easier to see what the EKF improved, and where sensor bandwidth still became the limiting factor.
Estimation Approach
The filter was built as a quaternion-based EKF rather than a direct Euler-angle filter. That choice mattered because quaternions avoid the singularities and awkward edge cases that can come with naive roll-pitch-yaw integration.
The measurement side of the filter used accelerometer-based attitude estimates for roll and pitch, while yaw was held at zero because the magnetometer behavior was too sensitive to rely on cleanly in this setup:
The sensor covariance values used for the measurement model were gathered by leaving the IMU stationary for roughly three minutes and computing the covariance in MATLAB:
| Sensor channel | Measured covariance |
|---|---|
| Accel x | 1.732 × 10-7 |
| Accel y | 1.327 × 10-7 |
| Accel z | 4.473 × 10-7 |
| Gyro x | 4.125 × 10-7 |
| Gyro y | 6.884 × 10-7 |
| Gyro z | 4.011 × 10-7 |
Bring-Up Workflow
Before the filtering work could be tested, the MATLAB support package for Arduino had to be configured so the board and IMU could be read reliably from the desktop toolchain. That step was simple, but it mattered because the whole data path depended on a clean hardware-software handshake.
Experimental Results
The project tested the EKF under two broad motion regimes:
- Low-frequency roll, pitch, and combined maneuvers over 10 seconds.
- Higher-frequency roll, pitch, and combined maneuvers over 2 seconds.
That split made the performance differences easy to see. The filter looked strong when the motion changed gradually, but the faster tests showed where the IMU and overall sampling chain started to struggle.
Low-Frequency Maneuvers
The 10-second tests produced the cleanest results. Roll and pitch traces stayed smooth, and the combined maneuver behaved consistently with the single-axis cases.
Higher-Frequency Maneuvers
When the same general test was compressed into a 2-second window, the outputs became much sharper and more angular. The roll and pitch estimates still tracked the commanded motion directionally, but the response was visibly less smooth and less settled.
What worked well
The EKF was effective for gradual attitude changes. In the slower 10-second tests, the filtered roll and pitch estimates looked smooth, stable, and well-behaved for both single-axis and combined motions.
What broke down first
High-frequency motion exposed the system's limits. The filter did not fail outright, but the curves became visibly more angular, which points back to hardware sampling constraints and the need for a faster, more robust IMU for aggressive maneuvers.
Outcome and Next Steps
This project was a good example of how much value you can get from a modest hardware stack when the estimation logic is solid. With an Arduino, a BNO055, and MATLAB, we built a working attitude-estimation pipeline that could clean up pitch and roll measurements and clearly demonstrate the strengths and limits of a low-cost EKF-based solution.
The next steps are clear from the test results:
- Add yaw estimation back in once the magnetic measurement path is more trustworthy.
- Tune the EKF more aggressively for dynamic maneuvers.
- Move to a higher-rate IMU if fast attitude changes are a real requirement.
- Keep the same estimation framework, but apply it to a more flight-like embedded setup.
If you want the full derivation, the report and editable writeup linked above go into the equations, implementation details, and experimental discussion in much more depth.