3 axes accel MMA7361 as Tilt meter

This code works well.
Use AREF at 3.3V
connect SL to 3.3V (keeps the unit out of sleep mode.)
Made the change to use atan2()

/*
// I use this sketch for find the max and min for each axes in counts from 0 to 1023
// carfully and slowly tilt the MMA7361 in all possible aditudes to obtain the max and min.
// This information is used to calibrate the MMA7361 - each one is slightly different.
long analog_x,analog_y,analog_z;
int analog_mx_x, analog_mn_x, analog_mx_y, analog_mn_y, analog_mx_z, analog_mn_z;
int i;
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
analog_mx_x = analog_mn_x =analog_mx_y = analog_mn_y =analog_mx_z = analog_mn_z = 512;
}
void loop()
{
analog_x = analog_y = analog_z = 0;
for (i = 0; i<1000; i++) {
analog_x += analogRead(0);
analog_y += analogRead(1);
analog_z += analogRead(2);
}
analog_x = analog_x/1000;
analog_y = analog_y/1000;
analog_z = analog_z/1000;

analog_mn_x = min(analog_x, analog_mn_x);
analog_mx_x = max(analog_x, analog_mx_x);
analog_mn_y = min(analog_y, analog_mn_y);
analog_mx_y = max(analog_y, analog_mx_y);
analog_mn_z = min(analog_z, analog_mn_z);
analog_mx_z = max(analog_z, analog_mx_z);

Serial.print(“x:”);
Serial.print(analog_x);
Serial.print(" “);
Serial.print(analog_mx_x);
Serial.print(” ");
Serial.print(analog_mn_x);

Serial.print(" y:");
Serial.print(analog_y);
Serial.print(" “);
Serial.print(analog_mx_y);
Serial.print(” ");
Serial.print(analog_mn_y);

Serial.print(" z:");
Serial.print(analog_z);
Serial.print(" “);
Serial.print(analog_mx_z);
Serial.print(” “);
Serial.print(analog_mn_z);
Serial.println(”");
delay(20);
}
*/

// compute the tilt angle.
void setup()
{
Serial.begin(9600);
analogReference(EXTERNAL);
}
long analog_x,analog_y,analog_z; // need a long because I agerage 1000 times and the number gets big.
int i;
float g_x,g_y,g_z; // need float for the asin() functions. 4 bytes
float degree_t,degree_y,degree_z; // degrees are also floating numbers. 4 bytes
void loop()
{
analog_x = analog_y = analog_z = 0;
for (i = 0; i < 1000; i++) { // average 1000 readings
analog_x += analogRead(0); // reads between 0 and 1023
analog_y += analogRead(1);
analog_z += analogRead(2);
}
analog_x = analog_x/100; // 10 times the average
analog_y = analog_y/100;
analog_z = analog_z/100;

// I use the calibration numbers abtained from the above sketch and map then from -1.000 to +1.000
// This mantains the resolution of the analogRead() values. about 500 counts from the 1023 full scale
g_x = map(analog_x,2710,7570,-10000,10000)/10000.0; // normalize 10 times the average into 10000 counts
g_y = map(analog_y,3130,7990,-10000,10000)/10000.0; // this provides a bit more resolution
g_z = map(analog_z,1830,6818,-10000,10000)/10000.0; // 10000 counts = 1g

if(g_z<=1&&g_z>=-1) // Check for overflow of asin(x).( If x>1 or x<-1, asin(x) not defined)
{
degree_t=atan2(g_y, g_x)180.0/(1PI); //calculate the tilt angle in degree
degree_z=asin(g_z)180.0/(1PI);
}
//fix the overflow condition

if(g_z>1) degree_z=91; // I use 91 to indicate an overflow.
if(g_z<-1) degree_z=-91;

Serial.print(“Degrees t:”);
Serial.print(degree_t);
Serial.print(" x:");
Serial.print(g_x100); // prints out gravity in percent.
Serial.print("% y:");
Serial.print(g_y
100);
Serial.print("% z:");
Serial.print(degree_z);
Serial.print(" z:");
Serial.print(g_z*100);
Serial.println("%");
}

Tilt angles should be best calculated as atan2 (x, z) and atan2 (y, z). asin isn’t the obvious trigonometric function to use and totally relies on good gain calibration. atan2 only needs offset calibration and gain-matching and can’t give NaN.

Calibration using max and min will be potentially badly skewed by vibration as you turn the device. Normally you would callibrate by taking 6 measurements with the device static as each is taken, then compute zero-points and gain factors.

A quicker calibration is to take x,y,z readings with device in +z and -z directions only, but then you only get the offset settings for x and y. For small tilt angles this is usually acceptable.

Yes atan2 is a better way. thanks. I average 1000 reading - this helps reduce the noise a bit. Ron

Hi, i have done the same project using simulink with low pass filters.
I have attached a PDF explaining pretty good the math and principles.
look at eq. 37,38

TiltAngle_Accelometer.pdf (579 KB)

Very nice. My application is for a Dob telescope El angle. My simple approach will work for that. Yours is a much more general solution - nicely done. Thanks. Ron

Hi, I am doing sign language translator project.I am using MMA7361 accelerometer to find hand orientation.Can anyone tell me how to calibrate MMA7361 using arduino.

Calibration of the MMA7361

I used a large poster board and fastened at 5cm by 80cm poster-board pendulum to the upper corner. Using drafting tools I made a large protractor with the pendulum fastening point as the center. I fastened the MMA7361 to the pendulum being sure to mount it as squarely as possible. Bu moving the pendulum to known angles I was able to "calibrate" the tilt meter.

To get the most accurate readings, it is very important to individually calibrate the offset and gain of each accelerometer axis. My favorite procedure is described here: sailboatinstruments.blogspot.com/2011/08/improved-magnetometer-calibration.html It is described for magnetometers but works equally well for accelerometers, providing the sensor is held still while each individual data point is collected.