Go Down

Topic: Monitoring Motion with Accelerometer (Read 3480 times)previous topic - next topic

willstumpf

Jul 15, 2012, 04:34 pm
Hi,

I am working on a project using an Arduino Duemilanove and a MMA7260QT 3 axis accelerometer, the project goal is to be able to monitor the motion of a person while they are laying down, for example the sensor could be positioned on the persons chest and I would like to be able to record the amount of motion in all axes. The ideal outcome of this project would be while the person was breathing it would be monitoring the motion in the z-axis and if they shifted their position it would record the data from the x and z axes as well.

Below is currently all my code for this project. To convert the acceleration to positon I have to integrate the acceleration twice, but how exactly would I do this? A little while ago I found a PDF that was similar to my project and it explained how they were getting position from the acceleration, it was kind of confusing because their code was pretty weird. This is what I got out of it:

Code: [Select]
`//============================================================================// analyzeAccelerometer - performs double integration on x, y, and z axes//============================================================================void analyzeAccelerometer(){  // acceleration[i][j]    // acceleration[0][j] is x  // acceleration[1][j] is y  // acceleration[2][j] is z    // let j = 0 be initial/previous, j = 1 be current    // outer loop that handles: x, y, z;    for (int j = 0; j < 3; j++)  {    // get the velocity    velocity[j][1] = velocity[j][0] + acceleration[j][0] + ((acceleration[j][1] - acceleration[j][0]) / 2);        // get the distance    position[j][1] = position[j][0] + velocity[j][0] + ((velocity[j][1] - velocity[j][0]) / 2);        // get ready for the next set of readings    acceleration[j][0] = acceleration[j][1];    velocity[j][0] = velocity[j][1];    position[j][0] = position[j][1];  }  }`

Is this correct? Right now if I run the program and just have the accelerometer sitting still, because of error the position just adds up, would I be able to compensate for that with having a logic statement where it would check the accelerometer readings and ignore minute changes therefore hopefully making cleaner data?

I was talking to someone else about it and they suggested using these two equations somehow:

Code: [Select]
`x=v0 * t + 1/2 at**2v=v0+at`

Would this be better or more helpful?

Currently, I just have an accelerometer (MMA7260QT) and a gyro but I am only using the accelerometer at the moment, should I purchase a IMU would that make this process easier?

Here is my full code:

Code: [Select]
`//============================================================================// MMA7260QT Accelerometer//============================================================================#define ACCEL_X A2#define ACCEL_Y A1#define ACCEL_Z A0double accelerometerOffsetX = 0.0;double accelerometerOffsetY = 0.0;double accelerometerOffsetZ = 0.0;double acceleration[3][2] = {{0,0}, {0,0}, {0,0}};double velocity[3][2] = {{0,0}, {0,0}, {0,0}};double position[3][2] = {{0,0}, {0,0}, {0,0}};//============================================================================// setup - Arduino Setup Funciton//============================================================================void setup(){  Serial.begin(9600);  initAccelerometer(5, 1);}//============================================================================// loop//============================================================================void loop(){  acceleration[0][1] =    readAccelerometer(ACCEL_X) - accelerometerOffsetX;         // x-axis  acceleration[1][1] =    readAccelerometer(ACCEL_Y) - accelerometerOffsetY;         // y-axis  acceleration[2][1] = -( readAccelerometer(ACCEL_Z) - accelerometerOffsetZ) + 1.0;  // z-axis inverse, 1 g for earth gravity.  analyzeAccelerometer();//  Serial.print("X: "); //  Serial.print(acceleration[0][1]);////  Serial.print(" Y: "); //  Serial.print(acceleration[1][1]);////  Serial.print(" Z: "); //  Serial.print(acceleration[2][1]);  Serial.print(position[0][1]);    Serial.println();  // delay 50 milliseconds  delay(50);}//============================================================================// initAccelerometer - Initializes everything for the accelerometer//============================================================================void initAccelerometer(int sleepPin, int sleepValue){  // Set the sleepPin to output  pinMode(sleepPin, OUTPUT);  // This turns the sensor on or off  // sleepValue = 1 the sensor is OFF  // sleepValue = 0 the sensor is ON  analogWrite(sleepPin, sleepValue);  // delay 1 second to get the sensor in position  delay(1000);  calibrateAccelerometer();}//============================================================================// calibrateAccelerometer - Handles all the calibration needed//============================================================================void calibrateAccelerometer(){      double x_raw = 0;  double y_raw = 0;  double z_raw = 0;    Serial.println("Calibrating...\n");  // To calibrate we are going to take 1024 readings from the accelerometer  // and average them to calculate the offset  for (int i = 0; i < 1024; i++)  {    x_raw += analogRead(ACCEL_X);    y_raw += analogRead(ACCEL_Y);    z_raw += analogRead(ACCEL_Z);  }    x_raw = x_raw / 1024;  y_raw = y_raw / 1024;  z_raw = z_raw / 1024;    // analogRead can be used without setting the pinMode.  // 5.0 : The range of the ADC: 3.3V or 5V  // 1023.0 :  1023 = 2^10 -1, the maximum raw value at the maximum voltage for a range of 0 - 1023  // 0.8 : the number of mV/g. It is 800mv/G for 1.5g range.  // 1.08 : the gain to compensate for a little less than 10% error  x_raw = (double) x_raw * 5.0 / 1023.0 / 0.8;  accelerometerOffsetX = x_raw * 1.08;    y_raw = (double) y_raw * 5.0 / 1023.0 / 0.8;    accelerometerOffsetY = y_raw * 1.08;    z_raw = (double) z_raw * 5.0 / 1023.0 / 0.8;    accelerometerOffsetZ = z_raw * 1.08;}//============================================================================// readAccelerometer - reads the current output from the accelerometer//============================================================================double readAccelerometer(int thePin){  // what we are returning  double g;  double data = 0;    // To remove noise from accelerometer readings we are going to  // sample the sensor 64 times and average the results.    for (int i = 0; i < 64; i++)  {    data += analogRead(thePin);  }  // average it  // since we took 64 readings, divide by 64;    data /= 64;    // analogRead can be used without setting the pinMode.  // 5.0 : The range of the ADC: 3.3V or 5V  // 1023.0 :  1023 = 2^10 -1, the maximum raw value at the maximum voltage for a range of 0 - 1023  // 0.8 : the number of mV/g. It is 800mv/G for 1.5g range.  // 1.08 : the gain to compensate for a little less than 10% error  g = (double) data * 5.0 / 1023.0 / 0.8;  g *= 1.08;   return (g);}//============================================================================// analyzeAccelerometer - performs double integration on x, y, and z axes//============================================================================void analyzeAccelerometer(){  // acceleration[i][j]    // acceleration[0][j] is x  // acceleration[1][j] is y  // acceleration[2][j] is z    // let j = 0 be initial/previous, j = 1 be current    // outer loop that handles: x, y, z;    for (int j = 0; j < 3; j++)  {    // get the velocity    velocity[j][1] = velocity[j][0] + acceleration[j][0] + ((acceleration[j][1] - acceleration[j][0]) / 2);        // get the distance    position[j][1] = position[j][0] + velocity[j][0] + ((velocity[j][1] - velocity[j][0]) / 2);        // get ready for the next set of readings    acceleration[j][0] = acceleration[j][1];    velocity[j][0] = velocity[j][1];    position[j][0] = position[j][1];  }       }`

If someone could try to point me in the right direction that would be great. Thanks!
-Will

MarkT

#1
Jul 15, 2012, 04:41 pm
Integrating twice leads to a signal with extreme amounts of drift - you will need to high-pass filter the result to lose the drift and retain the short-time-scale information.  From an accelerometer thats not moving fast you can derive orientation vector too (low pass filtering helps with this).  This can then provide an estimate of the gravity component to subtract from the input to the integration steps.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

willstumpf

#2
Jul 16, 2012, 03:45 pm
Mark,

Thank you, I will look into them. Is it possible to use just an accelerometer for this project or will I need a gyro (I guess I would just upgrade to an IMU?)

Thanks,
-Will

lucavd

#3
Nov 21, 2012, 03:23 pm
Any improvement so far?

Go Up