Subversion Repositories FlightCtrl

Compare Revisions

Ignore whitespace Rev 2188 → Rev 2189

/branches/dongfang_FC_rewrite/attitude_starlino.c
0,0 → 1,217
#include <stdlib.h>
#include <avr/io.h>
#include <stdio.h>
 
#include "attitude.h"
#include "commands.h"
#include "vector3d.h"
// For scope debugging only!
#include "rc.h"
 
// where our main data flow comes from.
#include "analog.h"
 
#include "configuration.h"
#include "output.h"
 
// Some calculations are performed depending on some stick related things.
#include "controlMixer.h"
 
#define CHECK_MIN_MAX(value, min, max) {if(value < min) value = min; else if(value > max) value = max;}
 
/*
* Gyro integrals. These are the rotation angles of the airframe relative to horizontal.
*/
float attitude[3];
 
uint8_t imu_sequence = 0; //incremented on each call to imu_update
 
float dcmAcc[3][3]; //dcm matrix according to accelerometer
float dcmGyro[3][3]; //dcm matrix according to gyroscopes
float dcmEst[3][3]; //estimated dcm matrix by fusion of accelerometer and gyro
 
float getAngleEstimateFromAcc(uint8_t axis) {
return GYRO_ACC_FACTOR * acc_ATT[axis];
}
 
/************************************************************************
* Neutral Readings
************************************************************************/
void attitude_setNeutral(void) {
// Calibrate hardware.
analog_setNeutral();
unsigned char i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
dcmGyro[i][j] = (i == j) ? 1.0 : 0.0;
}
 
/*
How to use this module in other projects.
 
Input variables are:
adcAvg[0..6] ADC readings of 3 axis accelerometer and 3 axis gyroscope (they are calculated in the background by adcutil.h)
interval_us - interval in microseconds since last call to imu_update
 
Output variables are:
DcmEst[0..2] which are the direction cosine of the X,Y,Z axis
 
First you must initialize the module with:
imu_init();
 
Then call periodically every 5-20ms:
imu_update(interval_us);
it is assumed that you also update periodicall the adcAvg[0..5] array
 
*/
 
#define ACC_WEIGHT_MAX 0.02 //maximum accelerometer weight in accelerometer-gyro fusion formula
//this value is tuned-up experimentally: if you get too much noise - decrease it
//if you get a delayed response of the filtered values - increase it
//starting with a value of 0.01 .. 0.05 will work for most sensors
 
#define ACC_ERR_MAX 0.3 //maximum allowable error(external acceleration) where accWeight becomes 0
 
//-------------------------------------------------------------------
// Globals
//-------------------------------------------------------------------
 
//bring dcm matrix in order - adjust values to make orthonormal (or at least closer to orthonormal)
//Note: dcm and dcmResult can be the same
void dcm_orthonormalize(float dcm[3][3]) {
//err = X . Y , X = X - err/2 * Y , Y = Y - err/2 * X (DCMDraft2 Eqn.19)
float err = vector3d_dot((float*) (dcm[0]), (float*) (dcm[1]));
float delta[2][3];
vector3d_scale(-err / 2, (float*) (dcm[1]), (float*) (delta[0]));
vector3d_scale(-err / 2, (float*) (dcm[0]), (float*) (delta[1]));
vector3d_add((float*) (dcm[0]), (float*) (delta[0]), (float*) (dcm[0]));
vector3d_add((float*) (dcm[1]), (float*) (delta[0]), (float*) (dcm[1]));
 
//Z = X x Y (DCMDraft2 Eqn. 20) ,
vector3d_cross((float*) (dcm[0]), (float*) (dcm[1]), (float*) (dcm[2]));
//re-nomralization
vector3d_normalize((float*) (dcm[0]));
vector3d_normalize((float*) (dcm[1]));
vector3d_normalize((float*) (dcm[2]));
}
 
//rotate DCM matrix by a small rotation given by angular rotation vector w
//see http://gentlenav.googlecode.com/files/DCMDraft2.pdf
void dcm_rotate(float dcm[3][3], float w[3]) {
//float W[3][3];
//creates equivalent skew symetric matrix plus identity matrix
//vector3d_skew_plus_identity((float*)w,(float*)W);
//float dcmTmp[3][3];
//matrix_multiply(3,3,3,(float*)W,(float*)dcm,(float*)dcmTmp);
 
int i;
float dR[3];
//update matrix using formula R(t+1)= R(t) + dR(t) = R(t) + w x R(t)
for (i = 0; i < 3; i++) {
vector3d_cross(w, dcm[i], dR);
vector3d_add(dcm[i], dR, dcm[i]);
}
 
//make matrix orthonormal again
dcm_orthonormalize(dcm);
}
 
//-------------------------------------------------------------------
// imu_update
//-------------------------------------------------------------------
#define ACC_WEIGHT 0.01 //accelerometer data weight relative to gyro's weight of 1
#define MAG_WEIGHT 0.0 //magnetometer data weight relative to gyro's weight of 1
 
void imu_update(void) {
int i;
imu_sequence++;
 
//interval since last call
 
//---------------
// I,J,K unity vectors of global coordinate system I-North,J-West,K-zenith
// i,j,k unity vectors of body's coordiante system i-"nose", j-"left wing", k-"top"
//---------------
// [I.i , I.j, I.k]
// DCM = [J.i , J.j, J.k]
// [K.i , K.j, K.k]
 
 
//---------------
//Acelerometer
//---------------
//Accelerometer measures gravity vector G in body coordinate system
//Gravity vector is the reverse of K unity vector of global system expressed in local coordinates
//K vector coincides with the z coordinate of body's i,j,k vectors expressed in global coordinates (K.i , K.j, K.k)
float Kacc[3];
//Acc can estimate global K vector(zenith) measured in body's coordinate systems (the reverse of gravitation vector)
Kacc[0] = -acc_ATT[X];
Kacc[1] = -acc_ATT[Y];
Kacc[2] = -acc_ATT[Z];
vector3d_normalize(Kacc);
//calculate correction vector to bring dcmGyro's K vector closer to Acc vector (K vector according to accelerometer)
float wA[3];
vector3d_cross(dcmGyro[2], Kacc, wA); // wA = Kgyro x Kacc , rotation needed to bring Kacc to Kgyro
 
//---------------
//Magnetomer
//---------------
//calculate correction vector to bring dcmGyro's I vector closer to Mag vector (I vector according to magnetometer)
float Imag[3];
float wM[3];
//in the absense of magnetometer let's assume North vector (I) is always in XZ plane of the device (y coordinate is 0)
Imag[0] = sqrt(1 - dcmGyro[0][2] * dcmGyro[0][2]);
Imag[1] = 0;
Imag[2] = dcmGyro[0][2];
 
vector3d_cross(dcmGyro[0], Imag, wM); // wM = Igyro x Imag, roation needed to bring Imag to Igyro
 
//---------------
//dcmGyro
//---------------
float w[3]; //gyro rates (angular velocity of a global vector in local coordinates)
w[0] = -gyro_ATT[PITCH] / 1000.0; //rotation rate about accelerometer's X axis (GY output) in rad/ms
w[1] = -gyro_ATT[ROLL] / 1000.0; //rotation rate about accelerometer's Y axis (GX output) in rad/ms
w[2] = -gyro_ATT[YAW] / 1000.0; //rotation rate about accelerometer's Z axis (GZ output) in rad/ms
 
for (i = 0; i < 3; i++) {
w[i] *= INTEGRATION_TIME_MS; //scale by elapsed time to get angle in radians
//compute weighted average with the accelerometer correction vector
w[i] = (w[i] + ACC_WEIGHT * wA[i] + MAG_WEIGHT * wM[i]) / (1.0
+ ACC_WEIGHT + MAG_WEIGHT);
}
 
dcm_rotate(dcmGyro, w);
 
//Output for PicQuadController_GYRO_DEBUG1.scc
//only output data ocasionally to allow computer to process data
/*
if(0 == imu_sequence % 4){
printf("%.5f,",(double)interval_ms);
print_float_list(3,(float*)w);
printf(",%.2f,%.2f,%.2f",adcAvg[3+1],adcAvg[3+0],adcAvg[3+2]);
 
printf("\n ");
}
*/
 
//Output for: PICQUADCONTROLLER_DEBUG1.pde
//only output data ocasionally to allow computer to process data
/*
if (0 == imu_sequence % 16) {
printf("%.2f,", (double) interval_ms);
print_float_list(3, (float*) Kacc);
printf(", ");
print_float_list(9, (float*) dcmGyro);
printf("\n");
}
*/
}
 
void attitude_update(void) {
analog_update();
startAnalogConversionCycle();
 
// Takes 4 ms.
imu_update();
}