@ -136,9 +136,13 @@ void GYRO::acc_gyro_init(void) {
write_register ( GYRO_CONFIG , INV_FSR_2000DPS < < 3 | FCB_DISABLED ) ;
delay ( 15 ) ;
// write_register(GYRO_CONFIG, INV_FSR_250DPS << 3 | FCB_DISABLED);
// delay(15);
write_register ( ACCEL_CONFIG , INV_FSR_16G < < 3 ) ;
delay ( 15 ) ;
//write_register(ACCEL_CONFIG, INV_FSR_4G << 3);
//delay(15);
write_register ( CONFIG , 0x07 ) ; // 7:0 6:0 5:0 4:0 3:0 2:1 1:1 0:1
delay ( 15 ) ;
@ -168,9 +172,12 @@ void GYRO::calculate_imu_error(void) {
// Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
// Read accelerometer values 200 times
while ( c < 200 ) {
AcX = read_register ( ACCEL_XOUT_H ) < < 8 | read_register ( ACCEL_XOUT_L ) ;
AcY = read_register ( ACCEL_YOUT_H ) < < 8 | read_register ( ACCEL_YOUT_L ) ;
AcZ = read_register ( ACCEL_ZOUT_H ) < < 8 | read_register ( ACCEL_ZOUT_L ) ;
AcX = ( read_register ( ACCEL_XOUT_H ) < < 8 | read_register ( ACCEL_XOUT_L ) ) / 2048.0 ;
AcY = ( read_register ( ACCEL_YOUT_H ) < < 8 | read_register ( ACCEL_YOUT_L ) ) / 2048.0 ;
AcZ = ( read_register ( ACCEL_ZOUT_H ) < < 8 | read_register ( ACCEL_ZOUT_L ) ) / 2048.0 ;
// AcX = (read_register(ACCEL_XOUT_H) << 8 | read_register(ACCEL_XOUT_L)) >> 11;
// AcY = (read_register(ACCEL_YOUT_H) << 8 | read_register(ACCEL_YOUT_L)) >> 11;
// AcZ = (read_register(ACCEL_ZOUT_H) << 8 | read_register(ACCEL_ZOUT_L)) >> 11;
AccErrorX = AccErrorX + ( ( atan ( ( AcY ) / sqrt ( pow ( ( AcX ) , 2 ) + pow ( ( AcZ ) , 2 ) ) ) * 180 / PI ) ) ;
AccErrorY = AccErrorY + ( ( atan ( - 1 * ( AcX ) / sqrt ( pow ( ( AcY ) , 2 ) + pow ( ( AcZ ) , 2 ) ) ) * 180 / PI ) ) ;
@ -183,24 +190,27 @@ void GYRO::calculate_imu_error(void) {
AccErrorY = AccErrorY / 200 ;
c = 0 ;
// Read gyro values 2 00 times
// Read gyro values 10 00 times
while ( c < 200 ) {
GyX = read_register ( GYRO_XOUT_H ) < < 8 | read_register ( GYRO_XOUT_L ) ;
GyY = read_register ( GYRO_YOUT_H ) < < 8 | read_register ( GYRO_YOUT_L ) ;
GyZ = read_register ( GYRO_ZOUT_H ) < < 8 | read_register ( GYRO_ZOUT_L ) ;
GyX = ( read_register ( GYRO_XOUT_H ) < < 8 | read_register ( GYRO_XOUT_L ) ) ;
GyY = ( read_register ( GYRO_YOUT_H ) < < 8 | read_register ( GYRO_YOUT_L ) ) ;
GyZ = ( read_register ( GYRO_ZOUT_H ) < < 8 | read_register ( GYRO_ZOUT_L ) ) ;
// Sum all readings
GyroErrorX = GyroErrorX + ( GyX / 16.4 ) ;
GyroErrorY = GyroErrorY + ( GyY / 16.4 ) ;
GyroErrorZ = GyroErrorZ + ( GyZ / 16.4 ) ;
// GyroErrorX = GyroErrorX + (GyX / 16.4);
// GyroErrorY = GyroErrorY + (GyY / 16.4);
// GyroErrorZ = GyroErrorZ + (GyZ / 16.4);
GyroErrorX + = GyX ;
GyroErrorY + = GyY ;
GyroErrorZ + = GyZ ;
c + + ;
}
// Divide the sum by 2 00 to get the error value
GyroErrorX = GyroErrorX / 200 ;
GyroErrorY = GyroErrorY / 200 ;
GyroErrorZ = GyroErrorZ / 200 ;
// Divide the sum by 10 00 to get the error value
GyroErrorX / = 200 ;
GyroErrorY / = 200 ;
GyroErrorZ / = 200 ;
# ifdef DEBUG_MODE
sprintf ( debug_str ,
@ -212,39 +222,103 @@ void GYRO::calculate_imu_error(void) {
void GYRO : : read_accelerometer ( void ) {
AcX = read_register ( ACCEL_XOUT_H ) < < 8 | read_register ( ACCEL_XOUT_L ) ;
AcY = read_register ( ACCEL_YOUT_H ) < < 8 | read_register ( ACCEL_YOUT_L ) ;
AcZ = read_register ( ACCEL_ZOUT_H ) < < 8 | read_register ( ACCEL_ZOUT_L ) ;
// For a range of +-16g, we need to divide the raw values by 2048, according to the datasheet
AcX = ( read_register ( ACCEL_XOUT_H ) < < 8 | read_register ( ACCEL_XOUT_L ) ) ;
AcY = ( read_register ( ACCEL_YOUT_H ) < < 8 | read_register ( ACCEL_YOUT_L ) ) ;
AcZ = ( read_register ( ACCEL_ZOUT_H ) < < 8 | read_register ( ACCEL_ZOUT_L ) ) ;
// AcX = (read_register(ACCEL_XOUT_H) << 8 | read_register(ACCEL_XOUT_L)) >> 11;
// AcY = (read_register(ACCEL_YOUT_H) << 8 | read_register(ACCEL_YOUT_L)) >> 11;
// AcZ = (read_register(ACCEL_ZOUT_H) << 8 | read_register(ACCEL_ZOUT_L)) >> 11;
// Calculating Roll and Pitch from the accelerometer data
accAngleX = ( atan ( AcY / sqrt ( pow ( AcX , 2 ) + pow ( AcZ , 2 ) ) ) * 180 / PI ) - 0.58 ; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details
accAngleY = ( atan ( - 1 * AcX / sqrt ( pow ( AcY , 2 ) + pow ( AcZ , 2 ) ) ) * 180 / PI ) + 1.58 ; // AccErrorY ~(-1.58)
// accAngleX = (atan(AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details
// accAngleY = (atan(-1 * AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)
}
void GYRO : : read_gyro ( void ) {
// Read Gyro data
previousTime = currentTime ; // Previous time is stored before the actual time read
currentTime = millis ( ) ; // Current time actual time read
elapsedTime = ( currentTime - previousTime ) / 1000 ; // Divide by 1000 to get seconds
GyX = ( read_register ( GYRO_XOUT_H ) < < 8 | read_register ( GYRO_XOUT_L ) ) / 16.4 ; // For a 2000deg/s range we have to divide first the raw value by 16.4, according to the datasheet
GyY = ( read_register ( GYRO_YOUT_H ) < < 8 | read_register ( GYRO_YOUT_L ) ) / 16.4 ;
GyZ = ( read_register ( GYRO_ZOUT_H ) < < 8 | read_register ( GYRO_ZOUT_L ) ) / 16.4 ;
GyX = ( read_register ( GYRO_XOUT_H ) < < 8 | read_register ( GYRO_XOUT_L ) ) ; // For a 2000deg/s range we have to divide first the raw value by 16.4, according to the datasheet
GyY = ( read_register ( GYRO_YOUT_H ) < < 8 | read_register ( GYRO_YOUT_L ) ) ;
GyZ = ( read_register ( GYRO_ZOUT_H ) < < 8 | read_register ( GYRO_ZOUT_L ) ) ;
// GyX = (read_register(GYRO_XOUT_H) << 8 | read_register(GYRO_XOUT_L)) >> 4; // For a 2000deg/s range we have to divide first the raw value by 16.4, according to the datasheet
// GyY = (read_register(GYRO_YOUT_H) << 8 | read_register(GYRO_YOUT_L)) >> 4;
// GyZ = (read_register(GYRO_ZOUT_H) << 8 | read_register(GYRO_ZOUT_L)) >> 4;
// Correct the outputs with the calculated error values
// Gyro X = Gyro X + 0.56; // GyroErrorX ~(-0.56)
// Gyro Y = Gyro Y - 2; // GyroErrorY ~(2)
// Gyro Z = Gyro Z + 0.79; // GyroErrorZ ~ (-0.8)
/// GyX = GyX + 0.56; // GyroErrorX ~(-0.56)
/// GyY = GyY - 2; // GyroErrorY ~(2)
/// GyZ = GyZ + 0.79; // GyroErrorZ ~ (-0.8)
// Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
gyroAngleX = GyX * elapsedTime ; // deg/s * s = deg
gyroAngleY = GyY * elapsedTime ;
yaw = GyZ * elapsedTime ;
/// gyroAngleX = GyX * elapsedTime; // deg/s * s = deg
/// gyroAngleY = GyY * elapsedTime;
//// yaw = GyZ * elapsedTime;
// Complementary filter - combine acceleromter and gyro angle values
roll = 0.96 * gyroAngleX + 0.04 * accAngleX ;
pitch = 0.96 * gyroAngleY + 0.04 * accAngleY ;
//// roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
//// pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;
}
void GYRO : : calc ( void ) {
// Subtract the offset values from the raw gyro values
GyX - = GyroErrorX ;
GyY - = GyroErrorY ;
GyZ - = GyroErrorZ ;
// Gyro angle calculations. Note: 0.0000611 = 1 /(250Hz x 65.5) <--- Example
// For this we are using: _+/-2000 dps with 16.4, So it will be:
// 0.0000304878 = 1 / (2000Hz x 16.4) and the nearest is 0.0000305
// Calculate the traveled pitch angle and add this to the angle_pitch variable
pitch + = GyX * 0.0000305 ;
roll + = GyY * 0.0000305 ;
yaw + = GyZ * 0.0000305 ;
// Calculate the traveled roll angle and add this to the angle_roll variable
// 0.000000532 = 0.0000305 * (3.142(PI) / 180degr) The Arduino sin function is in radians
// If the IMU has yawed transfer the roll angle to the pitch angle
pitch + = roll * sin ( GyZ * 0.000000532 ) ;
// If the IMU has yawed transfer the pitch angle to the roll angle
roll - = pitch * sin ( GyZ * 0.000000532 ) ;
// Accelerometer angle calculations
// Calculate the total accelerometer vector
acc_total_vector = sqrt ( ( AcX * AcX ) + ( AcY * AcY ) + ( AcZ * AcZ ) ) ;
// 57.296 = 1 / (3.142 / 180) The Arduino asin function is in radians
// Calculate the pitch angle
pitch_acc = asin ( ( float ) AcY / acc_total_vector ) * 57.296 ;
// Calculating the roll angle
roll_acc = asin ( ( float ) AcX / acc_total_vector ) * - 57.296 ;
// Accelerometer calibration value for pitch
// pitch_acc -= 0.0;
// Accelerometer calibration value for roll
// roll_acc -= 0.0;
if ( set_gyro_angles ) {
// IMU has been running
// Correct the drift of the gyro pitch angle with the accelerometer pitch angle
pitch = pitch * 0.9996 + pitch_acc * 0.0004 ;
// Correct the drift of the gyro roll angle with the accelerometer roll angle
roll = roll * 0.9996 + roll_acc * 0.0004 ;
} else {
// IMU just started
pitch = pitch_acc ;
roll = roll_acc ;
set_gyro_angles = true ;
}
// To dampen the pitch and roll angles complementary filter is used
// Take 90% of the output pitch value and add 10% of the raw pitch value
pitch_dmp = pitch_dmp * 0.9 + pitch * 0.1 ;
roll_dmp = roll_dmp * 0.9 + roll * 0.1 ;
}
@ -325,6 +399,9 @@ void GYRO::calculate_angles_beta(void) {
// Old multiwii code uses void getEstimatedAltitude();
void GYRO : : calculate_angles ( void ) {
//// calc(); return;
uint8_t axis ;
int32_t accMag = 0 ;
float scale ;
@ -340,13 +417,37 @@ void GYRO::calculate_angles(void) {
float invG ; // 1/|G|
static int16_t accZoffset = 0 ;
int32_t accZ_tmp = 0 ;
static uint16_t previousT ;
uint16_t currentT = micros ( ) ;
// Calculate position based on gyro and accelerometers data
calc ( ) ;
if ( ( int32_t ) yaw > ACCZ_25deg ) {
flags . SMALL_ANGLES_25 = 1 ;
} else {
flags . SMALL_ANGLES_25 = 0 ;
}
att . angle [ ROLL ] = roll ;
att . angle [ PITCH ] = pitch ;
att . heading = yaw ;
/// MAY NEED TO FINE TUNE!!! ALERT !!!
# if defined(THROTTLE_ANGLE_CORRECTION)
cosZ = ( yaw * 100 ) / ACC_1G ; // cos(angleZ) * 100
throttleAngleCorrection = THROTTLE_ANGLE_CORRECTION * constrain ( 100 - cosZ , 0 , 100 ) > > 3 ; // 16 bit ok: 200*150 = 30000
# endif
/*******************
//// static uint16_t previousT;
//// uint16_t currentT = micros();
// unit: radian per bit, scaled by 2^16 for further multiplication
// with a delta time of 3000 us, and GYRO scale of most gyros, scale = a little bit less than 1
scale = ( currentT - previousT ) * ( GYRO_SCALE * 65536 ) ;
previousT = currentT ;
//// scale = (currentT - previousT) * (GYRO_SCALE * 65536);
//// previousT = currentT;
// Initialization
for ( axis = 0 ; axis < 3 ; axis + + ) {
@ -414,6 +515,7 @@ void GYRO::calculate_angles(void) {
accZoffset + = accZ ;
}
accZ - = accZoffset > > 3 ;
* * * * * * * * * * */
}