hi,
i'm quite new in this world, and i'm actually playing with a 3 axis analogic accelerometer (MMA7361)
i use it in the +/- 1,5G range (sensitivity of 0,800 v/g)
i can easyly read data from the accelerometer, but the values are not very stables.... so when i convert them to angle, the result is really very instable.
someone can give help me...?
//Lebenj
//february 2011
//Created using version 0021 of the Arduino Development Environment
//playing with an accelerometer and display data on the serial monitor
#define wDelay 500//no ; here. Sets how long each "message" appears
// These constants won't change:
const int pinL = A2; // pin Xsensor
const int pinP = A1; // pin Ysensor
const int pinH = A0; // pin Zsensor
const int ledPin = 9; // pin that the LED is attached to
//const int range = 1.5; // accelerometer range
//const int voltageACC = 3.3; // accelerometer Voltage
const int voltageBOARD = 5; // arduino board Voltage
const int pi = 314159265;
// variables:
float sensitivityV = 0.800; // voltage accelerometer sensitivity
float sensitivityd = 1023 / voltageBOARD * sensitivityV ; // digital accelerometer sensitivity
int sensitivityD = int(sensitivityd);
// variables Laterales:
int sensorLvalue ; // the sensor value
int sensorLvalue1 ; // the sensor value
int sensorLvalue2 ; // the sensor value
int sensorLvalue3 ; // the sensor value
int sensorLvalue4 ; // the sensor value
int sensorLvalue5 ; // the sensor value
int sensorLmin = 1023; // minimum sensor value
int sensorLmax = 0; // maximum sensor value
int sensorLave; // average min/max during calibration
int accL ; // acceleration laterale
int angle1dL; // roll angle (laterale) calcul 21(roulie)
int angle2dL; // roll angle (laterale) 2D(roulie)
int angle3dL; // roll angle (laterale) 3D(roulie)
// variables pitch:
int sensorPvalue ; // the sensor value
int sensorPvalue1 ; // the sensor value
int sensorPvalue2 ; // the sensor value
int sensorPvalue3 ; // the sensor value
int sensorPvalue4 ; // the sensor value
int sensorPvalue5 ; // the sensor value
int sensorPmin = 1023; // minimum sensor value
int sensorPmax = 0; // maximum sensor value
int sensorPave = 0; // average min/max during calibration
int accP ; // acceleration pitch
float angleP; // angle Pitch (tanguage)
// variables verticales:
int sensorHvalue ; // the sensor value
int sensorHvalue1 ; // the sensor value
int sensorHvalue2 ; // the sensor value
int sensorHvalue3 ; // the sensor value
int sensorHvalue4 ; // the sensor value
int sensorHvalue5 ; // the sensor value
int sensorHmin = 1023; // minimum sensor value
int sensorHmax = 0; // maximum sensor value
int sensorHave = 0; // average min/max during calibration
int accH ; // acceleration verticale
float angleH; // angle ?????
void setup(){
Serial.begin(9600);
Serial.println(" ");
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
Serial.print("CALIBRATION");
Serial.println("");
// calibrate during the first five seconds
while (millis() < 4000) {
sensorLvalue = analogRead(pinL);
sensorPvalue = analogRead(pinP);
sensorHvalue = analogRead(pinH);
// record the maximum sensor value(LPH)
if (sensorLvalue > sensorLmax) {
sensorLmax = sensorLvalue;
}
if (sensorPvalue > sensorPmax) {
sensorPmax = sensorPvalue;
}
if (sensorHvalue > sensorHmax) {
sensorHmax = sensorHvalue;
}
// record the minimum sensor value (LPH)
if (sensorLvalue < sensorLmin) {
sensorLmin = sensorLvalue;
}
if (sensorPvalue < sensorPmin) {
sensorPmin = sensorPvalue;
}
if (sensorHvalue < sensorHmin) {
sensorHmin = sensorHvalue;
}
}
sensorLave = (sensorLmin + sensorLmax) / 2;
sensorPave = (sensorPmin + sensorPmax) / 2;
sensorHave = ((sensorHmin + sensorHmax) / 2);
Serial.print("tension arduino: ");
Serial.print(voltageBOARD); // print board voltage
Serial.println(""); // retour charriot
Serial.print("sensitivite VOLT: ");
Serial.print(sensitivityV); // print voltage sensitivity
Serial.println(""); // retour charriot
Serial.print("sensitivite digitale: ");
Serial.print(sensitivityD); // print digital sensitivity
Serial.println(""); // retour charriot
Serial.print("calibration laterale: ");
Serial.print(sensorLave); // print the average of L
Serial.println(""); // retour charriot
Serial.print(" "); // print nothing
Serial.print("calibration Pitch: ");
Serial.print(sensorPave); // print the average of H
Serial.println(""); // retour charriot
Serial.print(" "); // print nothing
Serial.print("calibration hauteur: ");
Serial.print(sensorHave); // print the average of P
Serial.println(""); // retour charriot
delay(1000);
Serial.print("FIN CALIBRATION"); // calibration END
delay(1000);
Serial.println(""); // retour charriot
// signal the end of the calibration period
digitalWrite(13, LOW);
};//end "setup()"
void loop(){
delay(wDelay);
// read the sensor:
sensorLvalue1 = analogRead(pinL);
sensorPvalue1 = analogRead(pinP);
sensorHvalue1 = analogRead(pinH);
delay(10);
sensorLvalue2 = analogRead(pinL);
sensorPvalue2 = analogRead(pinP);
sensorHvalue2 = analogRead(pinH);
delay(10);
sensorLvalue3 = analogRead(pinL);
sensorPvalue3 = analogRead(pinP);
sensorHvalue3 = analogRead(pinH);
delay(10);
sensorLvalue4 = analogRead(pinL);
sensorPvalue4 = analogRead(pinP);
sensorHvalue4 = analogRead(pinH);
delay(10);
sensorLvalue5 = analogRead(pinL);
sensorPvalue5 = analogRead(pinP);
sensorHvalue5 = analogRead(pinH);
sensorLvalue = (sensorLvalue1 + sensorLvalue2 + sensorLvalue3 + sensorLvalue4 + sensorLvalue5) / 5;
sensorPvalue = (sensorPvalue1 + sensorPvalue2 + sensorPvalue3 + sensorPvalue4 + sensorPvalue5) / 5;
sensorHvalue = (sensorHvalue1 + sensorHvalue2 + sensorHvalue3 + sensorHvalue4 + sensorHvalue5) / 5;
accL = 100 * (sensorLvalue - sensorLave) / sensitivityD; // calcul acceleration laterale
accP = 100 * (sensorPvalue - sensorPave) / sensitivityD; // calcul acceleration pitch
accH = 100 * (sensorHvalue - sensorHave) / sensitivityD; // calcul acceleration verticale
angle1dL= 180 * (asin(accL)) / pi * 10000; //calcul avec la deviation de X uniquement
angle2dL= 180 * (atan(accL / accH)) / pi * 10000; //calcul sur 2 axes X et Z
angle3dL= 180 * (atan(accL / sqrt(accH * accH + accP * accP))) / pi * 10000; //calcul sur 3 axes
Serial.print(" valeur laterale: ");
Serial.print(sensorLvalue);//write sensorValue
Serial.print(" valeur pitch: ");
Serial.print(sensorPvalue);//write sensorValue
Serial.print(" valeur hauteur: ");
Serial.print(sensorHvalue);//write sensorValue
Serial.println("");//Send an "x" to turn a digit off
Serial.print(" acceleration laterale: ");
Serial.print(accL);
Serial.print(" acceleration pitch: ");
Serial.print(accP);
Serial.print(" acceleration verticale: ");
Serial.print(accH);
Serial.println("");//retour charriot
Serial.print(" angle roulis(calcul 1D): ");
Serial.println(angle1dL);
Serial.print(" angle roulis(calcul 2D): ");
Serial.println(angle2dL);
Serial.print(" angle roulis(calcul 3D): ");
Serial.println(angle3dL);
delay(wDelay);
};
hi, @groove
you are true, my code looks very long, but for the moment it's not a priority for me, i prefer it like that to keep it clear for me.
when i will get better results, i will manage to do it better.
to calculate one value, i make the average of 5 samples. it's the way i explore to get a more stable reading.
@liudr
when my accelerometer is flat i dont have 512 on X and Y, but around 340. (and around 175 for Z)
i think it's normal, because my arduino is in 5V but my accelerometer (and quite all accelerometers) are working at 3,3V. so the 0g give 3,3V / 2 = 1,65V wich mapped to a 0 1023 of 0 5V give the normal result of 340, no???
sorry for my poor englidh skill...
i was playing yesterday night with excell (wich i use better for calculation), and i find some bugs in my code. so i have to work on it.
i thinks i get well that analogic inputs, my problems are to get a stable value when the accelerometer is not moving, and a good calculation to get the angle.
Hey, that's good. To further improve your accuracy, you can use analogReference(EXTERNAL); and connect your aref to 3.3V on arduino. Then you will get 512, a better use of the 1024 levels.
I think your accelerometer is too sensitive, +-1.5g. Is there a jumper to go to +-6.0g? Use that if you want to tell angle. If you tap on your accelerometer at +-1.5g range with your finger, it may go half its scale. Accelerations are pretty big even for those small movements, it's not related to small change in position but change in velocity.
In my music box project, I have +-6.g sensitivity and tapping on the box that encloses arduino with accelerometer on it, not tapping on the accelerometer, can give me a large fraction of a g!
you gave me 2 good ways to explore.... thanks a lot
for the 1,5G or 6G, i must make tries. i have also a ADXL3xx wich is 3G, as it works in the same way i can easyly change it for the other. i have only to modify the sensitivity.
i will get a look on your project. i hope it will help me a lot.
when i make tries to mesure angles, i never touch the accelerometer, only the board.
with your experience, do you really thing i need to make a calibration???
If you reduce the size of your code by factoring, you reduce the number of dark corners the bugs have to hide, and you will almost certainly make you code easier to maintain and debug.
Using arrays could make it even shorter.
Uses less memory too, even if you increase N_READINGS to the point where you have to make the variables "long"s instead of "int"s.
i made a update of my code (thanks liudr and Groove)
but when i compare result in excel and in my serial monitor i have still trouble reading the angle!!!
//Lebenj
//february 2011
//Created using version 0021 of the Arduino Development Environment
//playing with an accelerometer and display data on the serial monitor
#define wDelay 500//no ; here. Sets how long each "message" appears
// These constants won't change:
const int pinL = A2; // pin Xsensor
const int pinP = A1; // pin Ysensor
const int pinH = A0; // pin Zsensor
const int ledPin = 9; // pin that the LED is attached to
//const int range = 1.5; // accelerometer range
//const int voltageACC = 3.3; // accelerometer Voltage
const int voltageBOARD = 5; // arduino board Voltage
const int pi = 314159265;
const int Nsamples = 10;
// variables:
float Aref = 3.3;
float sensitivityV = 0.800; // voltage accelerometer sensitivity
float sensitivityd = 1023 / Aref * sensitivityV ; // digital accelerometer sensitivity
int sensitivityD = int(sensitivityd);
// variables Laterales:
int sensorLvalue ; // the sensor value
int sensorLmin = 1023; // minimum sensor value
int sensorLmax = 0; // maximum sensor value
int sensorLave; // average min/max during calibration
int sensorLaveT = 0; // teoric X value calibration
int accL ; // acceleration laterale
float angle1dL; // roll angle (laterale) calcul 21(roulie)
float angle2dL; // roll angle (laterale) 2D(roulie)
float angle3dL; // roll angle (laterale) 3D(roulie)
// variables pitch:
int sensorPvalue ; // the sensor value
int sensorPmin = 1023; // minimum sensor value
int sensorPmax = 0; // maximum sensor value
int sensorPave = 0; // average min/max during calibration
int sensorPaveT = 0; // teoric Y value calibration
int accP ; // acceleration pitch
float angleP; // angle Pitch (tanguage)
// variables verticales:
int sensorHvalue ; // the sensor value
int sensorHmin = 1023; // minimum sensor value
int sensorHmax = 0; // maximum sensor value
int sensorHave = 0; // average min/max during calibration
int sensorHaveT = 0; // teoric Z value calibration
int accH ; // acceleration verticale
float angleH; // angle ?????
void setup(){
Serial.begin(9600);
analogReference(EXTERNAL);
Serial.println(" ");
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
Serial.print("CALIBRATION");
Serial.println("");
// calibrate during the first five seconds
while (millis() < 4000) {
sensorLvalue = analogRead(pinL);
sensorPvalue = analogRead(pinP);
sensorHvalue = analogRead(pinH);
// record the maximum sensor value(LPH)
if (sensorLvalue > sensorLmax) {
sensorLmax = sensorLvalue;
}
if (sensorPvalue > sensorPmax) {
sensorPmax = sensorPvalue;
}
if (sensorHvalue > sensorHmax) {
sensorHmax = sensorHvalue;
}
// record the minimum sensor value (LPH)
if (sensorLvalue < sensorLmin) {
sensorLmin = sensorLvalue;
}
if (sensorPvalue < sensorPmin) {
sensorPmin = sensorPvalue;
}
if (sensorHvalue < sensorHmin) {
sensorHmin = sensorHvalue;
}
}
sensorLave = (sensorLmin + sensorLmax) / 2;
sensorPave = (sensorPmin + sensorPmax) / 2;
sensorHave = (sensorHmin + sensorHmax) / 2;
sensorLaveT = 511; // theoric valor
sensorPaveT = 511; // theoric valor
sensorHaveT = 759; // theoric valor
Serial.print("tension arduino: ");
Serial.print(voltageBOARD); // print board voltage
Serial.println(""); // retour charriot
Serial.print("tension de reference digitale (Aref: ");
Serial.print(Aref); // print board voltage
Serial.println(""); // retour charriot
Serial.print("sensitivite VOLT: ");
Serial.print(sensitivityV); // print voltage sensitivity
Serial.println(""); // retour charriot
Serial.print("sensitivite digitale: ");
Serial.print(sensitivityD); // print digital sensitivity
Serial.println(""); // retour charriot
Serial.print("calibration laterale theorique: ");
Serial.print(sensorLaveT); // print the average of L
Serial.print(" mesurée: ");
Serial.print(sensorLave); // print the average of L
Serial.println(""); // retour charriot
Serial.print(" "); // print nothing
Serial.print("calibration Pitch theorique: ");
Serial.print(sensorPaveT); // print the average of H
Serial.print(" mesurée: ");
Serial.print(sensorPave); // print the average of H
Serial.println(""); // retour charriot
Serial.print(" "); // print nothing
Serial.print("calibration hauteur theorique: ");
Serial.print(sensorHaveT); // print the average of P
Serial.print(" emsurée: ");
Serial.print(sensorHave); // print the average of P
Serial.println(""); // retour charriot
delay(1000);
Serial.print("FIN CALIBRATION"); // calibration END
delay(1000);
Serial.println(""); // retour charriot
// signal the end of the calibration period
digitalWrite(13, LOW);
};//end "setup()"
void loop(){
delay(wDelay);
analogReference(EXTERNAL);
// read the sensor:
for (int i = 0; i < Nsamples; ++i) {
sensorLvalue += analogRead (pinL);
sensorPvalue += analogRead (pinP);
sensorHvalue += analogRead (pinH);
delay (10);
}
sensorLvalue /= Nsamples;
sensorPvalue /= Nsamples;
sensorHvalue /= Nsamples;
accL = 100 * (sensorLvalue - sensorLave) / sensitivityD; // calcul acceleration laterale
accP = 100 * (sensorPvalue - sensorPave) / sensitivityD; // calcul acceleration pitch
accH = 100 * (sensorHvalue - sensorHave) / sensitivityD; // calcul acceleration verticale
angle1dL= 180 * (acos(accL)) / pi * 100000000; //calcul avec la deviation de X uniquement
angle2dL= 180 * (atan(accL / accH)) / pi * 100000000; //calcul sur 2 axes X et Z
angle3dL= 180 * (atan(accL / sqrt(accH * accH + accP * accP))) / pi * 100000000; //calcul sur 3 axes
Serial.print(" valeur laterale: ");
Serial.print(sensorLvalue);//write sensorValue
Serial.print(" valeur pitch: ");
Serial.print(sensorPvalue);//write sensorValue
Serial.print(" valeur hauteur: ");
Serial.print(sensorHvalue);//write sensorValue
Serial.println("");//Send an "x" to turn a digit off
Serial.print(" acceleration laterale: ");
Serial.print(accL);
Serial.print(" acceleration pitch: ");
Serial.print(accP);
Serial.print(" acceleration verticale: ");
Serial.print(accH);
Serial.println("");//retour charriot
Serial.print(" angle roulis(calcul 1D): ");
Serial.println(angle1dL);
Serial.print(" angle roulis(calcul 2D): ");
Serial.println(angle2dL);
Serial.print(" angle roulis(calcul 3D): ");
Serial.println(angle3dL);
delay(wDelay);
};
now at this point i have the acceleration correctly, but still with problems to get the right calculated angle.
on Excel (wich help me a lot to find bugs), i have the correct angle, but for the moment i'm still in trouble to calculate it on arduino.
i thinks it come from float() problems....
yesterday, i was getting negative value from the Z axis!!!! normally not possible because it's an average of 10 samples wich value is between 0 adn 1023!!!!!!....
really hard to understand what is going wrong....
i also change the way to define the calibration value: i took the choice to make an average of a number of samples (25),
can someone can plug a 3 axis accelerometer on a arduino board and try my code???
ints have a range of -32,768 to 32,767. You're trying to assign a value of 314,159,265 to one. Overflow.
angle1dL= 180 * (acos(accL)) / pi * 100000000; //calcul avec la deviation de X uniquement
angle2dL= 180 * (atan(accL / accH)) / pi * 100000000; //calcul sur 2 axes X et Z
angle3dL= 180 * (atan(accL / sqrt(accH * accH + accP * accP))) / pi * 100000000; //calcul sur 3 axes
In all likelihood, all these lines are overflowing as well, but even if they weren't, you're using an overflowed pi in them.
yes i know,
but this 500ms are at the end of the loop, so when i'm doing it one more time to get a new mesure.
and to read on the serial monitor. (between 2 samples to get the average value, i need more speed (i know, there is a small ms value also )
and this is the first part of my project,
for the moment, with the "float" i have more than enough speed, but when i will add more things, i hope it will not be to slow!
some news of my code.
i still have problems, but it's interesting!
the X ans Y 0g value are good (around 512)
but my 1G value on Z is strangely far from the theory: in theory i must have 512 - 248 (for 800mv/g) = 263