In this instructable I will go over how to build a tilt sensor (i.e measuring Pitch and Roll angles) using a single accelerometer. I have also included a “Gravity filter” that attempts to remove the effect of gravity from the accelerometer readings.
NOTE: I found out the design of this project is inherently flawed, but I decided to release it any way. The tilt senor can only make accurate readings while stationary. While Rotating or moving the sensor, the readings are WRONG. I’ll talk about this more in the theory section.To understand all of the code in this project, you must have completed the previous projects.
Step 1: Theory
I will not get into the math details about how I calculate the tilt angles, or how I attempt to filter out gravity. However here is a general overview of the theory behind my code.
The accelerometer I used senses acceleration on 3 axes, X, Y and Z. As discussed in the previous instructable the readings from these axes represent component vectors. When the device is sitting flat on a table, gravity is lined up with its Z axis so the Z axis reads roughly 1. The X and Y axes in this case both read 0. When you rotate the board gravity will fall somewhere between the X Y and Z axes. This means gravity’s component vectors are spread between the axes. The close the gravity vector is to lining up with an axis, the closer that axis’ reading will be to 1. So we can use some trigonometry to calculate the tilt angle, based on the magnitudes read on the X Y and Z axes. In my code I refer to these angles as Euler angles, since angles that represent 3d orientation of an object are called Euler angles.
More on Euler Angles here: http://en.wikipedia.org/wiki/Euler_angles
In my code I also included a gravity filter. It uses the Euler angles to estimate the component vectors caused by gravity. I subtract these estimated component vectors out to obtain final gravity free value. Again this approach only works while the device is stationary.
Step 2: Why Are the Readings Bad During Motion?
The Euler angle calculations only work if the device is stationary. If you move the device, there are two acceleration vectors now acting on it; the acceleration due to gravity and the acceleration from your movement. The component vector of these two acceleration forces both sum into indistinguishable values, throwing off the readings. A physics problem like this is said to have 6 degrees of freedom. This is because there are two sets of XYZ component vectors involved.
I learned about these inaccuracies the hard way when I rushed a prototype for a field test. In my spare time I like to Autocross and figured it would be a great opportunity to test my project. Unfortunately these races aren't held very often so I had to rush to finish it so I didn't miss my only chance. Linked above is a video of the race, where I overlaid the g-force and angle data I collected.
If you couldn't tell, all the recorded readings are pretty far off. For example if you look closely the max roll angle I recorded was 56 degrees. If this were true my car would have been up on two wheels and probably flipped.
To get accurate readings while in motion I would have needed to collect data from at least 6 sources (hence 6 degrees of freedom). So adding a 3 axis gyroscope or a 3 axis compass to measure angle would remedy the problem .
Step 3: Code
Here is my code, I won’t be explaining anything beyond the comments I have included in the block diagram. I basically guessed and checked until I got the trigonometry to work out how I wanted.