Calculating Pitch and Roll from an Accelerometer

Recently whilst developing a quad rotor UAV I came across the challenge of determining a crafts Pitch and Roll. To beat this challenge I used a combination of an Accelerometer and Gyroscopes. In this post I will discuss how to extract the Pitch and Roll from the Accelerometer exclusively.

An accelerometer works by measuring how much force is applied to an axis. For this task a 3 axis accelerometer is required. I used the Sparkfun 5 Degree of Freedom IMU. What does this mean? 5 Degrees of Freedom (DOF) means that 5 separate axes of motion can be measured. In the case of the IMU (Inertial Measurement Unit) there are 3 axes of accelerometer motion. This means the inertial forces across the x, y and z axes can be measured. There is also a 2 DOF gyroscope attached, measuring the rate of change around the x and y axes.

The forces acting on the accelerometer are shown in (diagram). When an accelerometer is held in place, i.e. there is no acceleration, then the only force acting on it will be gravity. If you imagine the board static with the x and y planes horizontal then gravity will be acting fully on the z axis. This means that the x and y readouts will display a value of 0g whilst the z axis displays a value of 1g, g representing gravity.

If you were to begin rotating the board around its x axis, the y axis will begin moving towards gravity (As shown) and the z axis will begin moving away from gravity. This will mean the value from the y readout will begin increasing, whilst the z axis will start decreasing. The x readout will stay at 0g as we have rotated around the x axis, so it has not moved close too or further from gravity. We can use some relatively simple equations to calculate the pitch and roll using the values we read from the x, y and z axes.

If you are using an analogue accelerometer you face the issue of how do I convert the output into something I can use? Our target is to convert this voltage into g’s. In order to read the data you first require an Analogue to Digital Converter (ADC). These can be found on most micro controllers.

We need to know a few things before we can start programming the micro controller. Firstly what is the voltage reference for the ADC? We need this value to determine what the maximum possible value will be read by the ADC. So if the reference is 3.3v, then the ADC will read a maximum of 3.3v. We also need to know the resolution of the ADC. Typically this will be expressed in bits, the controller I use has a resolution of 10 bits. The 0g voltage is an important factor also, we use 0g as a reference point so this is important. It is possible to detect this value by testing with a multimeter, also the devices data sheet will usually inform you of the 0 values for the accelerometer. Generally the value will be half of the max output, so the device I’m using has a 0g output of 1.5V. Finally we need to know the sensitivity of the outputs, this should be found in the data sheet and will be expressed in mV/g, for the device I’m using the sensitivity is 300mV/g.

What do we do with all this data? We can use it to convert the bits we receive from our ADC into mV, and then into g. I will explain this further as we go on.

Typically an ADC will spit out a value in the form of an unsigned integer. This means we have a string of bits which represent the voltage seen on the analogue pin. We can convert this number to a voltage range using the following (simple!) equation.

x = (ADC_Output * VReference) / ADC_Resolution;

ADC_Output being the value you read from your ADC. VReference is the reference voltage of your ADC. Try to express this in mV, so if your reference is 3.3V then it can be written as 3300mV. As there are 1000mV in 1V. Finally the ADC_Resolution can be found with the following equation;

ADC_Resolution = (2^Resolution) - 1;

So with my 10 bit ADC the value is 1023.

Now as we have expressed our voltage in mV the value of x is expressed in mV. This isn’t useful data just yet, we need to do two things before we can use it. First we need to subtract the 0g level. For my accelerometer the zeroGx value would be 1500mV.

x = x - zeroGx;

Finally we need to convert our voltage reading into g’s. In order to do this we divide by the sensitivity. As the term for x is expressed in mV when we divide by the sensitivity, which is expressed in mV/g, the final result is to have a reading in g.

x = x / sensitivity;

The same steps need to be repeated to find a reading for the y and z axes.

Now that we have 3 outputs expressed in g we should be able to calculate the pitch and the roll. This requires two further equations.

pitch = atan (x / sqrt(y^2 + z^2))
roll = atan (y / sqrt(z^2 + z^2))

This will produce the pitch and roll in radians, to convert them into friendly degrees we multiply by 180, then divide by PI.

pitch = (pitch * 180) / PI
roll = (roll * 180) / PI

You will probably notice that the values that you read from the accelerometer are quite noisy and tend to lose accuracy when the device is moving around a lot. In order to smooth these values out we need to use a complementary filter to combine gyro data, which I hope to include at a later date.

You may also find that when the device is level the x and y values are not 0′s as expected, this can be corrected by altering the zeroG values of the x and y axes. Also if the device is increasing its roll or pitch when you were expecting it to decrease, all you need to do is multiply the output value by -1, to reverse the axis.

  1. Ryan wrote on April 21st, 2011 at 12:35 Uhr1


    Great blog. Do you have an email I can contact you on? I have a few questions.