博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
姿态解算
阅读量:4359 次
发布时间:2019-06-07

本文共 12580 字,大约阅读时间需要 41 分钟。

Imu.h

/* --------------------------------------------------------------------- *  * Imu库函数: * 姿态解算操作函数. * *   修订操作      版本号       日期         修订人 * ------------    ------    ----------    ------------ *     创建        1.0       2018.01.19      Universea * * ---------------------------------------------------------------------*/#ifndef __IMU_H#define __IMU_H#include "stm32f4xx_hal.h"#include "BasicData.h"//IMU数据结构体typedef struct {    //四元数    float q0;    float q1;    float q2;    float q3;    float XaxisVector[VECTOR_XYZ];    //载体坐标下的x方向向量    float YaxisVector[VECTOR_XYZ];    //载体坐标下的y方向向量    float ZaxisVector[VECTOR_XYZ];    //载体坐标下的z方向向量,重力向量    float HorizontalXaxisVector[VECTOR_XYZ];    ////水平面方向向量    float AirframeAccel[VECTOR_XYZ];    //机体加速度    float WorldAccel[VECTOR_XYZ];    //世界加速度    float AccelHorizontal[VECTOR_XYZ];    //水平加速度    float MagHorizontal[VECTOR_XYZ];    //磁力计水平    float gacc_deadzone[VECTOR_XYZ];    float ObserverAccelWorld[VECTOR_XYZ];    //世界加速度观测    float ObserverAccelAirframe[VECTOR_XYZ];    //机体加速度观测    float GravityAccel[VECTOR_XYZ];    //重力坐标系    float EstimatorAccelAirframe[VECTOR_XYZ];    //机体加速度估测    float EstimatorAcceHorizontal[VECTOR_XYZ];    //水平加速度估测    float EstimatorAccelWorld[VECTOR_XYZ];    //世界加速度估测    float EstimatorSpeedHorizontal[VECTOR_XYZ];    //水平速度估测    float EstimatorSpeedWorld[VECTOR_XYZ];    //世界速度估测    float ROLL;    //横滚角    float PITCH;    //俯仰角    float YAW;    //偏航角}imuStruct;extern imuStruct imuData;//IMU 状态结构体typedef struct {    float GyroKp;    //陀螺仪比例系数    float GyroKi;    //陀螺仪积分系数    float MagKp;    //磁力计比例系数    uint8_t GravityReset;    //重力复位    uint8_t MagReset;    //磁力计复位    uint8_t GravityFixEnable;    //重力修正使能    uint8_t MagFixEnable;    //磁力计修正使能    uint8_t ObserverEnable;    //观测器使能}imuStateStruct;extern imuStateStruct imuState;void imuUpdate(float dT,imuStateStruct *,float gyro[VECTOR_XYZ],int32_t accel[VECTOR_XYZ],int16_t magValue[VECTOR_XYZ],imuStruct *imu);//imu更新void calculateAttitudeAngle(void);//计算角度void w2h_2d_trans(float w[VECTOR_XYZ],float ref_ax[VECTOR_XYZ],float h[VECTOR_XYZ]);//世界转水平void h2w_2d_trans(float h[VECTOR_XYZ],float ref_ax[VECTOR_XYZ],float w[VECTOR_XYZ]);//水平转世界#endif
View Code

Imu.c

/* --------------------------------------------------------------------- *  * Imu库函数: * 姿态解算操作函数. * *   修订操作      版本号       日期         修订人 * ------------    ------    ----------    ------------ *     创建        1.0       2018.01.19      Universea * * ---------------------------------------------------------------------*/#include "MyMath.h"#include "Imu.h"#include "MyFilter.h"#include 
#include "InvSensor.h"/*参考坐标,定义为SKY坐标* * * 俯视,机头方向为x正方向 * +x \ +y --\-- \ *//* 转换 */void w2h_2d_trans( float w[VECTOR_XYZ], float ref_ax[VECTOR_XYZ], float h[VECTOR_XYZ] ) { h[X] = w[X] * ref_ax[X] + w[Y] * ref_ax[Y]; h[Y] = w[X] * (-ref_ax[Y]) + w[Y] * ref_ax[X];}void h2w_2d_trans( float h[VECTOR_XYZ], float ref_ax[VECTOR_XYZ], float w[VECTOR_XYZ] ) { w[X] = h[X] * ref_ax[X] + h[Y] * (-ref_ax[Y]); w[Y] = h[X] * ref_ax[Y] + h[Y] * ref_ax[X];}float mag_yaw_calculate( float dT, float magValue[VECTOR_XYZ], float g_ZaxisVector[VECTOR_XYZ], float MagHorizontal_val[VECTOR_XYZ] )/* */ { vec_3dh_transition( g_ZaxisVector, magValue, MagHorizontal_val ); return(fast_atan2( MagHorizontal_val[Y], MagHorizontal_val[X] ) * 57.3f);}#define USE_MAG#define USE_LENGTH_LIM/* 初始化 */imuStruct imuData = { 1, 0, 0, 0, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, 0, 0, 0 };static float vectorError[VECTOR_XYZ];static float vectorERR_I[VECTOR_XYZ];static float q0q1, q0q2, q1q1, q1q3, q2q2, q2q3, q3q3, q1q2, q0q3;/* q0q0, */static float magYawError, magValuefloat[VECTOR_XYZ];static float imuResetValue;static uint16_t resetCount;imuStateStruct imuState = { 1, 1, 1, 1, 1, 1, 1, 1 };float airframeMatrix[3][3], airframeTemp;float imu_test[3];void imuUpdate( float dT, imuStateStruct *state, float gyro[VECTOR_XYZ], int32_t accel[VECTOR_XYZ], int16_t magValue[VECTOR_XYZ], imuStruct *imu ) { static float kpUsing = 0, kiUsing = 0, maGyroKpUsing = 0; //修正系数 float accelNormalise, accelNormaliseReciprocal,quaternionNormalise; //单位化 float accelNorm[VECTOR_XYZ]; float gyroCompensate[VECTOR_XYZ]; /* 四元数组合 */ /* q0q0 = imu->q0 * imu->q0; */ q0q1 = imu->q0 * imu->q1; q0q2 = imu->q0 * imu->q2; q1q1 = imu->q1 * imu->q1; q1q3 = imu->q1 * imu->q3; q2q2 = imu->q2 * imu->q2; q2q3 = imu->q2 * imu->q3; q3q3 = imu->q3 * imu->q3; q1q2 = imu->q1 * imu->q2; q0q3 = imu->q0 * imu->q3; if ( state->ObserverEnable ) /* 观测器使能 */ { /* 计算机体坐标下的运动加速度观测量。坐标系为北西天 */ for ( uint8_t i = 0; i < 3; i++ ) { int32_t temp = 0; for ( uint8_t j = 0; j < 3; j++ ) { temp += imu->ObserverAccelWorld[j] * airframeMatrix[j][i]; /* airframeMatrix[i][j] 转置为 airframeMatrix[j][i] */ } imu->ObserverAccelAirframe[i] = temp; imu->GravityAccel[i] = accel[i] - imu->ObserverAccelAirframe[i]; } } else { /* 观测器失能 */ for ( uint8_t i = 0; i < 3; i++ ) { imu->GravityAccel[i] = accel[i]; /* 重力坐标系 */ } } /*单位化加速计测量值*/ accelNormaliseReciprocal = my_sqrt_reciprocal( my_pow( imu->GravityAccel[X] ) + my_pow( imu->GravityAccel[Y] ) + my_pow( imu->GravityAccel[Z] ) ); /* 反倒数 */ accelNormalise = safeDivision(1,accelNormaliseReciprocal, 0 ); /* 限幅0-1 */ /* 加速度计的读数,单位化。 */ for ( uint8_t i = 0; i < 3; i++ ) { accelNorm[i] = imu->GravityAccel[i] * accelNormaliseReciprocal; } /* 载体坐标下的x方向向量,单位化。 */ airframeMatrix[0][0] = imu->XaxisVector[X] = 1 - (2 * q2q2 + 2 * q3q3); airframeMatrix[0][1] = imu->XaxisVector[Y] = 2 * q1q2 - 2 * q0q3; airframeMatrix[0][2] = imu->XaxisVector[Z] = 2 * q1q3 + 2 * q0q2; /* 载体坐标下的y方向向量,单位化。 */ airframeMatrix[1][0] = imu->YaxisVector[X] = 2 * q1q2 + 2 * q0q3; airframeMatrix[1][1] = imu->YaxisVector[Y] = 1 - (2 * q1q1 + 2 * q3q3); airframeMatrix[1][2] = imu->YaxisVector[Z] = 2 * q2q3 - 2 * q0q1; /* 载体坐标下的z方向向量(等效重力向量、重力加速度向量),单位化。 */ airframeMatrix[2][0] = imu->ZaxisVector[X] = 2 * q1q3 - 2 * q0q2; airframeMatrix[2][1] = imu->ZaxisVector[Y] = 2 * q2q3 + 2 * q0q1; airframeMatrix[2][2] = imu->ZaxisVector[Z] = 1 - (2 * q1q1 + 2 * q2q2); /* 水平面方向向量 */ imu->HorizontalXaxisVector[X] = airframeMatrix[0][0]; imu->HorizontalXaxisVector[Y] = airframeMatrix[1][0]; /* 计算载体坐标下的运动加速度。(与姿态解算无关) */ for ( uint8_t i = 0; i < 3; i++ ) { imu->AirframeAccel[i] = (int32_t) (accel[i] - 981 * imu->ZaxisVector[i]); } /* 计算世界坐标下的运动加速度。坐标系为北西天 */ for ( uint8_t i = 0; i < 3; i++ ) { int32_t temp = 0; for ( uint8_t j = 0; j < 3; j++ ) { temp += imu->AirframeAccel[j] * airframeMatrix[i][j]; } imu->WorldAccel[i] = temp; } w2h_2d_trans( imu->WorldAccel, imuData.HorizontalXaxisVector, imu->AccelHorizontal ); /* 测量值与等效重力向量的叉积(计算向量误差)。 */ /* 将地理坐标系转换到机体坐标系下的重力向量与机体坐标系测量的向量外积(叉积),得到的就是两坐标系的误差 */ vectorError[X] = (accelNorm[Y] * imu->ZaxisVector[Z] - imu->ZaxisVector[Y] * accelNorm[Z]); vectorError[Y] = -(accelNorm[X] * imu->ZaxisVector[Z] - imu->ZaxisVector[X] * accelNorm[Z]); vectorError[Z] = -(accelNorm[Y] * imu->ZaxisVector[X] - imu->ZaxisVector[Y] * accelNorm[X]); #ifdef USE_MAG /* 计算航向yaw误差 */ for ( uint8_t i = 0; i < 3; i++ ) { magValuefloat[i] = (float) magValue[i]; } if ( !(magValue[X] == 0 && magValue[Y] == 0 && magValue[Z] == 0) ) { magYawError = mag_yaw_calculate( dT, magValuefloat, (imu->ZaxisVector), (imu->MagHorizontal) ) - imu->YAW; magYawError = range_to_180deg( magYawError ); } #endif for ( uint8_t i = 0; i < 3; i++ ) { #ifdef USE_EST_DEADZONE if ( state->GravityReset == 0 && state->ObserverEnable == 0 ) { vectorError[i] = my_deadzone( vectorError[i], 0, imu->gacc_deadzone[i] ); } #endif #ifdef USE_LENGTH_LIM if ( accelNormalise > 1060 || accelNormalise < 900 ) { vectorError[X] = vectorError[Y] = vectorError[Z] = 0; } #endif /* 误差积分 */ vectorERR_I[i] += LIMIT( vectorError[i], -0.01f, 0.01f ) * dT * kiUsing; /*构造增量旋转(含融合纠正)。 因为陀螺仪会有误差,且四元数更新姿态是用陀螺仪来跟新的,所以陀螺仪的 误差是导致机体坐标系产生误差的根本原因,这里用两坐标系误差的 PI 来补偿陀螺仪, 使得到的机体坐标系更加准确。*/ #ifdef USE_MAG gyroCompensate[i] = (gyro[i] + (vectorError[i] + vectorERR_I[i]) * kpUsing - magYawError * imu->ZaxisVector[i] * maGyroKpUsing * RAD_PER_DEG) * dT / 2; # else gyroCompensate[i] = (gyro[i] + (vectorError[i] + vectorERR_I[i]) * kpUsing) * dT / 2; #endif } /* 四元数姿态更新 */ imu->q0 = imu->q0 - imu->q1 * gyroCompensate[X] - imu->q2 * gyroCompensate[Y] - imu->q3 * gyroCompensate[Z]; imu->q1 = imu->q0 * gyroCompensate[X] + imu->q1 + imu->q2 * gyroCompensate[Z] - imu->q3 * gyroCompensate[Y]; imu->q2 = imu->q0 * gyroCompensate[Y] - imu->q1 * gyroCompensate[Z] + imu->q2 + imu->q3 * gyroCompensate[X]; imu->q3 = imu->q0 * gyroCompensate[Z] + imu->q1 * gyroCompensate[Y] - imu->q2 * gyroCompensate[X] + imu->q3; //由于误差的引入使得四元数的模不再等于 1,四元数失去了规范性,因此在利用更新后的四元数计算欧拉角时,必须对四元数进行规范化处理 quaternionNormalise = my_sqrt_reciprocal( imu->q0 * imu->q0 + imu->q1 * imu->q1 + imu->q2 * imu->q2 + imu->q3 * imu->q3 ); imu->q0 *= quaternionNormalise; imu->q1 *= quaternionNormalise; imu->q2 *= quaternionNormalise; imu->q3 *= quaternionNormalise; /* ///修正开关/// */ #ifdef USE_MAG if ( state->MagFixEnable == 0 ) /* 磁力 */ { maGyroKpUsing = 0; /*不修正 */ state->MagReset = 0; /* 罗盘修正不复位,清除复位标记 */ } else { if ( state->MagReset ) /* */ { /* 通过增量进行对准 */ maGyroKpUsing = 5.0f; if ( magYawError != 0 && ABS( magYawError ) < 2 ) { state->MagReset = 0; /* 误差小于2的时候,清除复位标记 */ } } else { maGyroKpUsing = state->MagKp; /* 正常修正 */ } } #endif if ( state->GravityFixEnable == 0 ) /* 重力方向修正 */ { kpUsing = 0; /*不修正 */ } else { if ( state->GravityReset == 0 ) /* 正常修正 */ { kpUsing = state->GyroKp; kiUsing = state->GyroKi; } else { /* 快速修正,通过增量进行对准 */ kpUsing = 5.0f; kiUsing = 0.5f; /* * imu->EstimatorSpeedWorld[X] = imu->EstimatorSpeedWorld[Y] = 0; * imu->EstimatorAccelWorld[X] = imu->EstimatorAccelWorld[Y] = 0; * imu->EstimatorAcceHorizontal[X] = imu->EstimatorAcceHorizontal[Y] =0; */ /* 计算静态误差是否缩小 */ imuResetValue += (ABS( vectorError[X] ) + ABS( vectorError[Y] ) ) * 1000 * dT; imuResetValue -= 0.01f; imuResetValue = LIMIT( imuResetValue, 0, 1.0f ); if ( (imuResetValue < 0.01f) && (state->MagReset == 0) ) { /* 计时 */ resetCount += 2; if ( resetCount > 500 ) { resetCount = 0; state->GravityReset = 0; /* 已经对准,清除复位标记 */ } } else { resetCount = 0; } } }}void calculateAttitudeAngle() { /* /输出姿态角/// */ airframeTemp = LIMIT( 1 - my_pow( airframeMatrix[2][0] ), 0, 1 ); /* imuData.PITCH = asin(2*q1q3 - 2*q0q2)*57.30f; */ if ( ABS( imuData.ZaxisVector[Z] ) > 0.05f ) /* 避免奇点的运算 */ { imuData.PITCH = fast_atan2( airframeMatrix[2][0], my_sqrt( airframeTemp ) ) * 57.30f; imuData.ROLL = fast_atan2( airframeMatrix[2][1], airframeMatrix[2][2] ) * 57.30f; imuData.YAW = -fast_atan2( airframeMatrix[1][0], airframeMatrix[0][0] ) * 57.30f; }}
View Code

 

转载于:https://www.cnblogs.com/universea/p/8371291.html

你可能感兴趣的文章
1014
查看>>
Hive的Transform功能
查看>>
该怎样提高ZBrush的创作效率
查看>>
js-call、apply
查看>>
NOIP模拟题——LGTB与序列
查看>>
Codeforces Round #396 (Div. 2) A.Mahmoud and Longest Uncommon Subsequence
查看>>
创建部署规划
查看>>
JS鼠标捕获DIV内选中的坐标和宽高
查看>>
PM项目管理流程
查看>>
R语言从小木虫网页批量提取考研调剂信息
查看>>
ORACLE的rownum用法。用rownum来进行分页查询
查看>>
spring的部分配置
查看>>
django ORM模型表的一对多、多对多关系、万能双下划线查询
查看>>
学习——JavaWeb04:HTTP协议
查看>>
TYVJ P1728 普通平衡树
查看>>
【bzoj1854】[Scoi2010]游戏 二分图最大匹配
查看>>
【bzoj1579】[Usaco2009 Feb]Revamping Trails 道路升级 分层图最短路
查看>>
【bzoj2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机
查看>>
【bzoj2597】[Wc2007]剪刀石头布 动态加边费用流
查看>>
【uoj#21】[UR #1]缩进优化 数学
查看>>