Go Down

Topic: [ADXL335] Measuring acceleration in Gs. (Read 10766 times)previous topic - next topic

r4m0n

Jan 03, 2013, 04:13 pm
Hi.

I've bought an ADXL335 acceleration sensor and I want to measure the acceleration in Gs.

Code: [Select]
`float x, y, z;void setup(){  Serial.begin(9600);      }void loop(){  x = analogRead(0) / 330.000;         y = analogRead(1) / 330.000;         z = analogRead(2) / 330.000;           Serial.println("--MEASURING ACCELERATION... AXIS X, Y, Z--");  Serial.println(x);        Serial.println(y);           Serial.println(z);   delay(1000);             }`

When I put the acceleration sensor on a table, I can read this values:

1.02 (X)
1.27 (Y)
1.02 (Z)

I'm not sure this code is ok. Is it? The values it returns seem to be OK.
Is there a better code to measure acceleration in Gs? Than you.

johnwasser

#1
Jan 03, 2013, 05:39 pm

Take the average of 100 raw analog readings and display them.  Measure with each axis facing UP (-1G) and DOWN (+1G).  For each axis, note the minimum and maximum values.

long int x = map(analogInput(0),minimumX, maximumX, -1000, +1000);

To print in G's:  Serial.print(x/1000.0);

By calibrating you can correct for offset error and scale error.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

JamesD3rd

#2
Jan 03, 2013, 06:31 pmLast Edit: Jan 03, 2013, 06:55 pm by JD3 Reason: 1
The calibration method is really important.

If you use the 1g numbers for min and max, the only range you will get is 1g.
Any readings out of that range will not display properly.

Finding the range of +/- 1g is important.  Add them and divide by two.
That will give you the analogRead() value of 0g, assuming the accelerometer is perfectly level.
The difference between 0g and the min or max is your resolution.  How many units read/g.

For an example, on my sensor I get 401 & 611 on the X axis.  (I am using external voltage reference @ 3.6v)
Zero g would be at 506.  The resolution would be 105.
Multiply the difference of analog reading from 0g by .0095 (1/105 or 1/resolution) and there is your g reading.
Or (analogRead(analog pin) - 506) * .0095

Here is the code I used for calculating g forces while driving.
The orientation of the Adafruit accelerometer:  X points left, Y points to the rear.
Arduino orientated natural (USB on left) and accelerometer header pins mounted next to analog pins on protoshield.

WARNING - please do not use alone while driving.  Ask a friend to be your Co-pilot or Navigator - WARNING

Code: [Select]
`/* Designed by AB9VH James Douglas July 2012 Unified Microsystem's ATS-1 LCD Terminal Display Shield with adafruit 3 axis accelerometer, external 3.3v reference Shows g forces while driving */int Xaxis = 0;         // fresh data from accelerometerint Yaxis = 0;int Xcal = 505;        // calibration data, zero gint Ycal = 505;int key = -1;void setup() {  analogReference(EXTERNAL);     // uses 3.3v from accelerometer for reference voltage  Serial.begin(4800);            // opens serial port for LCD shield  Serial.write(1);               // clears display and homes cursor  Serial.println("   Automobile  ");  Serial.print(" Accelerometer ");  delay(2000);  Serial.write(1);  Serial.println(" Prototype 2012");  Serial.print(" J. Douglas III");  delay(2000);  Serial.write(1);               // clear display & home cursor  Serial.println(" Press any Key");  Serial.print("    to start ");  while (key<0) key = Serial.read();  Serial.write(1);}void loop() {  Xaxis = analogRead(2);  Yaxis = analogRead(1);  if (Xaxis<Xcal) {                          // calculate Left & right    Serial.print("Right ");    Serial.print((Xcal-Xaxis)*.0095);    Serial.println("g   ");  }  else if (Xaxis>Xcal) {                      // always display left and right    Serial.print("Left ");                   // g force as positive value    Serial.print((Xaxis-Xcal)*.0095);                Serial.println("g   ");  }  else Serial.println("L/R 0.00g     ");    // display forward as positive g  Serial.print("Front ");                   // display rearward as negative g  Serial.print((Ycal-Yaxis)*.0095);            Serial.println("g   ");  delay(50);  LCDpos(1,1);                                // home cursor ATS-1}void LCDpos(char x, char y) {  Serial.write(20);  Serial.write(x);  Serial.write(y);}`

r4m0n

#3
Jan 03, 2013, 09:45 pm
I think I'm doing something wrong or my code isn't good, because when I face down the ADXL335 I get values around 0'85 G's in the Z axis, and I should get -1G...

johnwasser

#4
Jan 03, 2013, 10:11 pmLast Edit: Jan 03, 2013, 11:18 pm by johnwasser Reason: 1

I think I'm doing something wrong or my code isn't good, because when I face down the ADXL335 I get values around 0'85 G's in the Z axis, and I should get -1G...

From the datasheet it looks like the zero point and the sensitivity can both be off by about 10%.  I think that means that if you use the nominal zero (Vs/2) and the nominal sensitivity (Vs*0.1 per g) you may get readings as much as 20% off.  If you get 0.85 instead of 1.0 your error is only about 15%, well within specs.

Below is what code with calibration looks like.  Of course your calibration values will be different from mine.

Yes, you will get results outside the -1000/+1000 range.  The map() function does not constrain the inputs or outputs.  It just uses the input range and output range to calculate the offset and scale.

Code: [Select]
`// Accelerometer calibrateconst int XPin = A2;const int YPin = A1;const int ZPin = A0;// Raw analog values for -1g and +1g.  Position carefully and look for min and max values.// These are from an accelerometer running on 3.3V measured agains a 5V analog reference.// You would expect (3.3V/2-0.33V)*1024/5V = 270 for -1g and (3.3V/2+0.33V)*1024/5V = 405 for +1g.// As you can see, my accelerometer does not match the nominal values.const int XMin = 180;const int XMax = 507;const int YMin = 199;const int YMax = 542;const int ZMin = 152;const int ZMax = 477;void setup() {  Serial.begin(9600);    pinMode(A3, OUTPUT);  digitalWrite(A3, HIGH);  // Power  pinMode(A4, OUTPUT);  digitalWrite(A4, LOW);  // Ground}void loop() {  unsigned long XSum = 0;  unsigned long YSum = 0;  unsigned long ZSum = 0;    for (int i=0; i<100; i++) {    XSum += analogRead(XPin);    YSum += analogRead(YPin);    ZSum += analogRead(ZPin);  }    Serial.print("X=");  Serial.print(map(XSum/100, XMin, XMax, -1000, 1000));      Serial.print(", Y=");  Serial.print(map(YSum/100, YMin, YMax, -1000, 1000));  Serial.print(", Z=");  Serial.println(map(ZSum/100, ZMin, ZMax, -1000, 1000));  delay(500);}`
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Damos76

#5
Jun 26, 2016, 06:44 am
Afternoon Guys,

I'm new to the Arduino world and would like some help from someone a lot more knowledgeable than myself. I am trying to use an ADXL335 accelerometer x axis to measure tilt in mm (use some form of trig function) length of base 1435mm and adjacent measuring up 150mm maximum.

I can get it to roughly measure angle and display in there Serial monitor, but would also like it to eventually display on LCD or similar value in mm from level (either "Level","L High", "R High").
at this stage I haven't looked at the LCD display part.

I hope what I have asked makes sense, it you guys could help me out that would be much appreciated.

Code: [Select]
`// these constants describe the pins. They won't change:const int groundpin = 18;             // analog input pin 4 -- groundconst int powerpin = 19;              // analog input pin 5 -- voltage int analogPin = A3;                 // x-axis of the accelerometer int val = 0;void setup() {  // initialize the serial communications:  Serial.begin(9600);  // Provide ground and power by using the analog inputs as normal  // digital pins.  This makes it possible to directly connect the  // breakout board to the Arduino.  If you use the normal 5V and  // GND pins on the Arduino, you can remove these lines.  pinMode(groundpin, OUTPUT);  pinMode(powerpin, OUTPUT);  digitalWrite(groundpin, LOW);  digitalWrite(powerpin, HIGH);}void loop() {  val = analogRead(analogPin)-357;     // print a tab between values:   (analogRead(analogPin));  Serial.println(val);  if (analogRead(analogPin)== 0)  {Serial.println("Level");}  if (analogRead(analogPin)> 0)  {Serial.println("L High");}  if (analogRead(analogPin)< 0)  {Serial.println("R High");}   // delay before next reading:  delay(100);}`

knut_ny

#6
Jun 29, 2016, 10:26 amLast Edit: Jun 29, 2016, 10:28 am by knut_ny
@Damos
Code: [Select]
`// these constants describe the pins. They won't change:const int groundpin = 18;             // analog input pin 4 -- groundconst int powerpin = 19;              // analog input pin 5 -- voltage int analogPin = A3;                 // x-axis of the accelerometer int val = 0;void setup() {  // initialize the serial communications:  Serial.begin(9600);  // Provide ground and power by using the analog inputs as normal  // digital pins.  This makes it possible to directly connect the  // breakout board to the Arduino.  If you use the normal 5V and  // GND pins on the Arduino, you can remove these lines.  pinMode(groundpin, OUTPUT);  pinMode(powerpin, OUTPUT);  digitalWrite(groundpin, LOW);  digitalWrite(powerpin, HIGH);}void loop() {  val = analogRead(analogPin)-357;    // print a tab between values:  Serial.println(val);  if (val== 0) Serial.println("Level");  else if (val> 0) Serial.println("L High");  else{Serial.println("R High");  delay(100);}`
Ny

MarkT

#7
Jun 30, 2016, 12:05 am
I think I'm doing something wrong or my code isn't good, because when I face down the ADXL335 I get values around 0'85 G's in the Z axis, and I should get -1G...
+1g.  The vector is upwards.  The table pushes upwards on the board, so it senses an upwards acceleration.
We only think of gravity acting downwards because we see objects in free fall going down, whereas free-fall
is the true reference frame.  An accelerometer in free-fall registers a zero acceleration vector.  Until it hits
the ground!
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Go Up