赞
踩
- //! Auxiliary variables to reduce number of repeated operations
- static float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; /** quaternion of sensor frame relative to auxiliary frame */
- static float dq0 = 0.0f, dq1 = 0.0f, dq2 = 0.0f, dq3 = 0.0f; /** quaternion of sensor frame relative to auxiliary frame */
- static float gyro_bias[3] = {0.0f, 0.0f, 0.0f}; /** bias estimation */
- static float q0q0, q0q1, q0q2, q0q3;
- static float q1q1, q1q2, q1q3;
- static float q2q2, q2q3;
- static float q3q3;
- static uint8_t bFilterInit = 0;
- imu_t imu= {0};
-
- //函数名:invSqrt(void)
- //描述:求平方根的倒数
- //该函数是经典的Carmack求平方根算法,效率极高,使用魔数0x5f375a86
- static float invSqrt(float number)
- {
- volatile long i;
- volatile float x, y;
- volatile const float f = 1.5F;
-
- x = number * 0.5F;
- y = number;
- i = * (( long * ) &y);
- i = 0x5f375a86 - ( i >> 1 );
- y = * (( float * ) &i);
- y = y * ( f - ( x * y * y ) );
- return y;
- }
-
- //四元数初始化
- //
- static void MahonyAHRSinit(float ax, float ay, float az, float mx, float my, float mz)
- {
- float initialRoll, initialPitch;
- float cosRoll, sinRoll, cosPitch, sinPitch;
- float magX, magY;
- float initialHdg, cosHeading, sinHeading;
-
-
- initialRoll = atan2(-ay, -az);
- initialPitch = atan2(ax, -az);
- // initialRoll = atan2(ay, az);
- // initialPitch = -asin(ax);
-
- cosRoll = cosf(initialRoll);
- sinRoll = sinf(initialRoll);
- cosPitch = cosf(initialPitch);
- sinPitch = sinf(initialPitch);
-
- magX = mx * cosPitch + my * sinRoll * sinPitch + mz * cosRoll * sinPitch;
-
- magY = my * cosRoll - mz * sinRoll;
-
- initialHdg = atan2f(-magY, magX);
- // magX = mx * cosRoll + my * sinRoll * sinPitch + mz * cosPitch * sinRoll;
- // magY = my * cosPitch - mz * sinPitch ;
- // initialHdg = -atan2f(magY, magX);
- cosRoll = cosf(initialRoll * 0.5f);
- sinRoll = sinf(initialRoll * 0.5f);
-
- cosPitch = cosf(initialPitch * 0.5f);
- sinPitch = sinf(initialPitch * 0.5f);
-
- cosHeading = cosf(initialHdg * 0.5f);
- sinHeading = sinf(initialHdg * 0.5f);
-
- q0 = cosRoll * cosPitch * cosHeading + sinRoll * sinPitch * sinHeading;
- q1 = sinRoll * cosPitch * cosHeading - cosRoll * sinPitch * sinHeading;
- q2 = cosRoll * sinPitch * cosHeading + sinRoll * cosPitch * sinHeading;
- q3 = cosRoll * cosPitch * sinHeading - sinRoll * sinPitch * cosHeading;
-
- // auxillary variables to reduce number of repeated operations, for 1st pass
- q0q0 = q0 * q0;
- q0q1 = q0 * q1;
- q0q2 = q0 * q2;
- q0q3 = q0 * q3;
- q1q1 = q1 * q1;
- q1q2 = q1 * q2;
- q1q3 = q1 * q3;
- q2q2 = q2 * q2;
- q2q3 = q2 * q3;
- q3q3 = q3 * q3;
- }
-
- //函数名:MahonyAHRSupdate()
- //描述:姿态解算融合,是Crazepony和核心算法
- //使用的是Mahony互补滤波算法,没有使用Kalman滤波算法
- //改算法是直接参考pixhawk飞控的算法,可以在Github上看到出处
- //https://github.com/hsteinhaus/PX4Firmware/blob/master/src/modules/attitude_estimator_so3/attitude_estimator_so3_main.cpp
- static void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float twoKp, float twoKi, float dt)
- {
- float recipNorm;
- float halfex = 0.0f, halfey = 0.0f, halfez = 0.0f;
-
- // Make filter converge to initial solution faster
- // This function assumes you are in static position.
- // WARNING : in case air reboot, this can cause problem. But this is very unlikely happen.
- if(bFilterInit == 0) {
- MahonyAHRSinit(ax,ay,az,mx,my,mz);
- bFilterInit = 1;
- }
-
- //! If magnetometer measurement is available, use it.
- if(!((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f))) { //磁场数据融合,数据归一,数据模型坐标系矩阵转置惯性坐标系,处理 理想水平面y轴分量为0,在转回,最后向量叉乘误差积分
- float hx, hy, hz, bx, bz;
- float halfwx, halfwy, halfwz;
-
- // Normalise magnetometer measurement
- // Will sqrt work better? PX4 system is powerful enough?
- recipNorm = invSqrt(mx * mx + my * my + mz * mz);
- mx *= recipNorm;
- my *= recipNorm;
- mz *= recipNorm;
-
- // Reference direction of Earth's magnetic field
- hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
- hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
- hz = 2.0f * mx * (q1q3 - q0q2) + 2.0f * my * (q2q3 + q0q1) + 2.0f * mz * (0.5f - q1q1 - q2q2);
- bx = sqrt(hx * hx + hy * hy);
- bz = hz;
-
- // Estimated direction of magnetic field
- halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
- halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
- halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);
-
- // Error is sum of cross product between estimated direction and measured direction of field vectors
- halfex += (my * halfwz - mz * halfwy);
- halfey += (mz * halfwx - mx * halfwz);
- halfez += (mx * halfwy - my * halfwx);
- }
-
- // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
- if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) //加速度数据融合,数据归一,矩阵转置模型坐标系,最后向量叉乘误差积分
- {
- float halfvx, halfvy, halfvz;
-
- // Normalise accelerometer measurement
- //归一化,得到单位加速度
- recipNorm = invSqrt(ax * ax + ay * ay + az * az);
-
- ax *= recipNorm;
- ay *= recipNorm;
- az *= recipNorm;
-
- // Estimated direction of gravity and magnetic field
- halfvx = q1q3 - q0q2;
- halfvy = q0q1 + q2q3;
- halfvz = q0q0 - 0.5f + q3q3;
-
- // Error is sum of cross product between estimated direction and measured direction of field vectors
- halfex += ay * halfvz - az * halfvy;
- halfey += az * halfvx - ax * halfvz;
- halfez += ax * halfvy - ay * halfvx;
- }
-
- // Apply feedback only when valid data has been gathered from the accelerometer or magnetometer
- if(halfex != 0.0f && halfey != 0.0f && halfez != 0.0f) { //角速度计误差补偿
- // Compute and apply integral feedback if enabled
- if(twoKi > 0.0f) {
- gyro_bias[0] += twoKi * halfex * dt; // integral error scaled by Ki
- gyro_bias[1] += twoKi * halfey * dt;
- gyro_bias[2] += twoKi * halfez * dt;
-
- // apply integral feedback
- gx += gyro_bias[0];
- gy += gyro_bias[1];
- gz += gyro_bias[2];
- }
- else {
- gyro_bias[0] = 0.0f; // prevent integral windup
- gyro_bias[1] = 0.0f;
- gyro_bias[2] = 0.0f;
- }
-
- // Apply proportional feedback
- gx += twoKp * halfex;
- gy += twoKp * halfey;
- gz += twoKp * halfez;
- }
-
- // Time derivative of quaternion. q_dot = 0.5*q\otimes omega.
- //! q_k = q_{k-1} + dt*\dot{q}
- //! \dot{q} = 0.5*q \otimes P(\omega)
- dq0 = 0.5f*(-q1 * gx - q2 * gy - q3 * gz);
- dq1 = 0.5f*(q0 * gx + q2 * gz - q3 * gy);
- dq2 = 0.5f*(q0 * gy - q1 * gz + q3 * gx);
- dq3 = 0.5f*(q0 * gz + q1 * gy - q2 * gx);
-
- q0 += dt*dq0;
- q1 += dt*dq1;
- q2 += dt*dq2;
- q3 += dt*dq3;
-
- // Normalise quaternion
- recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
- q0 *= recipNorm;
- q1 *= recipNorm;
- q2 *= recipNorm;
- q3 *= recipNorm;
-
- // Auxiliary variables to avoid repeated arithmetic
- q0q0 = q0 * q0;
- q0q1 = q0 * q1;
- q0q2 = q0 * q2;
- q0q3 = q0 * q3;
- q1q1 = q1 * q1;
- q1q2 = q1 * q2;
- q1q3 = q1 * q3;
- q2q2 = q2 * q2;
- q2q3 = q2 * q3;
- q3q3 = q3 * q3;
- }
-
- #define Kp 2.0f //加速度权重,越大收敛越快
- #define Ki 0.005f //误差积分增益
-
-
- //函数名: MahonyAHRSThread(void)
- //描述:姿态软件解算融合函数
- //该函数对姿态的融合是软件解算,
- void MahonyAHRSThread(void)
- {
- //! Time constant
- volatile float dt = 0.005f; //s
- static uint32_t tPrev=0; //us
- uint32_t now;
- uint8_t i;
-
- /* output euler angles */
- float euler[3] = {0.0f, 0.0f, 0.0f}; //rad
-
- /* Initialization */
- float Rot_matrix[9] = {1.f, 0.0f, 0.0f, 0.0f, 1.f, 0.0f, 0.0f, 0.0f, 1.f }; /**< init: identity matrix */
- float acc[3] = {0.0f, 0.0f, 0.0f}; //m/s^2
- float gyro[3] = {0.0f, 0.0f, 0.0f}; //rad/s
- float mag[3] = {0.0f, 0.0f, 0.0f};
-
- static float gyro_offsets_sum[3]= { 0.0f, 0.0f, 0.0f }; // gyro_offsets[3] = { 0.0f, 0.0f, 0.0f },
- static uint16_t offset_count = 0;
-
-
- // if(ReadIMUSensorHandle())return;//原始数据并滤波
- // now= (u32)CPU_TS32_to_uSec(CPU_TS_TmrRd());
- // dt=(tPrev>0)?(now-tPrev)/1000000.0f:0; //时间
- // tPrev=now;
- //
- gyro[0] = imu.gyro[0] ;
- gyro[1] = imu.gyro[1] ;
- gyro[2] = imu.gyro[2] ;
-
- acc[0] = imu.accb[0];
- acc[1] = imu.accb[1];
- acc[2] = imu.accb[2];
- mag[0] = imu.mag[0];
- mag[1] = imu.mag[1];
- mag[2] = imu.mag[2];
-
- // NOTE : Accelerometer is reversed.
- // Because proper mount of PX4 will give you a reversed accelerometer readings.
- MahonyAHRSupdate(gyro[0], gyro[1], gyro[2],
- acc[0], acc[1], acc[2],
- mag[0], mag[1], mag[2],
- Kp,Ki,dt);
-
- // Convert q->R, This R converts inertial frame to body frame.
- Rot_matrix[0] = q0q0 + q1q1 - q2q2 - q3q3;// 11
- Rot_matrix[1] = 2.f * (q1*q2 + q0*q3); // 12
- Rot_matrix[2] = 2.f * (q1*q3 - q0*q2); // 13
- Rot_matrix[3] = 2.f * (q1*q2 - q0*q3); // 21
- Rot_matrix[4] = q0q0 - q1q1 + q2q2 - q3q3;// 22
- Rot_matrix[5] = 2.f * (q2*q3 + q0*q1); // 23
- Rot_matrix[6] = 2.f * (q1*q3 + q0*q2); // 31
- Rot_matrix[7] = 2.f * (q2*q3 - q0*q1); // 32
- Rot_matrix[8] = q0q0 - q1q1 - q2q2 + q3q3;// 33
-
- //1-2-3 Representation.
- //Equation (290)
- //Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors, James Diebel.
- // Existing PX4 EKF code was generated by MATLAB which uses coloum major order matrix.
- euler[0] = atan2f(Rot_matrix[5], Rot_matrix[8]); //! Roll
- euler[1] = -asinf(Rot_matrix[2]); //! Pitch
- euler[2] = atan2f(Rot_matrix[1], Rot_matrix[0]);
-
- //DCM . ground to body
- for(i=0; i<9; i++)
- {
- *(&(imu.DCMgb[0][0]) + i)=Rot_matrix[i];
- }
-
- imu.rollRad=euler[0];
- imu.pitchRad=euler[1];
- imu.yawRad=euler[2];
-
- imu.roll=euler[0] * 180.0f / M_PI_F;
- imu.pitch=euler[1] * 180.0f / M_PI_F;
- imu.yaw=euler[2] * 180.0f / M_PI_F;
- ahrseuler[GyrIdx-1][0] = imu.roll;
- ahrseuler[GyrIdx-1][1] = imu.pitch;
- ahrseuler[GyrIdx-1][2] = imu.yaw;
- }
-
- #define SENSOR_MAX_G 2.0f //constant g //
- #define SENSOR_MAX_W 2000.0f //deg/s
- #define ACC_SCALE (SENSOR_MAX_G/32768.0f)
- #define GYRO_SCALE (SENSOR_MAX_W/32768.0f)
- #define MAG_SCALE (0.15f)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。