/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#include
#include "Kalman.h" // Source: https://github.com/TKJElectronics/KalmanFilter
Kalman kalmanX;
Kalman kalmanY;
#define gyroAddress 0x68
#define adxlAddress 0x53
double zeroValue[5] = { -200, 44, 660, 52.3, -18.5}; // Found by experimenting
/* All the angles start at 180 degrees */
double gyroXangle = 180;
double gyroYangle = 180;
double compAngleX = 180;
double compAngleY = 180;
unsigned long timer;
void setup() {
Serial.begin(115200);
Wire.begin();
i2cWrite(adxlAddress, 0x31, 0x09); // Full resolution mode
i2cWrite(adxlAddress, 0x2D, 0x08); // Setup ADXL345 for constant measurement mode
i2cWrite(gyroAddress, 0x16, 0x1A); // this puts your gyro at +-2000deg/sec and 98Hz Low pass filter
i2cWrite(gyroAddress, 0x15, 0x09); // this sets your gyro at 100Hz sample rate
kalmanX.setAngle(180); // Set starting angle
kalmanY.setAngle(180);
timer = micros();
}
void loop() {
double gyroXrate = -(((double)readGyroX() - zeroValue[3]) / 14.375);
gyroXangle += gyroXrate * ((double)(micros() - timer) / 1000000); // Without any filter
double gyroYrate = (((double)readGyroY() - zeroValue[4]) / 14.375);
gyroYangle += gyroYrate * ((double)(micros() - timer) / 1000000); // Without any filter
double accXangle = getXangle();
double accYangle = getYangle();
compAngleX = (0.93 * (compAngleX + (gyroXrate * (double)(micros() - timer) / 1000000))) + (0.07 * accXangle);
compAngleY = (0.93 * (compAngleY + (gyroYrate * (double)(micros() - timer) / 1000000))) + (0.07 * accYangle);
double xAngle = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros() - timer)); // calculate the angle using a Kalman filter
double yAngle = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros() - timer)); // calculate the angle using a Kalman filter
timer = micros();
/* print data to processing */
Serial.print(gyroXangle); Serial.print("\t");
Serial.print(gyroYangle); Serial.print("\t");
Serial.print(accXangle); Serial.print("\t");
Serial.print(accYangle); Serial.print("\t");
Serial.print(compAngleX); Serial.print("\t");
Serial.print(compAngleY); Serial.print("\t");
Serial.print(xAngle); Serial.print("\t");
Serial.print(yAngle); Serial.print("\t");
Serial.print("\n");
delay(10);
}
void i2cWrite(uint8_t address, uint8_t registerAddress, uint8_t data) {
Wire.beginTransmission(address);
Wire.write(registerAddress);
Wire.write(data);
Wire.endTransmission();
}
uint8_t* i2cRead(uint8_t address, uint8_t registerAddress, uint8_t nbytes) {
uint8_t data[nbytes];
Wire.beginTransmission(address);
Wire.write(registerAddress);
Wire.endTransmission();
Wire.beginTransmission(address);
Wire.requestFrom(address, nbytes);
for (uint8_t i = 0; i < nbytes; i++)
data[i] = Wire.read();
Wire.endTransmission();
return data;
}
int readGyroX() { // This really measures the y-axis of the gyro
uint8_t* data = i2cRead(gyroAddress, 0x1F, 2);
return ((data[0] << 8) | data[1]);
}
int readGyroY() { // This really measures the x-axis of the gyro
uint8_t* data = i2cRead(gyroAddress, 0x1D, 2);
return ((data[0] << 8) | data[1]);
}
double getXangle() {
double accXval = (double)readAccX() - zeroValue[0];
double accZval = (double)readAccZ() - zeroValue[2];
double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
return angle;
}
double getYangle() {
double accYval = (double)readAccY() - zeroValue[1];
double accZval = (double)readAccZ() - zeroValue[2];
double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG;
return angle;
}
int readAccX() {
uint8_t* data = i2cRead(adxlAddress, 0x32, 2);
return (data[0] | (data[1] << 8));
}
int readAccY() {
uint8_t* data = i2cRead(adxlAddress, 0x34, 2);
return (data[0] | (data[1] << 8));
}
int readAccZ() {
uint8_t* data = i2cRead(adxlAddress, 0x36, 2);
return (data[0] | (data[1] << 8));
}