# Some fun with an accelerometer

I recently discussed with some friends about sensors to record jump heights and hang time when kitesurfing. They are really expensive and requires to wear a phone in a waterproof case. As it is a useless sensor and I just wanted to have some fun: I tried with a cheap sensor, an µC, and some EEPROM, no need to be accurate to the centimeter…

So I wrote a really quick (30 min before going to bed), and dirty code using an old accelerometer: ADXL345. And the result is not so bad: if reset every 2 seconds to avoid drift, 75 cm delta height is measured with a precision of +/- 6 cm.

But I also need a gyroscope to be able to know the height variations no matter which orientation is the sensor: I ordered an MPU-6050 IMU which combines accelero+gyro and has some co-processor to avoid huge calculations on host processor. I might also try an ARM Cortex-M3 to speed up the refresh frequency in order to achieve better tracking.

Also, there is a lot of thesis on such subjects, often with algorithms made for huge computers, and every time the drawback is drift due to double integration… As I will use it to measure jump height, I might be able to get rid of it because lift time is small.

The following code is for Arduino with I2CDevLib library, I2C speed must be set to 400 kHz.

/* ============================================
Uses I2Cdev device library : http://www.i2cdevlib.com
*/

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#include "Wire.h"

// I2Cdev and ADXL345 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

// Declare objects

// Defines
#define G_MS2 9.80665

void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
Wire.begin();

Serial.begin( 115200 );

// Initialize device and setup
Serial.println( "Initializing I2C devices..." );
accel.initialize();

// verify connection
Serial.println( "Testing device connections..." );
}

void loop() {
// Variables declaration
float ax, ay, az, speedZOld, speedZThreshold, speedZ, positionZ, speedDelta;

unsigned long timerAccumulation, timerSerial; // the timer
unsigned long INTERVAL = 5; // the repeat interval
unsigned long INTERVAL_SERIAL = 2000;
unsigned long i;

speedZOld = 0;
speedZ = 0;
positionZ = 0;
speedDelta = 0;
speedZThreshold = 0.1;

// Start timers
timerAccumulation = millis();
timerSerial = timerAccumulation;

Serial.println( "\t\tStarting main loop" );

while (1) {

// Compute data
i = millis()-timerAccumulation;
if ( i > INTERVAL ) {
timerAccumulation += INTERVAL;      // Reset timer
az = accel.getAccelerationZ();
az = (az-231) * G_MS2 / 256.0;      // Convertion to m/s2
speedZ += az * i/1e3;               // Integration to get speed
// distance moved in deltaTime, s = 1/2 a t^2 + vt
double sz = 0.5 * az * i * i/1e6 + speedZ * i/1e3;
positionZ += sz;
}

if ( abs( speedZ ) < speedZThreshold ) {                      // If speed is behind given threshold, discard it to avoid noise accumulation
if ( abs( speedZOld ) > speedZThreshold ) {                 // If previous speed was high, it was moving
if ( abs( positionZ ) > 0.15 ) {                          // If we moved more than 0.15 cm, display it
Serial.print( az ); Serial.print( "\t" );
Serial.print( speedZ ); Serial.print( "\t" );
Serial.print( positionZ );
}
positionZ = 0;
speedZ = 0;
Serial.println( "\tReset" );
}
}
speedZOld = speedZ;

if ( (millis()-timerSerial) > INTERVAL_SERIAL ) {             // Periodic reset to clear values from noise
Serial.println( "\tReset time" );
timerSerial += INTERVAL_SERIAL;
positionZ = 0;
speedZ = 0;
}

}
}