hychwlq 发表于 2013-4-21 22:08:57

关于四轴算法——四元数与欧拉角的转化

关于四元数与欧拉角的转化的疑惑
看到好多人的飞控程序在处理偏航角——Yaw,俯仰角——Pitch,翻滚角——Rool的时候均用到这样两句代码:
                Pitch= asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch
                Rool = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // rollv
并且没有对Waw进行计算,但是自己查相关文献资料,可以得到四元数与欧拉角的如下转换公式:
                Yaw=      atan2f( 2 * (q0 * q1 + q2 * q3), q0q0 - q1q1 - q2q2 + q3q3 )*57.3;//yaw
                Pitch=      asin(-2 * (q1 * q3 + 2 * q0* q2)* 57.3; // pitch
                Rool =    atan2 ( 2 * (q1 * q2 + 2 * q0 * q3), q0q0 + q1q1 - q2q2 - q3q3 )* 57.3; //roll
如附图所示,文件来源:全角度欧拉角与四元数转换研究.pdf
各位大侠,聊聊你们对这部分的理解吧。。。
既然程序都可以用,那应该是有一定的道理的,请问这部分为什么这样处理?
而且不需要求Yaw,这又是为什么呢/???
谢谢各位大神啦!!!


程序源码如下:


#include<math.h>
//---------------------------------------------------------------------------------------------------
// 变量定义

#define f 1
#define Kp 2.0f                        // 比例增益支配率收敛到加速度计/磁强计
#define Ki 0.005f                // 积分增益支配率的陀螺仪偏见的衔接
#define halfT 0.5f                // 采样周期的一半

float q0 = 1, q1 = 0, q2 = 0, q3 = 0;          // 四元数的元素,代表估计方向
float exInt = 0, eyInt = 0, ezInt = 0;      // 按比例缩小积分误差
float gx=0,gy=0,gz=0,ax=0,ay=0,az=0;          //全局变量


//互补滤波
//时间常数   t=a/(1-a)*dt    a=t/(t+dt)         t 截至频率dt计算间隔时间
#define      kfa   0.98
#define      kfan1.0-kfa
//ang= kfa*ang+kfgn*acc;

#define      kfg   0.80
#define      kfgn1.0-kfg
float Yaw,Pitch,Rool;//偏航角,俯仰角,翻滚角

//ang= kfa*g+kfgn*acc;

//====================================================================================================
// Function
//====================================================================================================
//gx 采样时间弧度增量
//加数度为3轴采样数据,做归一化
//输出为4元数

void IMUupdate(float gxi, float gyi, float gzi, float axi, float ayi, float azi) {
      float norm;
      float vx, vy, vz;
      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;

      ax=ax*kfa+kfan*axi;
      ay=ay*kfa+kfan*ayi;
      az=az*kfa+kfan*azi;

      gx=gx*kfg+kfgn*gxi;
      gy=gy*kfg+kfgn*gyi;
      gz=gz*kfg+kfgn*gzi;

      // 测量正常化
      norm = sqrt(ax*ax + ay*ay + az*az);      
      ax = ax / norm;
      ay = ay / norm;
      az = az / norm;      
      
      // 估计方向的重力
      vx = 2*(q1*q3 - q0*q2);
      vy = 2*(q0*q1 + q2*q3);
      vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
      
      // 错误的领域和方向传感器测量参考方向之间的交叉乘积的总和
      ex = (ay*vz - az*vy);
      ey = (az*vx - ax*vz);
      ez = (ax*vy - ay*vx);
      
      // 积分误差比例积分增益
      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;
      Pitch= asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch
      Rool = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // rollv
}

lxl_lw 发表于 2013-4-21 22:19:15

不明白四元数+1,帮顶!{:3_48:}

js200300953 发表于 2013-4-21 22:45:40

四元数只有一种,欧拉角跟旋转顺序有关的,不同旋转顺序有不同公式。

js200300953 发表于 2013-4-21 22:47:26

那个// 测量正常化是卖萌吗?

binham 发表于 2013-4-22 17:55:20

pdf我下载怎么是.attach的文件呢?

sgzzour 发表于 2013-4-22 18:01:09

binham 发表于 2013-4-22 17:55 static/image/common/back.gif
pdf我下载怎么是.attach的文件呢?

没关系,直接打开就行。

sgzzour 发表于 2013-4-22 18:01:55

帮顶,最近也在学四元数,等大神出现。

binham 发表于 2013-4-22 18:05:59

sgzzour 发表于 2013-4-22 18:01 static/image/common/back.gif
没关系,直接打开就行。

可是.attach的文件下载下来打不开啊

sgzzour 发表于 2013-4-22 18:07:57

binham 发表于 2013-4-22 18:05 static/image/common/back.gif
可是.attach的文件下载下来打不开啊

你在属性里面改一下设置,选择你所用的pdf打开文件即可。

binham 发表于 2013-4-22 18:09:42

sgzzour 发表于 2013-4-22 18:07 static/image/common/back.gif
你在属性里面改一下设置,选择你所用的pdf打开文件即可。

好了 多谢~~

hychwlq 发表于 2013-4-22 19:24:40

保存的时候直接保存为PDF格式就OK了,等待大神。。。

svon 发表于 2013-4-22 21:05:39

LZ在哪看的别人的飞控程序啊,表示很难找到完整点的~~

svon 发表于 2013-4-22 21:12:16

四元数不是用在陀螺仪中将上一时刻角度加上角度增量得到下一时刻的角度吗? 加速度计和陀螺仪的融合和四元数有什么关系呢?

Gost 发表于 2013-4-23 20:43:20

mark 不明白

wu13180 发表于 2013-5-5 08:34:19

halfT的时间是怎么算的??需要一个时间间隔吗??怎么我使用这个函数转化后得出的Pitch和Rool很奇怪~变化很小~

g921002 发表于 2013-5-5 09:32:49

IMUupdate()這個函數只針對加速規及陀螺儀資料做融合,所以真的有修正到的只有pitch(俯仰)和roll(滾轉),yaw(方位)是沒有修正到的。

要把電子羅盤的數據放進來yaw的輸出才有被修正。
例如Madgwick's IMU and AHRS algorithms.
http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms

你也可以直接用
Yaw=atan2f( 2 * (q0 * q1 + q2 * q3), q0q0 - q1q1 - q2q2 + q3q3 )*57.3;
計算yaw的方位角,可以發現在沒有電子羅盤輔助下這個角度是會飄的。

>>四元数不是用在陀螺仪中将上一时刻角度加上角度增量得到下一时刻的角度吗? 加速度计和陀螺仪的融合和四元数有什么关系呢?

概念上是的,加速規是要去除陀螺儀的長期飄移,請見Madgwick的論文,這個很好的方式是用梯度下降法將加速規直接再四元素系統作融合。

>>halfT的时间是怎么算的??需要一个时间间隔吗??

前面代碼有寫
#define halfT 0.5f    // 采样周期的一半

這裡說採樣週期不太嚴謹,這是是指姿態更新的週期,通常會用高取樣率取樣--->濾波--->低更新週期(ex:50Hz)做更新。

lologame 发表于 2013-5-5 09:45:14

g921002 发表于 2013-5-5 09:32 static/image/common/back.gif
IMUupdate()這個函數只針對加速規及陀螺儀資料做融合,所以真的有修正到的只有pitch(俯仰)和roll(滾轉),ya ...

您好,我将电子罗盘测量到的数据,进行AHRSupdate的四元数更新。

旋转设备以后,yaw跟着转,但是yaw马上又回到之前那个值,有点像指南针一样....不知道为什么会出这种问题...

初始化四元数的时候,yaw我是令的0,只有roll和pitch角,进行了计算。、、

asha 发表于 2013-5-5 10:42:52

lologame 发表于 2013-5-5 09:45 static/image/common/back.gif
您好,我将电子罗盘测量到的数据,进行AHRSupdate的四元数更新。

旋转设备以后,yaw跟着转,但是yaw马上 ...

你把电子指南针去掉 只用陀螺就行了

lologame 发表于 2013-5-5 13:06:50

asha 发表于 2013-5-5 10:42 static/image/common/back.gif
你把电子指南针去掉 只用陀螺就行了

我用过IMUupdate,但是无法修正yaw。要修正yaw角的话,不是必须用指南针吗、、?yaw的数据稳定是我最想要的

asha 发表于 2013-5-5 13:13:00

lologame 发表于 2013-5-5 13:06 static/image/common/back.gif
我用过IMUupdate,但是无法修正yaw。要修正yaw角的话,不是必须用指南针吗、、?yaw的数据稳定是我最想 ...

那应该是你有的地方程序错了 要不应该不会这样的

lologame 发表于 2013-5-5 13:22:20

asha 发表于 2013-5-5 13:13 static/image/common/back.gif
那应该是你有的地方程序错了 要不应该不会这样的

我没有进行yaw的初始化,不知道这样有没有影响....

lologame 发表于 2013-5-5 13:51:20

asha 发表于 2013-5-5 13:13 static/image/common/back.gif
那应该是你有的地方程序错了 要不应该不会这样的

IMUupdate的时候,roll pitch角都可以纠正、
我直接把IMUupdate函数换成AHRSupdate,并添加了HMC5883L测量出来的磁力矢量(读取HMC5883L数据后,将数据进行正负转换)。

不知道这样会有没有什么不妥、

asha 发表于 2013-5-5 14:53:19

lologame 发表于 2013-5-5 13:51 static/image/common/back.gif
IMUupdate的时候,roll pitch角都可以纠正、
我直接把IMUupdate函数换成AHRSupdate,并添加了HMC5883L测 ...

不初始化不行 ,必须初始化。具体那个程序我没有看过,呵呵。推销下我的开发板嘎嘎

lologame 发表于 2013-5-5 14:59:42

asha 发表于 2013-5-5 14:53 static/image/common/back.gif
不初始化不行 ,必须初始化。具体那个程序我没有看过,呵呵。推销下我的开发板嘎嘎...

呵呵,就是没找到yaw的初始化,哎。。、、

asha 发表于 2013-5-5 15:04:35

用电子罗盘进行初始化就行

yamqqqq 发表于 2013-5-5 15:18:11

在工业机器人里也有用到这些问题!

g921002 发表于 2013-5-5 19:14:28

lologame 发表于 2013-5-5 09:45 static/image/common/back.gif
您好,我将电子罗盘测量到的数据,进行AHRSupdate的四元数更新。

旋转设备以后,yaw跟着转,但是yaw马上 ...

你有檢查電子羅盤是不是有正確的輸出?還有軸向是不是跟你的body座標定義一樣?
我是用Madgwick 的 AHRS algorithms.沒有這樣的問題,你要不要去試試看?

mazhenyu 发表于 2013-5-5 20:39:33

binham 发表于 2013-4-22 18:05 static/image/common/back.gif
可是.attach的文件下载下来打不开啊

或者直接改后缀

lologame 发表于 2013-5-5 21:28:18

g921002 发表于 2013-5-5 19:14 static/image/common/back.gif
你有檢查電子羅盤是不是有正確的輸出?還有軸向是不是跟你的body座標定義一樣?
我是用Madgwick 的 AHRS...

电子罗盘的坐标输出不知道怎么检测是不是对的,我把读出来的数据,进行了正负转换的。

嗯,能提供一个网址吗?

hychwlq 发表于 2013-5-13 14:56:04

g921002,真是大神啊,现在刚刚起步,还没有飞起来呢,继续研习算法,工作较忙,盼望您的帮助啊。。。

sedulity11 发表于 2013-5-13 15:39:40

马克一下,正好用到

xuyulei008 发表于 2013-5-14 09:55:41

没入门,各种不懂

keyxyh 发表于 2013-5-19 02:53:24

楼主你好,看了你的帖子学习了很多,有个疑问,你程序中的参数gx.gy.gz,ax,ay,az是传感器读出来的值单位化后的结果吗?gxi,gyi,gzi,axi,ayi,azi是怎么得来的呢

icoer 发表于 2013-5-20 12:06:22

没入门,各种不懂,
马克一下

hychwlq 发表于 2013-5-22 14:40:32

gxi,gyi,gzi,axi,ayi,azi是六轴输出数据,gx.gy.gz,ax,ay,az是经过滤波处理后的数据,最主要是角度转到四元数这一块。不要在其他地方下太多功夫。

lologame 发表于 2013-5-22 21:24:36

hychwlq 发表于 2013-5-22 14:40 static/image/common/back.gif
gxi,gyi,gzi,axi,ayi,azi是六轴输出数据,gx.gy.gz,ax,ay,az是经过滤波处理后的数据,最主要是角度转到四元 ...

您好,四元数获得的矩阵,到底 与 以什么欧拉角旋转的方向余弦矩阵 相对应呢?

lologame 发表于 2013-5-22 22:59:50

js200300953 发表于 2013-4-21 22:45 static/image/common/back.gif
四元数只有一种,欧拉角跟旋转顺序有关的,不同旋转顺序有不同公式。

大侠,具体是什么公式不一样呢?

pangyan111111 发表于 2013-7-23 16:05:05

最后得到的rool 和pitch 是欧拉角表示吧?

wyq200704 发表于 2013-8-10 17:10:15

学习ing~~

小乖 发表于 2013-8-13 15:37:43

看了几天的代码,还是模模糊糊的{:mad:}{:mad:}

oldbreadman 发表于 2013-9-3 23:22:01

g921002 发表于 2013-5-5 19:14 static/image/common/back.gif
你有檢查電子羅盤是不是有正確的輸出?還有軸向是不是跟你的body座標定義一樣?
我是用Madgwick 的 AHRS...

想请教一下,Madgwick 的AHRS函数参数,
AHRSupdate(Gyro_FinalX*0.0174,Gyro_FinalY*0.0174, Gyro_FinalZ*0.0174,-ACC_AVG_Y*0.0098,ACC_AVG_X*0.0098,ACC_AVG_Z*0.0098,magADC,magADC,magADC);

其中Gyro和ACC的参数都经过了预处理,但磁罗盘的参数我不知道该如何预处理,如果直接用椭圆修正之后的罗盘的直接值,得不到正确的解算,请问磁罗盘的数据输入是不是还要有一个系数什么的??

monroeking 发表于 2013-9-5 21:31:40

好好研究一下四元数。

Lanxm 发表于 2013-9-10 14:04:24

表示正在埋头找资料,有点看不懂。

zwj512 发表于 2013-9-12 14:02:47

用过没研究过                        {:mad:}

whuer 发表于 2013-9-17 19:45:33

看看迷惑中

matt_cc 发表于 2013-9-18 15:38:27

牛贴mark

shuizhb 发表于 2013-9-25 21:56:29

持续关注

jhjkdz 发表于 2013-9-25 22:12:46

谢谢,学习一下

dengkai092 发表于 2013-9-26 23:29:30

这个关系还是比较重要的

julian 发表于 2013-9-28 12:59:44

哪里找的?这段代码很多人在用啊好像

-阿发- 发表于 2013-10-10 11:15:46

binham 发表于 2013-4-22 18:09 static/image/common/back.gif
好了 多谢~~

重命名,把后缀改为PDF就可以用了。

-阿发- 发表于 2013-10-16 19:26:31

下手了。

zhangyun2743 发表于 2013-10-20 11:03:05

同问,yaw自动回漂啊

lxdsmall 发表于 2013-10-24 14:45:51

信誓旦旦的想做四轴,看来还有好多要学啊,
不懂+1

jinchenaquarius 发表于 2014-2-25 21:08:51

谢谢,学习一下

有明吗 发表于 2014-2-28 13:11:35

厉害学习了。。

茶亦爽 发表于 2014-2-28 19:05:46

感谢分享吧。

木君之上 发表于 2014-2-28 23:35:16

因为yaw还要根据电子磁罗盘修正吧,所以这个地方没有计算,你可以去其他地方找一下,应该有yaw的计算,而且是单独的计算

hz770495569 发表于 2014-3-1 16:24:47

楼主能不能发一份完整的程序?谢谢~~{:lol:}770495569@qq.com

hz770495569 发表于 2014-3-1 16:28:02

g921002 发表于 2013-5-5 09:32
IMUupdate()這個函數只針對加速規及陀螺儀資料做融合,所以真的有修正到的只有pitch(俯仰)和roll(滾轉),ya ...

您好!能不能请教下,对陀螺仪和加速度计数据融合和用这两个的数据来姿态解算有什么区别?我用卡尔曼算法把两者做数据融合得到的数据有什么用呢??看多了反而有些迷糊,谢谢~

g921002 发表于 2014-3-2 11:08:48

hz770495569 发表于 2014-3-1 16:28
您好!能不能请教下,对陀螺仪和加速度计数据融合和用这两个的数据来姿态解算有什么区别?我用卡尔曼算法 ...

看不懂你的問題。

hz770495569 发表于 2014-3-2 14:56:56

g921002 发表于 2014-3-2 11:08
看不懂你的問題。

好吧!我也觉得我问的乱七八糟的~那我想问下
      // 估计方向的重力
      vx = 2*(q1*q3 - q0*q2);
         vy = 2*(q0*q1 + q2*q3);
         vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
         
         // 错误的领域和方向传感器测量参考方向之间的交叉乘积的总和
      ex = (ay*vz - az*vy);
         ey = (az*vx - ax*vz);
         ez = (ax*vy - ay*vx);
这段代码是什么意思?根据什么公式来的吗?

硬邦邦 发表于 2014-3-2 15:00:58

可惜高等数学没学好

情迷MJ比莉珍 发表于 2014-3-7 18:35:53

好腻害的赶脚啊!!

s15200380596 发表于 2014-3-8 14:43:11

楼主,那个四元数值是怎么来的?公式?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;

空白L 发表于 2014-4-18 17:49:14

hz770495569 发表于 2014-3-2 14:56
好吧!我也觉得我问的乱七八糟的~那我想问下
      // 估计方向的重力
      vx = 2*(q1*q3 - q0*q2);


第一个知道是通过旋转矩阵来的,是重力在体坐标下的投影。第二部分的公式我也想问是怎么来的

yzb1019 发表于 2014-4-19 13:11:32

四元数欧拉角标记

yangkuan85988 发表于 2014-6-19 09:48:02

空白L 发表于 2014-4-18 17:49
第一个知道是通过旋转矩阵来的,是重力在体坐标下的投影。第二部分的公式我也想问是怎么来的 ...

   ex = (ay*vz - az*vy);
         ey = (az*vx - ax*vz);
         ez = (ax*vy - ay*vx);

第一部分公式是把重力向量在导航坐标系的投影(0,0,1)通过四元数姿态矩阵投影到载体坐标系,得到估计值(vx,vy,vz),重力向量在载体坐标系的测量值由加速度计直接输出(ax,ay,az),估计值和测量值做向量叉乘,就得上面的公式,至于为什么要做叉乘,目前正在思考中!

chaojikoushuige 发表于 2014-10-28 10:19:59

好资料谢谢楼主

feiniao007@ 发表于 2014-10-28 14:23:19

这个算法也在研究中,原理上推导确实有一定难度,看起比较涩。

love0679 发表于 2014-10-28 14:31:47

跟着学习一下

cntsw 发表于 2014-11-1 23:28:25

mark! 好文章,

nhw1234 发表于 2014-11-7 00:21:15

学习中,表示不懂

JnzGoto 发表于 2014-11-7 00:32:21

全角度欧拉角与四元数

zjzly 发表于 2014-11-7 19:56:24

你好,我想问一下9150内置DMP出来的四元数可否用来将加速度从机体坐标系转到地理坐标系?

Gosling 发表于 2014-11-7 20:12:43

ax=ax*kfa+kfan*axi;
      ay=ay*kfa+kfan*ayi;
      az=az*kfa+kfan*azi;

      gx=gx*kfg+kfgn*gxi;
      gy=gy*kfg+kfgn*gyi;
      gz=gz*kfg+kfgn*gzi;

这个是互补滤波?

chenpeng0407 发表于 2014-11-10 13:29:29

学习中{:smile:}

koko1256 发表于 2014-11-10 22:02:13

请问为什么pitch roll 数据不稳定,会不断漂移??还有,为什么有时候移动传感器,串口打印突然就停止了???请大神答疑~~·

qxc16b 发表于 2014-11-10 22:32:00

mark            

koko1256 发表于 2014-11-14 13:21:41

g921002 发表于 2013-5-5 09:32
IMUupdate()這個函數只針對加速規及陀螺儀資料做融合,所以真的有修正到的只有pitch(俯仰)和roll(滾轉),ya ...

请问这里周期采样f单位是是什么,是秒还是毫秒?我们一般选取多打f?

zhouzhen 发表于 2014-11-18 17:09:52

好贴,学习!

g921002 发表于 2014-11-21 17:57:46

koko1256 发表于 2014-11-14 13:21
请问这里周期采样f单位是是什么,是秒还是毫秒?我们一般选取多打f?

就是你執行這個IMUupdate()的周期。
比如你每20ms呼叫一次IMUupdate(),那他的周期就是0.02(second)

芽芽小宝 发表于 2014-11-21 22:38:08

继续研究

芽芽小宝 发表于 2014-11-21 22:39:05

做精品,透彻了解自己的产品

2013的弹子球 发表于 2014-12-4 20:13:01

这篇论文有详细讲。。。确实是互补滤波

2013的弹子球 发表于 2014-12-4 20:15:57

http://wenku.baidu.com/link?url=IGe6Wor_o5KSfDnsjbH0Uc-gbdunFIeVk6Bbk52HUXlbMKWzcR41Q2UQV78KVqvQGyoXCFPCJAEHqdA_sZscvlNN2zDATXmV8B7q-io05vW

GHmcu 发表于 2015-5-20 15:23:28

标记一下,谢谢!

老谷 发表于 2015-7-3 18:49:41

标记下细看

tangwei039 发表于 2015-7-3 22:11:50

我最近也做了个IMU玩玩,与楼住问题一样,动 pitch时 YAW也跟着动,停止后恢复。

而且把磁航向融合整个姿态收敛很慢。

源码是第七实验室公开(买板子送的)

* main.c file
编写者:lisn3188

编译环境:MDK-LiteVersion: 4.23
初版时间: 2012-04-25
测试: 本程序已在第七实验室的mini IMU上完成测试
功能:
姿态解算 IMU
将传感器的输出值进行姿态解算。得到目标载体的俯仰角和横滚角 和航向角
------------------------------------
*/

#include "IMU.h"

floatpitch ,roll ,yaw;
volatile float exInt, eyInt, ezInt;// 误差积分
volatile float q0, q1, q2, q3; // 全局四元数
volatile float integralFBhand,handdiff;
volatile uint32_t lastUpdate, now; // 采样周期计数 单位 us


/**************************实现函数********************************************
*函数原型:           void IMU_init(void)
*功  能:          初始化IMU相关       
                          初始化各个传感器
                          初始化四元数
                          将积分清零
                          更新系统时间
输入参数:无
输出参数:没有
*******************************************************************************/
void IMU_init(void)
{       
        int i;
        for(i=0;i<100;i++)
                Dof6_Update();
        HMC5983L_SetUp();
        now = micros();//读取时间
        lastUpdate = now;        //更新时间
        // initialize quaternion
        q0 = 1.0f;//初始化四元数
        q1 = 0.0f;
        q2 = 0.0f;
        q3 = 0.0f;
        exInt = 0.0;
        eyInt = 0.0;
        ezInt = 0.0;
}

/**************************实现函数********************************************
*函数原型:           void IMU_getValues(float * values)
*功  能:       读取加速度 陀螺仪 磁力计 的当前值
输入参数: 将结果存放的数组首地址
输出参数:没有
*******************************************************************************/
void IMU_getValues(float * values) {
        //读取加速度和陀螺仪的当前ADC
        Dof6_Update();

        values = Accel_Xint;
        values = Accel_Yint;
        values = Accel_Zint;

        values = Gyro_X;        //        角速度X轴, 单位dps [度每秒]
        values = Gyro_Y;
        values = Gyro_Z;
    HMC5983_mgetValues(&values);        //读取磁力计的ADC值
}

// Fast inverse square-root
/**************************实现函数********************************************
*函数原型:           float invSqrt(float x)
*功  能:           快速计算 1/Sqrt(x)        
输入参数: 要计算的值
输出参数: 结果
*******************************************************************************/
float invSqrt(float x) {
        float halfx = 0.5f * x;
        float y = x;
        long i = *(long*)&y;
        i = 0x5f3759df - (i>>1);
        y = *(float*)&i;
        y = y * (1.5f - (halfx * y * y));
        return y;
}

/**************************实现函数********************************************
*函数原型:           void IMU_AHRSupdate
*功  能:       更新AHRS 更新四元数
输入参数: 当前的测量值。
输出参数:没有
*******************************************************************************/
#define Kp 2.0f   // proportional gain governs rate of convergence to accelerometer/magnetometer
#define Ki 0.01f   // integral gain governs rate of convergence of gyroscope biases

void IMU_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,halfT;
float tempq0,tempq1,tempq2,tempq3;

// 先把这些用得到的值算好
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;         

now = micros();//读取时间
if(now<lastUpdate){ //定时器溢出过了。
halfT =((float)(now + (0xffff- lastUpdate)) / 2000000.0f);
}
else        {
halfT =((float)(now - lastUpdate) / 2000000.0f);
}
lastUpdate = now;        //更新时间

norm = invSqrt(ax*ax + ay*ay + az*az);      
ax = ax * norm;
ay = ay * norm;
az = az * norm;
//把加计的三维向量转成单位向量。

norm = invSqrt(mx*mx + my*my + mz*mz);         
mx = mx * norm;
my = my * norm;
mz = mz * norm;

/*
这是把四元数换算成《方向余弦矩阵》中的第三列的三个元素。
根据余弦矩阵和欧拉角的定义,地理坐标系的重力向量,转到机体坐标系,正好是这三个元素。
所以这里的vx\y\z,其实就是当前的欧拉角(即四元数)的机体坐标参照系上,换算出来的重力单位向量。
*/
// compute reference direction of flux
hx = 2*mx*(0.5f - q2q2 - q3q3) + 2*my*(q1q2 - q0q3) + 2*mz*(q1q3 + q0q2);
hy = 2*mx*(q1q2 + q0q3) + 2*my*(0.5f - q1q1 - q3q3) + 2*mz*(q2q3 - q0q1);
hz = 2*mx*(q1q3 - q0q2) + 2*my*(q2q3 + q0q1) + 2*mz*(0.5f - q1q1 - q2q2);         
bx = sqrt((hx*hx) + (hy*hy));
bz = hz;   

// estimated direction of gravity and flux (v and w)
vx = 2*(q1q3 - q0q2);
vy = 2*(q0q1 + q2q3);
vz = q0q0 - q1q1 - q2q2 + q3q3;
wx = 2*bx*(0.5f - q2q2 - q3q3) + 2*bz*(q1q3 - q0q2);
wy = 2*bx*(q1q2 - q0q3) + 2*bz*(q0q1 + q2q3);
wz = 2*bx*(q0q2 + q1q3) + 2*bz*(0.5f - q1q1 - q2q2);

// error is sum of cross product between reference direction of fields and direction measured by sensors
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);

/*
axyz是机体坐标参照系上,加速度计测出来的重力向量,也就是实际测出来的重力向量。
axyz是测量得到的重力向量,vxyz是陀螺积分后的姿态来推算出的重力向量,它们都是机体坐标参照系上的重力向量。
那它们之间的误差向量,就是陀螺积分后的姿态和加计测出来的姿态之间的误差。
向量间的误差,可以用向量叉积(也叫向量外积、叉乘)来表示,exyz就是两个重力向量的叉积。
这个叉积向量仍旧是位于机体坐标系上的,而陀螺积分误差也是在机体坐标系,而且叉积的大小与陀螺积分误差成正比,正好拿来纠正陀螺。(你可以自己拿东西想象一下)由于陀螺是对机体直接积分,所以对陀螺的纠正量会直接体现在对机体坐标系的纠正。
*/
if(ex != 0.0f && ey != 0.0f && ez != 0.0f){
exInt = exInt + ex * Ki * halfT;
eyInt = eyInt + ey * Ki * halfT;       
ezInt = ezInt + ez * Ki * halfT;

// 用叉积误差来做PI修正陀螺零偏
gx = gx + Kp*ex + exInt;
gy = gy + Kp*ey + eyInt;
gz = gz + Kp*ez + ezInt;

}

// 四元数微分方程
tempq0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
tempq1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT;
tempq2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT;
tempq3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;

// 四元数规范化
norm = invSqrt(tempq0*tempq0 + tempq1*tempq1 + tempq2*tempq2 + tempq3*tempq3);
q0 = tempq0 * norm;
q1 = tempq1 * norm;
q2 = tempq2 * norm;
q3 = tempq3 * norm;
}

/**************************实现函数********************************************
*函数原型:           void IMU_getQ(float * q)
*功  能:       更新四元数 返回当前的四元数组值
输入参数: 将要存放四元数的数组首地址
输出参数:没有
*******************************************************************************/
float mygetqval;        //用于存放传感器转换结果的数组
void IMU_getQ(float * q) {

IMU_getValues(mygetqval);       
//将陀螺仪的测量值转成弧度每秒
//加速度和磁力计保持 ADC值 不需要转换
IMU_AHRSupdate(mygetqval * M_PI/180, mygetqval * M_PI/180, mygetqval * M_PI/180,
   mygetqval, mygetqval, mygetqval, mygetqval, mygetqval, mygetqval);

q = q0; //返回当前值
q = q1;
q = q2;
q = q3;
}


/**************************实现函数********************************************
*函数原型:           void IMU_getYawPitchRoll(float * angles)
*功  能:       更新四元数 返回当前解算后的姿态数据
输入参数: 将要存放姿态角的数组首地址
输出参数:没有
*******************************************************************************/
void IMU_getYawPitchRoll(float * angles) {
float q; // 四元数
volatile float gx=0.0, gy=0.0, gz=0.0; //估计重力方向
IMU_getQ(q); //更新全局四元数

angles = -atan2(2 * q * q + 2 * q * q, -2 * q*q - 2 * q * q + 1)* 180/M_PI; // yaw
angles = -asin(-2 * q * q + 2 * q * q)* 180/M_PI; // pitch
angles = atan2(2 * q * q + 2 * q * q, -2 * q * q - 2 * q * q + 1)* 180/M_PI; // roll
if(angles<0)angles+=360.0f;//将 -+180度转成0-360度
yaw = angles;
pitch = angles;
roll = angles;
}




//------------------End of File----------------------------

小憨不傻 发表于 2015-7-6 11:31:30

s15200380596 发表于 2014-3-8 14:43
楼主,那个四元数值是怎么来的?公式?q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;         q1 = q1 + (q0* ...

这个就是四元数的微分方程,用于更新四元数用的!

fcmer2016 发表于 2016-3-28 23:44:08

这里面的XYZ轴和欧拉角对应关系是啥?以哪个轴为机头方向?

sjh306 发表于 2016-5-28 13:11:31

表示看不懂,还在努力研究中!

jagel_huang 发表于 2016-6-7 18:21:39

学习、围观了~~
{:smile:}

foxpro2005 发表于 2016-6-11 23:06:24

谢谢分享, 以后会用到, 先学习一下

AMANHE 发表于 2016-6-16 11:35:01

不错AAAAAAAAAAAA

chiying 发表于 2016-7-24 20:22:23

不知道为什么加表测量重力单位向量,与通过陀螺积分姿态角坐标转换得到的机体坐标系下的重力表示的叉积,就是陀螺积分的姿态与加表测得的角度之间的误差呢?

chiying 发表于 2016-7-24 20:23:15

tangwei039 发表于 2015-7-3 22:11
我最近也做了个IMU玩玩,与楼住问题一样,动 pitch时 YAW也跟着动,停止后恢复。

而且把磁航向融合整个姿 ...

不知道为什么加表测量重力单位向量,与通过陀螺积分姿态角坐标转换得到的机体坐标系下的重力表示的叉积,就是陀螺积分的姿态与加表测得的角度之间的误差呢?
页: [1]
查看完整版本: 关于四轴算法——四元数与欧拉角的转化