Loading

Arduino tilt sensor using MMA7260Q accelerometer

I’ve playing with the MMA7260Q accelerometer. Following the indications in

I connected X,Y and Z of the MMA7260Q breakout to A0, A1 and A2 of the Arduino. Then, GS1 and GS2 connected to ground to set the range to 1.5g. Ah, and of course, I connected ^SLEEP to VCC.

I managed to put together this piece of code that ouputs the tilt angles ρ(rho) , φ(phi); and Θ(heta) in degrees. I does automatic autozero calibration so before getting sensible results you should tilt the sensor around +/-90 degrees in every axis.

#include <math.h>
#include <float.h>
#include <limits.h>
 
 
int valx = 0;
int valy = 0;
int valz = 0;
 
int xaxis = 0;
int yaxis = 1;   
int zaxis = 2;   
 
float xa=0;
float ya=0;
float za=0;
 
 
 
 
int minx = INT_MAX;
int maxx = 0;
int miny = INT_MAX;
int maxy = 0;
int minz = INT_MAX;
int maxz = 0;
 
int g0x = 0;
int g0y = 0;
int g0z = 0;
 
long time1 = 0;
long time2 = 0;
 
float rho = 0;
float phi = 0;
float theta = 0;
 
 
void setup()
{
  Serial.begin(9600);
  Serial.println("RST\r\n");
  pinMode(xaxis,INPUT);
  pinMode(yaxis,INPUT);
  pinMode(zaxis,INPUT);
  time1=millis();
  time2=millis();
}
 
void loop()
{
 
  valx = analogRead(xaxis);    // read the value from the sensor
  valy = analogRead(yaxis);    // read the value from the sensor
  valz = analogRead(zaxis);    // read the value from the sensor
 
  int pfx = valx;
  int pfy = valy;
  int pfz = valz;
 
  autoZeroCalibration(pfx,pfy,pfz);
 
  int fx = (pfx - g0x);
  int fy = (pfy - g0y);
  int fz = (pfz - g0z);
 
  float ax = fx*(3.3/(1024.0*0.800));
  float ay = fy*(3.3/(1024.0*0.800));
  float az = fz*(3.3/(1024.0*0.800));
 
  //
  rho =   atan(ax/sqrt(pow(ay,2)+pow(az,2)))*(360/(2*3.1592));  
  phi =   atan(ay/sqrt(pow(ax,2)+pow(az,2)))*(360/(2*3.1592));  
  theta = atan(sqrt(pow(ay,2)+pow(ax,2))/az)*(360/(2*3.1592));  
 
  printAngles();
 
}
 
void autoZeroCalibration(int pfx, int pfy, int pfz)
{
    if ((pfx < minx)||(pfy < miny)||(pfz < minz)||(pfx > maxx)||(pfy > maxy)||(pfz > maxz)) {
     // autozero calibration
     if (pfx < minx) minx = pfx;
     if (pfy < miny) miny = pfy;
     if (pfz < minz) minz = pfz;
 
     if (pfx > maxx) maxx = pfx;
     if (pfy > maxy) maxy = pfy;
     if (pfz > maxz) maxz = pfz;
 
     g0x = ((maxx - minx)/2)+minx;
     g0y = ((maxy - miny)/2)+miny;
     g0z = ((maxz - minz)/2)+minz;
 
     printValues();
  }
}
void printFloat(float value, int places) {
   // this is used to cast digits
   int digit;
   float tens = 0.1;
   int tenscount = 0;
   int i;
   float tempfloat = value;
 
   // if value is negative, set tempfloat to the abs value
   // make sure we round properly. this could use pow from  
   //<math.h>, but doesn't seem worth the import
   // if this rounding step isn't here, the value  54.321 prints as  
   //54.3209
 
   // calculate rounding term d:   0.5/pow(10,places)
   float d = 0.5;
   if (value < 0)
     d *= -1.0;
   // divide by ten for each decimal place
   for (i = 0; i < places; i++)
     d/= 10.0;
   // this small addition, combined with truncation will round our  
   // values properly
   tempfloat +=  d;
 
   // first get value tens to be the large power of ten less than value
   // tenscount isn't necessary but it would be useful if you wanted  
   // to know after this how many chars the number will take
 
   if (value < 0)
     tempfloat *= -1.0;
   while ((tens * 10.0) <= tempfloat) {
     tens *= 10.0;
     tenscount += 1;
   }
 
 
   // write out the negative if needed
   if (value < 0)
     Serial.print('-');
 
   if (tenscount == 0)
     Serial.print(0, DEC);
 
   for (i=0; i< tenscount; i++) {
     digit = (int) (tempfloat/tens);
     Serial.print(digit, DEC);
     tempfloat = tempfloat - ((float)digit * tens);
     tens /= 10.0;
   }
 
   // if no places after decimal, stop now and return
   if (places <= 0)
     return;
 
   // otherwise, write the point and continue on
   Serial.print('.');
 
   // now write out each decimal place by shifting digits one by one  
   // into the ones place and writing the truncated value
   for (i = 0; i < places; i++) {
     tempfloat *= 10.0;
     digit = (int) tempfloat;
     Serial.print(digit,DEC);
     // once written, subtract off that digit
     tempfloat = tempfloat - (float) digit;
   }
}
 
void printAngles()
{
   if (millis()-time1 > 1000) {
    time1 = millis();
    Serial.print("rho: ");
    printFloat(rho,3);
    Serial.print(" phi: ");
    printFloat(phi,3);
    Serial.print(" theta: ");
    printFloat(theta,3);
    Serial.print("\r\n");
  }
}
 
void printValues()
{
  if ((millis() - time2) > 800) {
    time2=millis();
    Serial.print("minx: ");
    Serial.print((int)minx,DEC);
    Serial.print(".");
    Serial.print((minx-(int)minx)*1000,DEC);
    Serial.print(" miny: ");
    Serial.print((int)miny,DEC);
    Serial.print(".");
    Serial.print((miny-(int)miny)*1000,DEC);
    Serial.print(" minz: ");
    Serial.print((int)minz,DEC);
    Serial.print(".");
    Serial.print((minz-(int)minz)*1000,DEC);
    Serial.print("\r\n");
 
    Serial.print("maxx: ");
    Serial.print((int)maxx,DEC);
    Serial.print(".");
    Serial.print((maxx-(int)maxx)*1000,DEC);
    Serial.print(" maxy: ");
    Serial.print((int)maxy,DEC);
    Serial.print(".");
    Serial.print((maxy-(int)maxy)*1000,DEC);
    Serial.print(" maxz: ");
    Serial.print((int)maxz,DEC);
    Serial.print(".");
    Serial.print((maxz-(int)maxz)*1000,DEC);
    Serial.print("\r\n");
  }
}

2 Comments

  1. Rohit Banerjee
    Posted March 4, 2010 at 5:54 pm | Permalink

    Hello,

    I was just wondering why when you are converting from a float to an int, you do an effective divide by 0.8. Why don’t you do just *= 3.3/1024 ?

    Thanks

  2. Posted March 4, 2010 at 6:48 pm | Permalink

    If I recall correctly, I divide by 0.8 to normalize the value (the MMA7260Q output is 800mV/g).

One Trackback

  1. By Arduino XBee sensor « Ruben’s blog on March 17, 2009 at 7:52 pm

    [...] XBee sensor Easy AdSenser by UnrealI finally put together an Arduino Pro Mini, the XBee, the MMA7260Q, the HMC6352, the TEMT6000 and the [...]

Post a Comment

Your email is never shared.