#include "footPDR_prev.h" //当地的重力加速度 static float g = 9.8179995f; static float dt = 0.014f; static float P[81], acc_n[3]; static float Temporary_array1[9], Temporary_array2[9]; static float K[27], P_prev[81], delta_x[9]; static float C[9], C_prev[9]; static float vel_n[3], pos_n[3]; static float last_pos_n[3]; static float pos_offset[3]; static uint32_t frame_index = 0; static int stand_num = 0; static float gyr_extreme[6]; static float gyr_mean[3]; static float num_peak; static float gyrBias[3]; static int SAVEFLASH = 1; //last_stage:0 为 走路状态; //last_stage:1 为 静止状态 static float measure_degree = 1.0f; static float heading_buff[20]; static float zupt_heading; static int step_index = 0; void Initialize_prev(float *gyr, float *acc) { frame_index = 1; stand_num = 0; memset(last_pos_n, 0, 3 * sizeof(float)); memset(pos_offset, 0, 3 * sizeof(float)); memset(P, 0, 81 * sizeof(float)); memset(acc_n, 0, 3 * sizeof(float)); memset(vel_n, 0, 3 * sizeof(float)); memset(pos_n, 0, 3 * sizeof(float)); memset(Temporary_array1, 0, 9 * sizeof(float)); memset(Temporary_array2, 0, 9 * sizeof(float)); memset(K, 0, 27 * sizeof(float)); memset(P_prev, 0, 81 * sizeof(float)); memset(delta_x, 0, 9 * sizeof(float)); memset(C, 0, 9 * sizeof(float)); memset(Temporary_array1, 0, 9 * sizeof(float)); memset(Temporary_array2, 0, 9 * sizeof(float)); init_attitude_matrix(C, acc, g); memcpy(C_prev, C, 9 * sizeof(float)); // memcpy(gyrBias, (uint32_t *)FLASH_ADD, 3 * sizeof(float)); } unsigned char footPDR_prev(uint32_t num, float *gyr, float *acc, int16_t vel_zero, int32_t* pos_res, int16_t* att) { unsigned char movement_e = 0; for (int i = 0; i < 3; i++) { gyr[i] *= (PI / 180); acc[i] *= g; } if (num_peak == 0) { for (int i = 0; i < 3; i++) { gyr_extreme[2 * i] = gyr[i]; gyr_extreme[2 * i + 1] = gyr[i]; } } for (int i = 0; i < 3; i++) { if (gyr[i] < gyr_extreme[2 * i]) { gyr_extreme[2 * i] = gyr[i]; } if (gyr[i] > gyr_extreme[2 * i + 1]) { gyr_extreme[2 * i + 1] = gyr[i]; } } for (int i = 0; i < 3; i++) { gyr_mean[i] += gyr[i]; } num_peak++; //在线估计陀螺仪的零偏, 6050的零偏偏大 if (num_peak == 300) { if (isStandCon(gyr_extreme)) { if(SAVEFLASH) { //识别每一次游戏模式下,静止状态的陀螺仪令零偏 for(int i = 0; i < 3; i++) { gyrBias[i] = gyr_mean[i] * 0.0033f; } DEBUG_LOG("gyrBias has cor!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); } } num_peak = 0; memset(gyr_mean, 0, 3 * sizeof(float)); } gyr[0] -= gyrBias[0]; gyr[1] -= gyrBias[1]; gyr[2] -= gyrBias[2]; float gyr_norm_xyz = sqrt(gyr[0] * gyr[0] + gyr[1] * gyr[1] + gyr[2] * gyr[2]); float acc_norm_xyz = sqrt(acc[0] * acc[0] + acc[1] * acc[1] + acc[2] * acc[2]); //需要一个滑动窗口来判断脚步是否在地上 frame_index++; //下面为惯导解算 if (num == 0|| frame_index == 0) { Initialize_prev(gyr, acc); gpio_mt_run(500); return movement_e; } //惯导解算: 姿态矩阵更新 attitude_matrix_update(C, Temporary_array1, Temporary_array2, gyr, dt); //惯导解算: 将IMU坐标系的加速度转换到“导航坐标系”下 multiply3x1(C, acc, acc_n); //惯导解算: 更新IMU速度 vel_n[0] = vel_n[0] + acc_n[0] * dt; vel_n[1] = vel_n[1] + acc_n[1] * dt; vel_n[2] = vel_n[2] + (acc_n[2] - g) * dt; //惯导解算: 更新IMU位置 pos_n[0] = pos_n[0] + vel_n[0] * dt; pos_n[1] = pos_n[1] + vel_n[1] * dt; pos_n[2] = pos_n[2] + vel_n[2] * dt; //ekf步骤: 状态协方差矩阵预测更新 //P = F*P*F' + Q; State_covariance_matrix_update(P, acc_n, dt); //zupt if (vel_zero == 1) { //ekf步骤: 计算卡尔曼滤波增益 //K = P*H'/(H*P*H' + R); calKafmanGain9x4(K, P); //ekf步骤: 观测误差更新 //delta_x = K * [vel_n(:,i);]; float now_heading = atan2(C[3], C[0]); float measure[4]; //计算理想的角度 memset(measure, 0, 4 *sizeof(float)); measure[0] = calDeltaHeading(step_index, now_heading, heading_buff); if(measure[0] > 10.0f) { measure[0] = 0; } measure[1] = vel_n[0]; measure[2] = vel_n[1]; measure[3] = vel_n[2]; calDeltaX9x4(K, measure, delta_x); //ekf步骤: 状态协方差矩阵观测更新 calStateCov9x4(P, K); //这里先从设置 delta_x(3) = atan2(C(2,1),C(1,1)); //意味着每一步的参考方向是IMU X轴方向 // delta_x[2] = atan2(C[3], C[0]); // theta = -1.7801 + atan2(C[3], C[0]); // theta = 0.0f; //修正姿态矩阵 Att_matrix_corr(C, C_prev, Temporary_array1, Temporary_array2, delta_x); //修正位置 pos_n_corr(pos_n, delta_x); //修正速度 vel_n_corr(vel_n, delta_x); //vel_n[2] = 0.8f * vel_n[2]; if(vel_zero == 1) { zupt_heading = now_heading; stand_num ++; } memcpy(last_pos_n, pos_n, 3 * sizeof(float)); } else { //存放一步内记录的mag数据以及heading数据 if(stand_num != 0) { heading_buff[step_index % 20] = zupt_heading; step_index ++; } stand_num = 0; measure_degree = 1.0f; } //状态协方差矩阵保持正交性,以防出现退化 State_covariance_matrix_orthogonalization(P); pos_offset[0] = pos_offset[0] + pos_n[0] - last_pos_n[0]; pos_offset[1] = pos_offset[1] + pos_n[1] - last_pos_n[1]; pos_offset[2] = pos_offset[2] + pos_n[2] - last_pos_n[2]; memcpy(last_pos_n, pos_n, 3 * sizeof(float)); dcm2angleTest(C, att); //航向角,俯仰角, 翻滚角(z y x) att[1] = (int16_t)(vel_n[0] * 1000.0f); att[2] = (int16_t)(vel_n[1] * 1000.0f); pos_res[0] = (int32_t) (pos_offset[0] * 100.0f); pos_res[1] = (int32_t) (pos_offset[1] * 100.0f); pos_res[2] = (int32_t) (pos_offset[2] * 100.0f); return movement_e; }