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"
#include "ADXL345.h"
// Declare objects
ADXL345 accel;
// 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();
accel.setRate( ADXL345_RATE_200 );
accel.setRange( ADXL345_RANGE_2G );
// verify connection
Serial.println( "Testing device connections..." );
Serial.println( accel.testConnection() ? "ADXL345 connection successful" : "ADXL345 connection failed" );
}
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;
}
}
}
Share this post
Twitter
Google+
Facebook
Reddit
LinkedIn
StumbleUpon
Pinterest
Email