Accelerometers measure acceleration. That is acceleration due to movement and also acceleration due to gravity. Accelerometers are often used to calculate a tilt angle. They can only do this reliably when they are static and not moving. To get an accurate angle of tilt they are often combined with one or more gyro's and the combination of data is used to calculate the angle.

Digital accelerometers will give you information using a serial protocol like I2C , SPI or USART, while analog accelerometers will output a voltage level within a predefined range that you have to convert to a digital value using an ADC (analog to digital converter) module.

In this tutorial we will briefly explain the functionality of accelerometers, how they are used to measure tilt angles and finally provide some example code. Also see the tutorial on combining accelerometer and gyro data to give a better tilt angle for a dynamic system.

What does an accelerometer measure

Accelerometers measure acceleration. For a static object that is the acceleration due to gravity (1g). Note also, that the output from accelerometers is not linear but is a sinewave, so you cannot take the direct output as a proportional representation of an angle of tilt based on gravity.

Normally an accelerometer's x and y output voltages will be half the supply voltage when measuring zero g (i.e. the device is perpendicular to gravity - horizontal). Tilt it one way and the voltage will increase, tilt it the other way and it will decrease. With a Triple axis accelerometer the z axis will be measuring 1g with the device horizontal. The output of an accelerometer is a sinewave of the acceleration measured. Accelerometers are more sensitive to small changes in tilt when they are perpendicular to gravity. I.e. when horizontal, small changes in tilt give useful readings. Past about 45 degrees of tilt they become increasingly less sensitive. For this reason it is common to use more than one axis value when determining the angle of tilt as will be seen below.

Measuring Tilt Angle using One Axis

If you want to measure tilt in both x and y axis with a 2-axis accelerometer then you can simply use sin-1(a) where a is the output from one axis of the accelerometer.

Remember that beyond +45 and -45 degrees the accuracy will diminish

Measuring Tilt Angle using Two Axis

The reduction in resolution and accuracy beyond 45 degrees of tilt can be improved by using 2 axis to measure the tilt
The component of gravity acting on the x axis is a sine function whilst that acting on the y axis is a cosine. When the sensitivity of the x axis starts dropping off after 45 degrees of tilt, the sensitivity of the y axis is increasing. As can be seen in the chart below, the bolded parts of each line show the area of most sensitivity.

Thus by combining the x and y values a much improved accuracy can be obtained

The angle is calculated using the formula

Measuring Tilt Angle using Three Axis

For accurate measurements of tilt in the x and y planes we therefore need a 3 axis accelerometer. We could use the formula above to calculate the angles using x and z for the x axis and using y and z for the y axis. However we can improve things further by using all three outputs to calculate each angle. This is done using the following formulas.

Lets get down to some Coding

Hopefully, we are now fairly clear about the principles, but lets see how this is done in practice. We will use a 3 axis accelerometer and work out angles for roll (x) and pitch (y).

We will assume that depending on the type of accelerometer used you have read the values for x, y and z and that you also have baseline values for x, y and z when the accelerometer is stationary and level.

void calc_xy_angles(void){
   // Using x y and z from accelerometer, calculate x and y angles
   float x_val, y_val, z_val, result;
   unsigned short long x2, y2, z2; //24 bit

   // Lets get the deviations from our baseline
   x_val = (float)accel_value_x-(float)accel_center_x;
   y_val = (float)accel_value_y-(float)accel_center_y;
   z_val = (float)accel_value_z-(float)accel_center_z;

   // Work out the squares
   x2 = (unsigned short long)(x_val*x_val);
   y2 = (unsigned short long)(y_val*y_val);
   z2 = (unsigned short long)(z_val*z_val);

   //X Axis
   accel_angle_x = atan(result);

   //Y Axis
   accel_angle_y = atan(result);

Ok, thats it. Just a couple of notes about accelerometers in general. They are very sensitive and are thus quite prone to vibration. If you are using one in a system with motors or other sources of vibration i strongly suggest some form of foam damping. Also, take multiple readings from the accelerometer and average them to filter out any noise.