Pages: [1]   Go Down
Author Topic: 3 axes accel MMA7361 as Tilt meter  (Read 2973 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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/(1*PI);    //calculate the tilt angle in degree
    degree_z=asin(g_z)*180.0/(1*PI);
  }
  //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_x*100);  // 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("%");
}






« Last Edit: October 10, 2012, 05:29:28 pm by RonSpooner » Logged

0
Offline Offline
Shannon Member
****
Karma: 215
Posts: 12467
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

israel
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.26 KB - downloaded 108 times.)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Oregon, USA
Offline Offline
Edison Member
*
Karma: 69
Posts: 2374
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

"It seems to run on some form of electricity"

Pages: [1]   Go Up
Jump to: