Calibration

To be a bit more constructive, here is some code for pitch and roll calculation using 3D accelerometer data, following the guidelines of the Freescale Application Note I linked earlier.

It works very well.

The routine to read the accelerometer (read_accel_raw()) must return signed values for the acceleration along each axis. This is not a complete, working Arduino program, because nothing is assumed about the accelerometer to be used.

// pitch and roll calculated from raw 3D accelerometer readings
// See Freescale Semiconductor Document Number: AN3461
// Application Note Rev. 4, 02/2012
// Tilt Sensing Using Linear Accelerometers

#include <math.h>
#define R2D 180.0/3.14159265


// define a vector data type (3 floats)

typedef struct vector
{
 float x, y, z;
} vector;

// vector operators

void vector_cross(vector *a, vector *b, vector *out)
{
 out->x = a->y * b->z - a->z * b->y;
 out->y = a->z * b->x - a->x * b->z;
 out->z = a->x * b->y - a->y * b->x;
}

float vector_dot(vector *a, vector *b)
{
  return a->x * b->x + a->y * b->y + a->z * b->z;
}

void vector_normalize(vector *a)
{
 float mag = sqrt(vector_dot(a, a));
 a->x /= mag;
 a->y /= mag;
 a->z /= mag;
}

//
// calculate and print pitch and roll from accelerometer data
//

void print_pitch_roll(void) {

 vector b = {0,0,0};
 vector a = {0,0,0};
 int i;

// take 5 acceleration readings and average them
 for(i = 0; i < 5; i++)
 {

 read_accel_raw(&a);  //get the accelerometer data

 b.x += a.x;
 b.y += a.y;
 b.z += a.z;
 }

 b.x /= 5;
 b.y /= 5;
 b.z /= 5;

 vector_normalize(&b);

// here defining pitch as the rotation about X, roll as rotation about Y
// accelerometer X to right, Y backwards, pointing toward the user, Z down

 float pitch = R2D*atan2(-b.y, -b.z);
 float roll = R2D*atan2(-b.x, sqrt(b.y*b.y + b.z*b.z));

 Serial.print("pitch ");
 Serial.println(pitch);
 Serial.print("roll ");
 Serial.println(roll);
}

*** It is probably worth pointing out that the Freescale Application Note boils down to these two lines, with the caution that there are a few orientiations where they won't work as expected. One example is when the z acceleration (b.z) is zero.

 float pitch = R2D*atan2(-b.y, -b.z);
 float roll = R2D*atan2(-b.x, sqrt(b.y*b.y + b.z*b.z));