搜索
bottom↓
回复: 21

AHRS航姿解算算法疑问

[复制链接]

出0入0汤圆

发表于 2015-12-15 19:49:01 | 显示全部楼层 |阅读模式
先上程序,如下:

#define Kp 2.0f         // 比例增益支配收敛率accelerometer/magnetometer
#define Ki 0.005f         // 积分增益执政速率陀螺仪的衔接gyroscopeases
#define halfT 0.5f         // 采样周期的一半

//---------------------------------------------------------------------------------------------------

float q0 = 1, q1 = 0, q2 = 0, q3 = 0;        // 四元数的元素,代表估计

方向
float exInt = 0, eyInt = 0, ezInt = 0;        // 按比例缩小积分误差

//====================================================================================================
// Function
//====================================================================================================

void AHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {
float norm;
float hx, hy, hz, bx, bz;
float vx, vy, vz, wx, wy, wz;
float ex, ey, ez;

// 辅助变量,以减少重复操作数
float q0q0 = q0*q0;
float q0q1 = q0*q1;
float q0q2 = q0*q2;
float q0q3 = q0*q3;
float q1q1 = q1*q1;
float q1q2 = q1*q2;
float q1q3 = q1*q3;
float q2q2 = q2*q2;   
float q2q3 = q2*q3;
float q3q3 = q3*q3;           

// 测量正常化
norm = sqrt(ax*ax + ay*ay + az*az);        
ax = ax / norm;
ay = ay / norm;
az = az / norm;
norm = sqrt(mx*mx + my*my + mz*mz);           
mx = mx / norm;
my = my / norm;
mz = mz / norm;         

// 计算参考磁通方向
hx = 2*mx*(0.5 - q2q2 - q3q3) + 2*my*(q1q2 - q0q3) + 2*mz*(q1q3 + q0q2);
hy = 2*mx*(q1q2 + q0q3) + 2*my*(0.5 - q1q1 - q3q3) + 2*mz*(q2q3 - q0q1);
hz = 2*mx*(q1q3 - q0q2) + 2*my*(q2q3 + q0q1) + 2*mz*(0.5 - q1q1 - q2q2);         
bx = sqrt((hx*hx) + (hy*hy));
bz = hz;         

//估计方向的重力和磁通(V和W)
vx = 2*(q1q3 - q0q2);
vy = 2*(q0q1 + q2q3);
vz = q0q0 - q1q1 - q2q2 + q3q3;
wx = 2*bx*(0.5 - q2q2 - q3q3) + 2*bz*(q1q3 - q0q2);
wy = 2*bx*(q1q2 - q0q3) + 2*bz*(q0q1 + q2q3);
wz = 2*bx*(q0q2 + q1q3) + 2*bz*(0.5 - q1q1 - q2q2);   

// 错误是跨产品的总和之间的参考方向的领域和方向测量传感器
ex = (ay*vz - az*vy) + (my*wz - mz*wy);
ey = (az*vx - ax*vz) + (mz*wx - mx*wz);
ez = (ax*vy - ay*vx) + (mx*wy - my*wx);

// 积分误差比例积分增益
exInt = exInt + ex*Ki;
eyInt = eyInt + ey*Ki;
ezInt = ezInt + ez*Ki;

// 调整后的陀螺仪测量
gx = gx + Kp*ex + exInt;
gy = gy + Kp*ey + eyInt;
gz = gz + Kp*ez + ezInt;

// 整合四元数率和正常化
q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT;
q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT;
q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;   

// 正常化四元
norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
q0 = q0 / norm;
q1 = q1 / norm;
q2 = q2 / norm;
q3 = q3 / norm;
}

这个程序里面的思路是用ACC和MAG数据校正GRY数据,但是有点疑问的是:这个函数的输入值是什么?看到有人是这么写的:/*输入参数为加速度xyz原始数据,磁力计xyz原始数据,陀螺仪数据必须转换为弧度制*/

问题来了,这里的加速度xyz原始数据,磁力计xyz原始数据,是指的6050和8975输出的校正后的数据吗?陀螺仪数据必须转换为弧度制,知道的是6050的陀螺仪的输出数据的单位是度每秒,是不是直接除以57.3换成弧度每秒?

最后一个也是最重要的一个,这个AHRS算法能结算出正确的角度吗?我的解算思路是:用TIM定时器定时,每2ms读取一次6050数据,每5ms解算一次姿态,每10ms读取一次8975数据,用这个算法解算的时候,我的角度输出如图:

ROL和YAW角的值明显不对,PIT的值直接为0,原以为是中断中的浮点数不可重入的原因,但是在中断给标志位,main中计算还是不行,真心不清楚什么原因,求大神们指导!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2015-12-15 21:52:54 | 显示全部楼层
以下是我个人使用过程中的理解:
加速度和电子罗盘数据都是经过正常化的,直接使用。陀螺仪要转化成弧度。
要根据你的采样频率调整本函数的三个参数。
另外AHRS的四元数需要初始化。

出0入0汤圆

 楼主| 发表于 2015-12-16 10:25:47 | 显示全部楼层
zhangyun2743 发表于 2015-12-15 21:52
以下是我个人使用过程中的理解:
加速度和电子罗盘数据都是经过正常化的,直接使用。陀螺仪要转化成弧度。
...


“加速度和电子罗盘数据都是经过正常化的”,是不是说直接用从6050和8975读取的AD值,陀螺仪转换为弧度应该是指的将度每秒转换为弧度每秒??

“要根据你的采样频率调整本函数的三个参数”,这句话不太明白,这个姿态更新函数的输入参数应该是ACC,GYR,MAG这9个数据,和采样周期怎么联系?

四元数最后归一化没问题,这是保证求解准确的。

还望能够指导一下,谢谢!

出0入0汤圆

发表于 2015-12-16 11:01:35 | 显示全部楼层
加速度和电子罗盘数据可以直接用AD读取到的值,不过最好滤波处理下。读取到的陀螺仪数据转化为弧度每秒。
Kp  Ki  halfT 这三个参数要改,halfT是采样周期一半,比如你陀螺仪采样速率为2ms一次,那么halfT=0.001,剩下两个根据其作用手动调调看,尽量增大角度变化的稳定性和减少误差。

出0入0汤圆

发表于 2015-12-16 11:03:58 | 显示全部楼层
另外加速度和电子罗盘数据还是推荐将AD读取到的数据经过数据手册里的比例因子转换为实际值,也方便以后处理和观察

出0入0汤圆

 楼主| 发表于 2015-12-16 11:52:04 | 显示全部楼层
zhangyun2743 发表于 2015-12-16 11:03
另外加速度和电子罗盘数据还是推荐将AD读取到的数据经过数据手册里的比例因子转换为实际值,也方便以后处理 ...

外加速度和电子罗盘数据还是推荐将AD读取到的数据经过数据手册里的比例因子转换为实际值??这句不太明白,实际值指的的是实际单位的值吗?像加速度一样转换为m/s^2这样?


在调用IMUupdate();这个函数的时候,ACC,GYR,MAG这几个的数据都能传递进来,但是在结算过程中,结算出来的角度直接不对,静止时,陀螺仪的数据在0000,和FFFF之间来回变,但是在仅修改磁感器数据为234,365,876这样的随意给定值时,角度输出不在固定上图那样是来回变化的,到底哪的问题,有点迷糊………………

出0入0汤圆

发表于 2015-12-16 12:06:10 | 显示全部楼层
实际值就是实际单位的值  比例因子你看技术手册  在参数里有sensitivity scale factor  ,用过这个可以吧AD值转化为实际值。

另外IMU好像不需要罗盘数据吧? 至于陀螺仪在0x0000和0xffff直接变化,如果这时的数据值AD采集到的值,那么很正常,但是如果如果已经化为度/秒了,那你就需要校准AD采集值的偏差了。   一定注意陀螺仪数据要从实际值(不是AD值)转化为弧度

出0入0汤圆

 楼主| 发表于 2015-12-16 12:17:42 | 显示全部楼层
zhangyun2743 发表于 2015-12-16 12:06
实际值就是实际单位的值  比例因子你看技术手册  在参数里有sensitivity scale factor  ,用过这个可以吧AD ...

另外IMU好像不需要罗盘数据吧? 至于陀螺仪在0x0000和0xffff直接变化,如果这时的数据值AD采集到的值,那么很正常,但是如果如果已经化为度/秒了,那你就需要校准AD采集值的偏差了。   一定注意陀螺仪数据要从实际值(不是AD值)转化为弧度

我用的AHRS解算姿态,用磁感数据校正陀螺仪,

仿真时加入窗口的是陀螺仪的AD值,陀螺仪的弧度转换是AD值 / 16.4精度值 * 3.141592657 / 180。

仿真时发现,这几个数据都能传递过来,但是解算出来的角度不对,直接就像最上面的图一样,很是不明白,参数都对的,为什么解算出来就不对,结算过程不对?这是常用的AHRS解算过程啊,很是明白……………………
真是难得糊涂啊……………………

很感谢您的耐心指导,谢谢!都中午了,吃点好吃的慰劳慰劳自己吧……

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-12-16 12:33:42 | 显示全部楼层
我的AHRS使用时先将四元数q0,q1,q2,q3初始化了,给你代码你试试
void init_quaternion(void)
{
//陀螺仪y轴为前进方向   
init_Roll = -atan2(acc[0], acc[2]);    //算出的单位是弧度,如需要观察则应乘以57.3转化为角度
init_Pitch=  asin(acc[1]);              //init_Pitch = asin(ay / 1);      
init_Yaw  =  atan2(mag[0]*cos(init_Roll) + mag[1]*sin(init_Roll)*sin(init_Pitch) + mag[2]*sin(init_Roll)*cos(init_Pitch),
                   mag[1]*cos(init_Pitch) - mag[2]*sin(init_Pitch));//类似于atan2(my, mx),其中的init_Roll和init_Pitch是弧度
if(init_Yaw < 0){init_Yaw = init_Yaw + 2*3.141593f;}
if(init_Yaw > 360){init_Yaw = init_Yaw - 2*3.141593f;}                                           
//将初始化欧拉角转换成初始化四元数,注意sin(a)的位置的不同,可以确定绕xyz轴转动是Pitch还是Roll还是Yaw,按照ZXY顺序旋转,Qzyx=Qz*Qy*Qx,其中的init_YawRollPtich是角度        
q0 = cos(0.5f*init_Roll)*cos(0.5f*init_Pitch)*cos(0.5f*init_Yaw) - sin(0.5f*init_Roll)*sin(0.5f*init_Pitch)*sin(0.5f*init_Yaw);  //w
q1 = cos(0.5f*init_Roll)*sin(0.5f*init_Pitch)*cos(0.5f*init_Yaw) - sin(0.5f*init_Roll)*cos(0.5f*init_Pitch)*sin(0.5f*init_Yaw);  //x   绕x轴旋转是pitch
q2 = sin(0.5f*init_Roll)*cos(0.5f*init_Pitch)*cos(0.5f*init_Yaw) + cos(0.5f*init_Roll)*sin(0.5f*init_Pitch)*sin(0.5f*init_Yaw);  //y   绕y轴旋转是roll
q3 = cos(0.5f*init_Roll)*cos(0.5f*init_Pitch)*sin(0.5f*init_Yaw) + sin(0.5f*init_Roll)*sin(0.5f*init_Pitch)*cos(0.5f*init_Yaw);  //z   绕z轴旋转是Yaw

}

出0入0汤圆

发表于 2015-12-16 12:39:43 | 显示全部楼层
halfT 是指两次调用本算法解算之间的时间的一半,不是指采样时间的一半
定时解算,halfT直接取定值
连续解算,可以用定时器测量两次解算过程的时间,halfT取定时器时间的一半

出0入0汤圆

 楼主| 发表于 2015-12-17 07:59:17 | 显示全部楼层
[quote]zhangyun2743 发表于 2015-12-16 12:33



init_Roll = -atan2(acc[0], acc[2]);    //算出的单位是弧度,如需要观察则应乘以57.3转化为角度
init_Pitch=  asin(acc[1]);              //init_Pitch = asin(ay / 1);      
init_Yaw  =  atan2(mag[0]*cos(init_Roll) + mag[1]*sin(init_Roll)*sin(init_Pitch) + mag[2]*sin(init_Roll)*cos(init_Pitch),
                   mag[1]*cos(init_Pitch) - mag[2]*sin(init_Pitch));//类似于atan2(my, mx),其中的init_Roll和init_Pitch是弧度
if(init_Yaw < 0){init_Yaw = init_Yaw + 2*3.141593f;}
if(init_Yaw > 360){init_Yaw = init_Yaw - 2*3.141593f;}

这几条语句是不是就能够求解出Roll,Pitch Yaw了,那后面初始化四元数做什么?还是说用初始化的四元数再求解角度?

init_Roll这种格式是不是把角强制转换成了int类型?还是就是浮点型?

acc[0]是加速度数据,mag[0]是磁感器数据?这个数据是不是由采样AD值/精度转换成了实际单位数值?

昨天下午忙着出图了,一直没看,sorry…………………………

出0入0汤圆

 楼主| 发表于 2015-12-17 08:06:07 | 显示全部楼层
samo110 发表于 2015-12-16 12:39
halfT 是指两次调用本算法解算之间的时间的一半,不是指采样时间的一半
定时解算,halfT直接取定值
连续解 ...

”halfT 是指两次调用本算法解算之间的时间的一半“    我是定时每10ms进一次中断解算一次,这样halfT是不是取值为5ms?

出0入0汤圆

发表于 2015-12-17 10:09:18 | 显示全部楼层
hswkcg 发表于 2015-12-17 08:06
”halfT 是指两次调用本算法解算之间的时间的一半“    我是定时每10ms进一次中断解算一次,这样halfT是 ...

是的,但是我记得halfT的单位是秒,这个要注意

出0入0汤圆

发表于 2015-12-17 10:14:52 | 显示全部楼层
不懂帮顶!

出0入0汤圆

发表于 2015-12-17 13:07:09 | 显示全部楼层
是的,应该是0.005

出0入0汤圆

发表于 2015-12-17 15:32:43 | 显示全部楼层
我觉得不是直接AD值,而是算出来的加速度值,具体是不是还要看你程序里乘以的系数

出0入0汤圆

 楼主| 发表于 2015-12-17 16:46:28 | 显示全部楼层

那么也就是ACC,GYR和MAG的输入都是实际单位值,halfT的值是0.005s?

我没太明白您的算法,是用加速度数据求解出PICT和ROL角,然后用磁感数据和求解出来的角度求解YAW角,
但是为什么还要更新四元数呢?又没用四元数求解姿态角。。。

出0入0汤圆

 楼主| 发表于 2015-12-17 16:47:01 | 显示全部楼层

谢谢,大家互相交流……

出0入0汤圆

 楼主| 发表于 2015-12-17 16:48:10 | 显示全部楼层
qrytian 发表于 2015-12-17 15:32
我觉得不是直接AD值,而是算出来的加速度值,具体是不是还要看你程序里乘以的系数 ...

谢谢您的回答,我会用AD值和实际单位值分别仿真求解一遍,具体是哪个会在有结果后贴出来…………

出0入0汤圆

发表于 2015-12-18 11:38:34 | 显示全部楼层
hswkcg 发表于 2015-12-17 16:46
那么也就是ACC,GYR和MAG的输入都是实际单位值,halfT的值是0.005s?

我没太明白您的算法,是用加速度数 ...

那个是初始化四元数q0,q1,q2,q3的函数,初始化后再用于AHRS

出0入0汤圆

发表于 2015-12-18 14:37:44 | 显示全部楼层
zhangyun2743 发表于 2015-12-16 12:33
我的AHRS使用时先将四元数q0,q1,q2,q3初始化了,给你代码你试试
void init_quaternion(void)
{

请问你的这个坐标是怎么定义的?

出0入0汤圆

发表于 2015-12-19 09:40:32 | 显示全部楼层
yzhu 发表于 2015-12-18 14:37
请问你的这个坐标是怎么定义的?

acc,mag[0]--------pitch
acc,acc[1]--------roll
acc,acc[2]----------yaw
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 15:12

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表