//-*-c++-*- // read values from a ADXL 3xx accellerometer // jet@flatline.net // 15 Mar 08 // // What we're doing is taking a reading and then comparing it to an // average of the past N readings as a way of filtering out noise. // Depending on how much stability you want, you might just compare it // to 2 or 4 readings or as many as 16. // // to get an idea of what "noise" looks like, just read/print the // values from the ADXL as fast as you can then put the sensor on a // very stable surface. You'll notice that the values change by small // amounts, even when you think the sensor is perfectly still. This // noise makes it hard to know if the chip is really moving or how // fast it is moving. // note: there are a number of ways to deal with noise, this is just one way. // what we do is: // 1) read the current values and update our array of past values // 2) compute averages of our last sampleSize reads // 3) compare our current value to the average to determine if we've moved // // another way would be to store the previous sensor value, then // compare it to the current sensor value and ignore it if the // absolute value is within some small range: // // static int noise = 5; // if (abs(curVal - oldVal) > 5) { // assume there's been movement and not noise // } //Output static int statusLed = 13; // input static int adxl_pin_x = 0; static int adxl_pin_y = 1; static int adxl_pin_z = 2; int xVal = 0; int yVal = 0; int zVal = 0; #define sampleSize 8 // MUST be a multiple of 2, see later for why #define shiftBits 3 // sampleSize = 2 ^ shiftBits // I picked startVal somewhat arbitrariliy. What you probably should // do is read the sensor in setup(), do some calibrations by turning // the sensor on and off with the reset pin (ST), and pick a good // starting value. static int startVal = 512; int curSamp = 0; int xVals[sampleSize]; int yVals[sampleSize]; int zVals[sampleSize]; int xAvg = 0; int yAvg = 0; int zAvg = 0; int xPreAvg = 0; int yPreAvg = 0; int zPreAvg = 0; void setup() { pinMode(statusLed,OUTPUT); pinMode(adxl_pin_x,INPUT); pinMode(adxl_pin_y,INPUT); pinMode(adxl_pin_z,INPUT); for (int i=0; i < sampleSize; i++) { xVals[i] = startVal; yVals[i] = startVal; zVals[i] = startVal; } beginSerial(9600); } void loop() { blinkLed(statusLed, 10); // we use curSamp as an index into the array and increment at the // end of the main loop(), so see if we need to reset it at the // very start of the loop if (curSamp == sampleSize) { curSamp = 0; } xVal = GetAdxlX(); yVal = GetAdxlY(); zVal = GetAdxlZ(); xVals[curSamp] = xVal; yVals[curSamp] = yVal; zVals[curSamp] = zVal; xPreAvg = xAvg; yPreAvg = yAvg; zPreAvg = zAvg; xAvg = 0; yAvg = 0; zAvg = 0; for (int i=0; i < sampleSize; i++) { xAvg += xVals[i]; yAvg += yVals[i]; zAvg += zVals[i]; } // for those who didn't grow up on C, "x >> y" is a way of saying // shift the bits in variable x y bits to the right, effectively // dividing by 2 and losing the remainder. 1 bit is in half, 2 // bits is 1/4, and so on. It's much faster than using the divide // operator "/" if you're working with powers of 2. (Ok, so a // good compiler would optimize that for you, but this is just in // case.) xAvg = (xAvg >> shiftBits); yAvg = (yAvg >> shiftBits); zAvg = (zAvg >> shiftBits); // dump the values. move the sensor quickly, slowly, bang on it, // etc, and watch how these values change. // // extra credit: read this data in Processing and plot out! Serial.print(xPreAvg); Serial.print(" "); Serial.print(xAvg); Serial.print(" "); Serial.print(xVal); Serial.print(" | "); Serial.print(yPreAvg); Serial.print(" "); Serial.print(yAvg); Serial.print(" "); Serial.print(yVal); Serial.print(" | "); Serial.print(zPreAvg); Serial.print(" "); Serial.print(zAvg); Serial.print(" "); Serial.println(zVal); // increment our array pointer curSamp++; } int GetAdxlX() { return(analogRead(adxl_pin_x)); } int GetAdxlY() { return(analogRead(adxl_pin_y)); } int GetAdxlZ() { return(analogRead(adxl_pin_z)); } void blinkLed(int pin, int ms) { digitalWrite(pin,LOW); // turn it off it was on digitalWrite(pin,HIGH); delay(ms); digitalWrite(pin,LOW); delay(ms); }