How to read from both axis on accelerometer.

Hello,

  • I am using an Arduino UNO with a single axis ADXL193 +/-250g accelerometer (https://www.sparkfun.com/products/9332) to measure the G-force of an impact and print to a serial LCD screen (https://www.sparkfun.com/products/9393).

  • I can get a reading on the screen of impacts in one direction on the axis, but not for the other - presumably because of the way I have used the ‘if’ command to limit what is sent to the LCD.

How do I need to change my code so I can read G-force on both directions of the axis, and write the highest G impact to the screen?

Also, I think currently the most recent reading of the impact above 80G is being printed to the screen, rather than the largest in that ‘hit’, What do I need to change to ensure the highest G-force in each ‘hit’ is printed to the LCD?

Many thanks, I have attached my code for reference.

/*
  PrintGForceLCD- Accelerometer
  Reads an analog input on pin 0, converts it to g force, and prints the result to the LCD.
  Attach the center pin of the accelerometer to pin A0, and the outside pins to +5V and ground.

 */

#include <SoftwareSerial.h> // Use the softwareserial library to create a new "soft" serial port for display.

SoftwareSerial mySerial(3,2); // pin 2 = TX, pin 3 = RX // Attach the serial display's RX line to digital pin 2

// the setup routine runs once when you press reset:

void setup() {
  // initialize serial commun4ication at 9600 bits per second:
  
  mySerial.begin(9600);                  // set up serial port for 9600 baud
  delay(500);                            // wait for display to boot up

  mySerial.write(254);			 // move cursor to beginning of first line
  mySerial.write(128);
  mySerial.write("                ");	 // clear display
  mySerial.write("                ");
  mySerial.write(254); 			 // move cursor to beginning of first line
  mySerial.write(128);
  mySerial.write("READY");		 // write “READY” on screen
}
  

void loop() {
 
  int sensorValue = analogRead(A0); 		 // read the input on analog pin 0: the accelerometer
  
  float voltage = sensorValue * (5.0 / 1023.0);	 // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
 
  float g_force = (voltage - 2.48) / 0.008 ;	 //work out the g-force reading from the voltage
  
  if (g_force > 3)				 //if g_force is greater than 80 = print to the LCD

{
  mySerial.write(254);				 // move cursor to beginning of first line
  mySerial.write(128);

  mySerial.write("                "); 		// clear display
  mySerial.write("                ");

  mySerial.write(254); 				// move cursor to beginning of first line
  mySerial.write(128);
 
  mySerial.print("G Force = ") ;		// Write "G Force ="
  mySerial.print(g_force);			// Write g force reading from accelerometer
}

}

A single axis accelerometer is a single axis sensor. There is no second axis to get data from. To get acceleration in the other direction you would need to rotate the sensor in the required direction, in flight!. I’m sure getting a multiple axis sensor (probably 3-axis) is more practical. Or get a second sensor and mount it perpendicular to the first or whatever direction is of interest, and connect it to a different input pin.

Valen:
A single axis accelerometer is a single axis sensor. There is no second axis to get data from. To get acceleration in the other direction you would need to rotate the sensor in the required direction, in flight!. I’m sure getting a multiple axis sensor (probably 3-axis) is more practical. Or get a second sensor and mount it perpendicular to the first or whatever direction is of interest, and connect it to a different input pin.

I see what you’re saying; but as the ‘rest’ reading of the accelerometer with (at 5v) is around 2.5v = 0G and this increases with the G-force in one direction, and decreases in the other - surely there is a way to not only read the increased voltage as a force, but also the decreased voltage?

Oh ok, so you are talking about the negative side of the axis. Well your code should be able to calculate negative G-forces from the voltage given by the sensor when they are below 2.5-ish volt. Does it not give out negative numbers if you remove the if(g_force > 3) condition?

To give out a reading when the g-force is less than -3g or more than 3g then you need to modify the above if-condition to:

if abs(g_force)>3    // the function abs() returns the given parameter without the sign,
                            //  so when outside of the range -3g to +3g, it does the following...
   { // do your stuff  }

[EDIT] I hope you have read the datasheet. It says this sensor has a (Bessel function) filter inside that filters out vibrations from crashes. So I suspect this one isn’t very well suited for impact analysis. But I guess it depends on what you want to learn from it. Just so you know.

From Page 8 of datasheet…:
Signals from crashes and other events may contain high

amplitude, high frequency components. These components

contain very little useful information and are reduced by the

2-pole Bessel filter at the output of the accelerometer.

Also,

float g_force = (voltage - 2.48) / 0.008 ;

Using a fixed reference voltage of 2.48 is risky. What if due to temperature differences in the system, or noisy USB input voltage or low batteries the voltage regulator is slightly off from what you expect, so the 0g voltage might be different? I suggest you measure the voltage of the sensor right before letting the device under test loose (while it is still in 0g state) to get this baseline value. Once the device-under-test is about to impact, can you measure and calculate the actual g-force.

A measurement made is only as good as it’s reference value.

Ok, it also helps to actually read what you wrote, instead of answering about what I think you should do. :wink:

You want to report the highest extreme of the signal, which can be either negative or positive g, or maybe you even want to know both. For that you need to sample the sensor output quickly and compare it to the previously stored (positive or negative) latest highest value. If it is further away from 0 then you update the latest highest value, to be used after the next sample.

But for that to work correctly you need a very quick loop. As impacts tend to take very little time. So get rid of those float calculations, and serial communications. Those take ages to complete for a micro-controller, and with your current program taking the next sample from your sensor has to wait for that to finish. So postpone that until the sensor readings have come to rest again, or after some fixed impact duration time. You do the comparisons and computations with just the sensed sensor value in integer format.

Pseudo Arduino code, and probably full of bugs:

setup:
{
int max_g=0;
int min_g=0;
int g_force_int=0;
int baseline_value=sense sensor_value;

long impact_duration=1e6; // one second
long start_time=millis();
long end_time=start_time+impact_duration;

// insert code to cause impact to begin
}

loop:
{
if (millis()<end_time) // is impact still going on?
  { sense  sensor_value; //sampling sensor value
    g_force_int= (sensor_value-baseline_value); //correct ADC value for 0g baseline
    if (g_force_int>max_g) {max_g=g_force_int;} // check for new max positive g, and raise the bar.
    if (g_force_int<min_g) {min_g=g_force_int;}  // check for new max negative g, and 'lower' the bar.
  } // done with sample comparison
else
 { // impacting is done
 // insert code to calculate max_g and min_g into float values, and send to serial or LCD
  // maybe also time of impact period 
 // ...
 // insert code to wait or cause the next impact session to start
  // ...
  // restart sampling the sensor
    max_g=0;
    min_g=0;
    g_force_int=0;
   
   start_time=millis();
    end_time=start_time+impact_duration;
  } // end reporting and resetting phase

} // end loop

I think that should be the general structure.

Valen:
You want to report the highest extreme of the signal, which can be either negative or positive g, or maybe you even want to know both. For that you need to sample the sensor output quickly and compare it to the previously stored (positive or negative) latest highest value. If it is further away from 0 then you update the latest highest value, to be used after the next sample.

Yeah, that’s exactly it. Thank you for the code, I will have a go at adjusting it.

Much appreciated.