
ドローン用計測制御基板の作り方 vol.1 ハードウェア編 p.19掲載 カルマンフィルタによる姿勢推定
Dependencies: mbed MPU6050_alter
Revision 0:f41e4813b4c5, committed 2019-12-30
- Comitter:
- Joeatsumi
- Date:
- Mon Dec 30 16:39:22 2019 +0000
- Commit message:
- 20191231
Changed in this revision
diff -r 000000000000 -r f41e4813b4c5 MPU6050.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MPU6050.lib Mon Dec 30 16:39:22 2019 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/Joeatsumi/code/MPU6050_alter/#44c458576810
diff -r 000000000000 -r f41e4813b4c5 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Dec 30 16:39:22 2019 +0000 @@ -0,0 +1,517 @@ +//================================================== +//Atitude estimation (kalman filter) +//MPU board: mbed LPC1768 +//Accelerometer +Gyro sensor : GY-521 +// +//Matrix functions were derived from トランジスタ技術2019年7月号 +// +//2019/12/30 A.Toda +//================================================== +#include "mbed.h" +#include "MPU6050.h" + +//================================================== +#define RAD_TO_DEG 57.2957795f // 180 / π +#define MAX_MEAN_COUNTER 100 +#define ACC_X 1.3//offset of x-axi accelerometer +#define FRQ 100//Hz +//================================================== + +DigitalOut led1(LED1); + +//Timer interrupt +Ticker flipper; + +//Port Setting +MPU6050 mpu(p9, p10); //Accelerometer + Gyro + //(SDA,SCLK) + +Serial pc(USBTX, USBRX); //UART + +//================================================== +//Accelerometer and gyro data +//================================================== + +double acc[3]; //variables for accelerometer +double gyro[3]; //variables for gyro + +double offset_gyro_x=0.0; +double offset_gyro_y=0.0; + +double sum_gyro_x=0.0; +double sum_gyro_y=0.0; + +//================================================== +//Atitude data +//================================================== +double roll_and_pitch_acc[2][1];//atitude from accelerometer +double roll_and_pitch[2][1]; //atitude from gyro and accelerometer + +double threshold_acc,threshold_acc_ini; + +//================================================== +//Matrix definition +//================================================== +double MAT_A[2][2]; +double inv_MAT_A[2][2]; + +double MAT_B[2][2]; +double inv_MAT_B[2][2]; + +double MAT_C[2][2]; +double inv_MAT_C[2][2]; + +double MAT_X_k[2][1]; +double pre_MAT_X_k[2][1]; + +double COV_P[2][2];//covariance matrix of atitude angles +double pre_COV_P[2][2];//covariance matrix of atitude angles +double pre_COV_P_2[2][2];//covariance matrix of atitude angles +double pre_COV_P_3[2][2];//covariance matrix of atitude angles + +double COV_Q[2][2];//covariance matrix of gyro inputs +double COV_R[2][2];//covariance matrix of atitude angles from accelerometer + +//========================================================= +// Matrix common functions +//========================================================= +//Matrix addition +void mat_add(double *m1, double *m2, double *sol, int row, int column) +{ + for(int i=0; i<row; i++) + { + for(int j=0; j<column; j++) + { + sol[i*column + j] = m1[i*column + j] + m2[i*column + j]; + } + } + return; +} + +//Matrix subtraction +void mat_sub(double *m1, double *m2, double *sol, int row, int column) +{ + for(int i=0; i<row; i++) + { + for(int j=0; j<column; j++) + { + sol[i*column + j] = m1[i*column + j] - m2[i*column + j]; + } + } + return; +} + +//Matrix multiplication +void mat_mul(double *m1, double *m2, double *sol, int row1, int column1, int row2, int column2) +{ + for(int i=0; i<row1; i++) + { + for(int j=0; j<column2; j++) + { + sol[i*column2 + j] = 0; + for(int k=0; k<column1; k++) + { + sol[i*column2 + j] += m1[i*column1 + k]*m2[k*column2 + j]; + } + } + } + return; +} + +//Matrix transposition +void mat_tran(double *m1, double *sol, int row_original, int column_original) +{ + for(int i=0; i<row_original; i++) + { + for(int j=0; j<column_original; j++) + { + sol[j*row_original + i] = m1[i*column_original + j]; + } + } + return; +} + +//Matrix scalar maltiplication +void mat_mul_const(double *m1,double c, double *sol, int row, int column) +{ + for(int i=0; i<row; i++) + { + for(int j=0; j<column; j++) + { + sol[i*column + j] = c * m1[i*column + j]; + } + } + return; +} + +//Matrix inversion (by Gaussian elimination) +void mat_inv(double *m, double *sol, int column, int row) +{ + //allocate memory for a temporary matrix + double* temp = (double *)malloc( column*2*row*sizeof(double) ); + + //make the augmented matrix + for(int i=0; i<column; i++) + { + //copy original matrix + for(int j=0; j<row; j++) + { + temp[i*(2*row) + j] = m[i*row + j]; + } + + //make identity matrix + for(int j=row; j<row*2; j++) + { + if(j-row == i) + { + temp[i*(2*row) + j] = 1; + } + else + { + temp[i*(2*row) + j] = 0; + } + } + } + + //Sweep (down) + for(int i=0; i<column; i++) + { + //pivot selection + double pivot = temp[i*(2*row) + i]; + int pivot_index = i; + double pivot_temp; + for(int j=i; j<column;j++) + { + if( temp[j*(2*row)+i] > pivot ) + { + pivot = temp[j*(2*row) + i]; + pivot_index = j; + } + } + if(pivot_index != i) + { + for(int j=0; j<2*row; j++) + { + pivot_temp = temp[ pivot_index * (2*row) + j ]; + temp[pivot_index * (2*row) + j] = temp[i*(2*row) + j]; + temp[i*(2*row) + j] = pivot_temp; + } + } + + //division + for(int j=0; j<2*row; j++) + { + temp[i*(2*row) + j] /= pivot; + } + + //sweep + for(int j=i+1; j<column; j++) + { + double temp2 = temp[j*(2*row) + i]; + + //sweep each row + for(int k=0; k<row*2; k++) + { + temp[j*(2*row) + k] -= temp2 * temp[ i*(2*row) + k ]; + } + } + } + + //Sweep (up) + for(int i=0; i<column-1; i++) + { + for(int j=i+1; j<column; j++) + { + double pivot = temp[ (column-1-j)*(2*row) + (row-1-i)]; + for(int k=0; k<2*row; k++) + { + temp[(column-1-j)*(2*row)+k] -= pivot * temp[(column-1-i)*(2*row)+k]; + } + } + } + + //copy result + for(int i=0; i<column; i++) + { + for(int j=0; j<row; j++) + { + sol[i*row + j] = temp[i*(2*row) + (j+row)]; + } + } + free(temp); + return; +} + +//================================================== +//Gyro and accelerometer functions +//================================================== +//get data +void aquisition_sensor_values(double *a,double *g){ + + float ac[3],gy[3]; + + mpu.getAccelero(ac);//get acceleration (Accelerometer) + //x_axis acc[0] + //y_axis acc[1] + //z_axis acc[2] + mpu.getGyro(gy); //get rate of angle(Gyro) + //x_axis gyro[0] + //y_axis gyro[1] + //z_axis gyro[2] + + //Invertion for direction of Accelerometer axis + ac[0]*=(-1.0); + ac[0]+=ACC_X; + + ac[2]*=(-1.0); + + //Unit convertion of rate of angle(radian to degree) + gy[0]*=RAD_TO_DEG; + gy[0]*=(-1.0); + + gy[1]*=RAD_TO_DEG; + + gy[2]*=RAD_TO_DEG; + gy[2]*=(-1.0); + + for(int i=0;i<3;i++){ + a[i]=double(ac[i]); + g[i]=double(gy[i]); + } + g[0]-=offset_gyro_x;//offset rejection + g[1]-=offset_gyro_y;//offset rejection + + return; + +} + +//calculate offset of gyro +void offset_calculation_for_gyro(){ + + //Accelerometer and gyro setting + mpu.setAcceleroRange(0);//acceleration range is +-2G + mpu.setGyroRange(1);//gyro rate is +-500degree per second(dps) + + //calculate offset of gyro + for(int mean_counter=0; mean_counter<MAX_MEAN_COUNTER ;mean_counter++){ + aquisition_sensor_values(acc,gyro); + sum_gyro_x+=gyro[0]; + sum_gyro_y+=gyro[1]; + wait(0.01); + } + + offset_gyro_x=sum_gyro_x/MAX_MEAN_COUNTER; + offset_gyro_y=sum_gyro_y/MAX_MEAN_COUNTER; + + return; +} + +//atitude calculation from acceleromter +void atitude_estimation_from_accelerometer(double *a,double *roll_and_pitch){ + + //roll_and_pitch[0] = atan2(a[1], a[2])*RAD_TO_DEG;//roll + roll_and_pitch[0] = atan(a[1]/a[2])*RAD_TO_DEG;//roll + //roll_and_pitch[1] = atan(a[0]/sqrt( a[1]*a[1]+a[2]*a[2] ) )*RAD_TO_DEG;//pitch + roll_and_pitch[1] = atan2(a[0],sqrt( a[1]*a[1]+a[2]*a[2] ) )*RAD_TO_DEG;//pitch + + return; +} + +//atitude calculation +void atitude_update(){ + + + aquisition_sensor_values(acc,gyro);//加速度、ジャイロの取得 + + //入力の設定 + double MAT_IN[2][1]={}; + double pre_MAT_IN[2][1]={}; + + MAT_IN[0][0]=gyro[0]; + MAT_IN[1][0]=gyro[1]; + + /*--------------------Time update phase 時間更新フェーズ--------------------*/ + //A*x+B*u + + mat_mul(MAT_A[0], MAT_X_k[0],pre_MAT_X_k[0] ,2, 2, 2, 1); + mat_mul(MAT_B[0], MAT_IN[0],pre_MAT_IN[0] ,2, 2, 2, 1); + + mat_add(pre_MAT_X_k[0],pre_MAT_IN[0], pre_MAT_X_k[0], 2, 1); + + //A*P*A^T+B*P*B^T + double pre_COV_P_1[2][2]={}; + double pre_COV_P_1_2[2][2]={}; + + double pre_COV_P_2[2][2]={}; + double pre_COV_P_2_2[2][2]={}; + + mat_mul(MAT_A[0], COV_P[0],pre_COV_P_1[0] ,2, 2, 2, 2); + mat_mul(pre_COV_P_1[0], inv_MAT_A[0] , pre_COV_P_1_2[0] ,2, 2, 2, 2); + + + mat_mul(MAT_B[0], COV_Q[0],pre_COV_P_2[0] ,2, 2, 2, 2); + mat_mul(pre_COV_P_2[0], inv_MAT_B[0] , pre_COV_P_2_2[0] ,2, 2, 2, 2); + + mat_add(pre_COV_P_1_2[0],pre_COV_P_2_2[0], pre_COV_P[0], 2, 2); + + //pc.printf("1;Roll=%f,Pitch=%f\r\n",pre_COV_P[0][0],pre_COV_P[1][1]); + /*------------------------------------------------------------------------*/ + + /*--------------------Measurement update phase 観測更新フェーズ--------------------*/ + + threshold_acc=sqrt(acc[0]*acc[0]+acc[1]*acc[1]+acc[2]*acc[2]); + + //加速度のノルムが9.8m/s^2付近かどうかの判定 + if((threshold_acc>=0.95*threshold_acc_ini)&&(threshold_acc<=1.05*threshold_acc_ini)){ + + //pc.printf("corrected\r\n"); + led1=0; + + double GAIN_K[2][2]={}; + double pre_GAIN_K_1[2][2]={}; + double pre_GAIN_K_1_2[2][2]={}; + double pre_GAIN_K_1_3[2][2]={}; + double pre_GAIN_K_1_4[2][2]={}; + + double pre_GAIN_K_2[2][2]={}; + + //K=P*C^T*(C*P*C^T+R)^-1 + //(C*P*C^T+R)^-1 + mat_mul(MAT_C[0], pre_COV_P[0] , pre_GAIN_K_1[0] ,2, 2, 2, 2); + mat_mul(pre_GAIN_K_1[0], inv_MAT_C[0] , pre_GAIN_K_1_2[0] ,2, 2, 2, 2); + + mat_add(pre_GAIN_K_1_2[0],COV_R[0], pre_GAIN_K_1_3[0], 2, 2); + + mat_inv(pre_GAIN_K_1_3[0], pre_GAIN_K_1_4[0], 2, 2); + + //P*C^T + mat_mul(pre_COV_P[0], inv_MAT_C[0] , pre_GAIN_K_2[0] ,2, 2, 2, 2); + + //P*C^T*(C*P*C^T+R)^-1 + mat_mul(pre_GAIN_K_2[0], pre_GAIN_K_1_4[0] , GAIN_K[0] ,2, 2, 2, 2); + + double pre_MAT_X_k_2[2][1]={}; + double pre_MAT_X_k_2_2[2][1]={}; + + //X=X+K(y-C*X) + + atitude_estimation_from_accelerometer(acc,roll_and_pitch_acc[0]); + mat_sub(roll_and_pitch_acc[0], pre_MAT_X_k[0], pre_MAT_X_k_2[0], 2, 1); + + mat_mul(GAIN_K[0], pre_MAT_X_k_2[0] ,pre_MAT_X_k_2_2[0] ,2, 2, 2, 1); + + mat_add(pre_MAT_X_k[0], pre_MAT_X_k_2_2[0], MAT_X_k[0], 2, 1); + + //P=(I-K*C)*P + double MAT_UNIT[2][2]={}; + /*initialize Unit matrix*/ + MAT_UNIT[0][0]=1.0; + MAT_UNIT[0][1]=0.0; + MAT_UNIT[1][0]=0.0; + MAT_UNIT[1][1]=1.0; + /*----------------------*/ + + mat_sub(MAT_UNIT[0], GAIN_K[0], pre_COV_P_3[0], 2, 2); + mat_mul(pre_COV_P_3[0], pre_COV_P[0], COV_P[0], 2, 2, 2, 2); + + + }else{ + //pc.printf("Not corrected\r\n"); + led1=1; + + MAT_X_k[0][0]=pre_MAT_X_k[0][0]; + MAT_X_k[1][0]=pre_MAT_X_k[1][0]; + + COV_P[0][0]=pre_COV_P[0][0]; + COV_P[1][1]=pre_COV_P[1][1]; + + } + + pc.printf("%f,%f,Roll=%f,Pitch=%f\r\n",threshold_acc,threshold_acc_ini,MAT_X_k[0][0],MAT_X_k[1][0]); + //pc.printf("2;Roll=%f,Pitch=%f\r\n",COV_P[0][0],COV_P[1][1]); + + /*--------------------------------------------------------------------*/ + + return; + +} + + +//================================================== +//Main +//================================================== +int main() { + + //UART initialization + pc.baud(115200); + + //gyro and accelerometer initialization + offset_calculation_for_gyro(); + + //identify initilal atitude + aquisition_sensor_values(acc,gyro); + atitude_estimation_from_accelerometer(acc,MAT_X_k[0]); + + threshold_acc_ini=sqrt(acc[0]*acc[0]+acc[1]*acc[1]+acc[2]*acc[2]); + + /*Initialize MAT_A*/ + MAT_A[0][0]=1.0; + MAT_A[0][1]=0.0; + MAT_A[1][0]=0.0; + MAT_A[1][1]=1.0; + + mat_tran(MAT_A[0], inv_MAT_A[0], 2, 2); + /*----------------*/ + + /*Initialize MAT_B*/ + MAT_B[0][0]=1.0/FRQ; + MAT_B[0][1]=0.0; + MAT_B[1][0]=0.0; + MAT_B[1][1]=1.0/FRQ; + + mat_tran(MAT_B[0], inv_MAT_B[0], 2, 2); + /*----------------*/ + + /*Initialize MAT_C*/ + MAT_C[0][0]=1.0; + MAT_C[0][1]=0.0; + MAT_C[1][0]=0.0; + MAT_C[1][1]=1.0; + + mat_tran(MAT_C[0], inv_MAT_C[0], 2, 2); + /*----------------*/ + + /* + これら共分散の値は仮の値である。 + */ + /*Initialize COV_P*/ + COV_P[0][0]=1.0; + COV_P[0][1]=0.0; + COV_P[1][0]=0.0; + COV_P[1][1]=1.0; + /*----------------*/ + + /*Initialize COV_Q*/ + COV_Q[0][0]=0.01; + COV_Q[0][1]=0.0; + COV_Q[1][0]=0.0; + COV_Q[1][1]=0.01; + /*----------------*/ + + /*Initialize COV_R*/ + COV_R[0][0]=0.001; + COV_R[0][1]=0.0; + COV_R[1][0]=0.0; + COV_R[1][1]=0.001; + /*----------------*/ + + pc.printf("Roll=%f,Pitch=%f\r\n",COV_P[0][0],COV_P[1][1]); + + //Ticker + flipper.attach(&atitude_update, 0.01); + + while(1) { + wait(0.01); + + } +}
diff -r 000000000000 -r f41e4813b4c5 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Dec 30 16:39:22 2019 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/mbed_official/code/mbed/builds/e1686b8d5b90 \ No newline at end of file