Electronic – arduino – Understanding how to use an accelerometer to detect vehicle collisions

accelerometerarduino

Objective: To use an accelerometer to detect where on a vehicle a crash occurred (e.g. impact occurred on the passenger side.).

Parts: Arduino Uno and LSM3030DLHC accelerometer

Background: I've been using the code provided in the reference 1 below and I'm having trouble interfacing with the accelerometer component. At rest, the accelerometer is measuring acceleration along all the axis as close to 0g 0g 1g as possible. By doing some background reading in [2] I've come to the conclusion that I can use the force vector to determine the angle where the impact occurred. I'm not sure if I'm testing the impact incorrectly or what is happening but if I hit the breadboard to the right of the accelerometer, inside the well, it sometimes produced different values on the various axis (see sample output). From the reading in [2] I determined that if I use the magnitude variable and the changes in acceleration along the x and y axis I should be able to determine the angle where an impact occurred but this impact is always around the same value regardless if I hit it at the right of the accelerometer or to the left.

Questions:

1) Is the angle being measured using the magnitude R = sqrt(x^2 + y^2 + z^2) not relative to the x-y axis? So I would like to be able to say that if there is an impact on the right side in the picture then that is a collision on the right passenger side.

2) Why does the accelerometer produce different values along all the axis even though the breadboard would be hit in roughly the same spot? Note, I don't mean that the values are slightly off but rather that they would be negative sometimes and positive at others.

Code Walkthrough: The program begins and the accelerometer is initialized. The impact routine is called every 2ms and it gets the acceleration axis readings and then another axis reading and compares them. If the magnitude exceeds some sensitivity value then there is a successful hit and more data is logged. Otherwise if it doesn't exceed this sensitivity we go back to searching.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <math.h>

byte updateflag;

Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(54321);
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);


sensors_event_t event;
sensors_event_t magEvent;

int xaxis = 0, yaxis = 0, zaxis = 0;
int deltx = 0, delty = 0, deltz = 0;
int vibration = 0, magnitude = 0, sensitivity = 0, devibrate = 0;
double angle;
unsigned long time1; //Time when the program started. Used to run impact routine every 2mS.
unsigned long time2;
float impactDirection; //Direction car was traveling prior to impact.


void setup()
{
  Wire.begin();
  sensitivity=15;
  devibrate=75;

  Serial.begin(9600);

  //Initialize component;
  if(!accel.begin())
  {

    Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
    while(1);
  }
  if(!mag.begin())
  {
  Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
  while(1);
  }

  time1 = micros(); 
  //Serial.print("time1 = "); Serial.println(time1);
}

void loop()
{
  accel.getEvent(&event);
  mag.getEvent(&magEvent);

  if (micros() - time1 > 1999) Impact();  // call impact routine every 2mS

  if(updateflag > 0) 
  {
    updateflag=0;
    Serial.print("Impact detected!!\tMagnitude:"); Serial.print(magnitude);
    Serial.print("\t Angle:"); Serial.print(angle, 2);
    Serial.print("\t Car Direction: "); Serial.print(impactDirection);
    Serial.print(" ("); Serial.print(compassDirection(impactDirection)); Serial.println(")");
    Serial.println();
  }

}


void Impact()
{

  /* 
  //Calibration testing. Accelerometer is calibrated correctly x ~0 y ~0 z ~9.8
  Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" ");
  Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" ");
  Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print(" ");Serial.println("m/s^2 ");
  */

  time1 = micros(); // resets time value

  int oldx = xaxis; // local variables store previous axis readings for comparison
  int oldy = yaxis;
  int oldz = zaxis;

  //Serial.print("current time = "); Serial.print(micros()); Serial.print("\toldx = "); Serial.print(oldx); Serial.print("\toldy = "); Serial.print(oldy); Serial.print("\toldz = "); Serial.println(oldz);

  vibration--; // loop counter prevents false triggering. Vibration resets if there is an impact. Don't detect new changes until that "time" has passed.
  //Serial.print("Vibration = "); Serial.println(vibration);
  if(vibration < 0) vibration = 0;                                
  //Serial.println("Vibration Reset!");
  //Serial.println("****************************");

  xaxis = event.acceleration.x; 
  yaxis = event.acceleration.y; 
  zaxis = event.acceleration.z;

  //Serial.print("current time = "); Serial.print(micros()); Serial.print("\txaxis = "); Serial.print(xaxis); Serial.print("\tyaxis = "); Serial.print(yaxis); Serial.print("\tzaxis = "); Serial.println(zaxis);
  //Serial.println("****************************");

  if(vibration > 0) return;

  deltx = xaxis - oldx;                                           
  delty = yaxis - oldy;
  deltz = zaxis - oldz;

  magnitude = sqrt(sq(deltx) + sq(delty) + sq(deltz)); //Magnitude to calculate force of impact.

  if (magnitude >= sensitivity) //impact detected
  {

    //Values that caused the impact
    Serial.print("Impact Time = "); Serial.print(micros()); Serial.print("\t\tCar Direction = "); Serial.print(getHeading(magEvent)); Serial.print(" "); Serial.println(compassDirection(getHeading(magEvent))); 
    Serial.print("oldx = "); Serial.print(oldx); Serial.print("\toldy = "); Serial.print(oldy); Serial.print("\toldz = "); Serial.println(oldz);
    Serial.print("xaxis = "); Serial.print(xaxis); Serial.print("\tyaxis = "); Serial.print(yaxis); Serial.print("\tzaxis = "); Serial.println(zaxis);
    Serial.print("Mag = "); Serial.print(magnitude);
    Serial.print("\tdeltx = "); Serial.print(deltx);
    Serial.print("\tdelty = "); Serial.print(delty);
    Serial.print("\tdeltz = "); Serial.println(deltz);


    updateflag=1;
    impactDirection = getHeading(magEvent);

    //double X = xaxis - 512; // adjust xaxis reading to +/- 512
    //double Y = yaxis - 512; // adjust yaxis reading to +/- 512

    double X = acos((double) deltx / magnitude);
    double Y = acos((double) delty / magnitude);

    Serial.print("X = "); Serial.print(X); Serial.print("Y = "); Serial.println(Y);

    Serial.println("****************************");

    angle = (atan2(Y,X) * 180)/PI; // use atan2 to calculate angle and convert radians to degrees
    angle += 180;                                               

    vibration = devibrate;                                      // reset anti-vibration counter
    time2 = millis();  
  }
  else
  {
    //if (magnitude > 15)
      //Serial.println(magnitude);
    magnitude=0;                                              // reset magnitude of impact to 0
  }
}

float getHeading(sensors_event_t &event)
{
   float heading = (atan2(event.magnetic.y,event.magnetic.x) * 180) / PI;
   if (heading < 0)
      heading = 360 + heading;

   return heading;

}

String compassDirection(float heading)
{
    int val = (int) ((heading / 22.5) + .5);
    String arr [] = {"N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"};

    return arr[(val % 16)];
}

enter image description here

Output:

Impact Time = 1988808 Car Direction = 55.69 NE oldx = 0 oldy = 0 oldz
= 9 xaxis = -2 yaxis = 13 zaxis = -20 Mag = 31 deltx = -2 delty = 13 deltz = -29 X = 1.64Y = 1.14
**************************** Impact detected!! Magnitude:31 Angle:214.83 Car Direction: 55.69 (NE)

Impact Time = 5076556 Car Direction = 56.86 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = 13 yaxis = 0 zaxis = -13 Mag = 25 deltx = 13 delty
= 0 deltz = -22 X = 1.02Y = 1.57
**************************** Impact detected!! Magnitude:25 Angle:236.90 Car Direction: 56.86 (ENE)

Impact Time = 8273600 Car Direction = 57.63 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = -1 yaxis = 11 zaxis = -20 Mag = 31 deltx = -1 delty
= 11 deltz = -29 X = 1.60Y = 1.21
**************************** Impact detected!! Magnitude:31 Angle:217.00 Car Direction: 57.63 (ENE)

Impact Time = 12727924 Car Direction = 57.27 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = -3 yaxis = 10 zaxis = -17 Mag = 28 deltx = -3 delty
= 10 deltz = -26 X = 1.68Y = 1.21
**************************** Impact detected!! Magnitude:28 Angle:215.69 Car Direction: 57.27 (ENE)

Impact Time = 14347336 Car Direction = 57.15 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = 16 yaxis = 2 zaxis = -19 Mag = 32 deltx = 16 delty
= 2 deltz = -28 X = 1.05Y = 1.51
**************************** Impact detected!! Magnitude:32 Angle:235.23 Car Direction: 57.15 (ENE)

Impact Time = 15695684 Car Direction = 57.20 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = 1 yaxis = 4 zaxis = -8 Mag = 17 deltx = 1 delty =
4 deltz = -17 X = 1.51Y = 1.33
**************************** Impact detected!! Magnitude:17 Angle:221.41 Car Direction: 57.20 (ENE)

Impact Time = 17879680 Car Direction = 57.27 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = 14 yaxis = 7 zaxis = -18 Mag = 31 deltx = 14 delty
= 7 deltz = -27 X = 1.10Y = 1.34
**************************** Impact detected!! Magnitude:31 Angle:230.62 Car Direction: 57.27 (ENE)

Impact Time = 19149812 Car Direction = 57.08 ENE oldx = 12 oldy =
1 oldz = -10 xaxis = 2 yaxis = -3 zaxis = 5 Mag = 18 deltx = -10 delty
= -4 deltz = 15 X = 2.16Y = 1.79
**************************** Impact detected!! Magnitude:18 Angle:219.73 Car Direction: 57.08 (ENE)

Impact Time = 23040448 Car Direction = 56.63 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = 2 yaxis = 10 zaxis = -14 Mag = 25 deltx = 2 delty =
10 deltz = -23 X = 1.49Y = 1.16
**************************** Impact detected!! Magnitude:25 Angle:217.87 Car Direction: 56.63 (ENE)

Impact Time = 25968304 Car Direction = 57.11 ENE oldx = 0 oldy =
0 oldz = 9 xaxis = 0 yaxis = 5 zaxis = -7 Mag = 16 deltx = 0 delty =
5 deltz = -16 X = 1.57Y = 1.25
**************************** Impact detected!! Magnitude:16 Angle:218.58 Car Direction: 57.11 (ENE)

Best Answer

The real problem is always the simplest. Generally you have a lot of noise on these sensors and you just need to make sure you know what you need to filter. A quick noisy pulse on the sensor can lead to an extremely high-g reading since there is not a lot of mass attached. If the board is susceptible to noise in one area you may be receiving a constant pulse to one side. Though it looks like you are doing some filtering I would suggest running a median filter before getting the angle to insure these high-g impulses are taken care of.

In addition, I would like to point out the sampling rate of your sensor. Look at the ODR of the sensor. Though the accelerometer has an ODR of over 1kHz, the magnetometer is limited down at 220Hz. If you want to do anything past this angle detection, I would suggest getting a low-g/gyro sensor. This will allow you do do fun rotation projects. The magnetometer can be used for this but comes with a ton of shielding problems and far to slow an update rate with given ODR.

Related Topic