5iMX宗旨:分享遥控模型兴趣爱好

5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)
楼主: dongfang
打印 上一主题 下一主题

开源!我的捷联系统的四元数法姿态算法和程序

[复制链接]
41
 楼主| 发表于 2011-6-29 20:46 | 只看该作者
你说的乱蹦,我估计是电磁干扰引起的,建议做些简单的滤波。

我那个算法在我的板子上倒是很乖,静态时漂移和原来的积分算法区别不大。回头看看你的算法表现如何。

欢迎继续阅读楼主其他信息

42
 楼主| 发表于 2011-10-16 22:34 | 只看该作者
正好有人PM问我,CLAMP是什么,实际上就是一个限定范围的macro了,定义如下:

#define CLAMP(x , min , max) ((x) > (max) ? (max) : ((x) < (min) ? (min) : x))
43
发表于 2011-10-16 23:58 | 只看该作者
这个算法可以应用到炒股上

动态调整4种投资组合,完成给定固定收益率曲线(航线)条件的方法
44
发表于 2011-10-17 00:15 | 只看该作者
学习了啊啊啊啊
45
发表于 2011-10-17 00:24 | 只看该作者
楼主诈尸了自挖自坟啊,仔细看了看,发现和我用的不太一样。
我是用一阶龙库算法更新四元数的,感觉楼主这个过程有点象旋转矢量法,不过我没仔细看过旋转矢量法,不知道是不是。
也象我最近想用来解决姿态控制的的误差四元数。。。
46
发表于 2011-10-17 19:18 | 只看该作者
:em15:
47
 楼主| 发表于 2011-10-17 21:16 | 只看该作者
已经好久没有更新姿态算法了,算是跳过了跳过姿态,去研究控制和航线了。

前一阵子在玩X-PLANE时,发现了PID算法中,I的实际意义: 参数I乘以误差积分值,等于系统稳定时,需要的控制量。比如通过控制油门来控制飞行速度的PID模型:
1. 误差=预期速度-实际速度。
2. 误差积分=误差的积分(自算法一开始算起,到目前)
3.误差积分*参数I,在理想的情况下,接近于达到该飞行速度的理想油门量。比如用50%的油门,可以得到稳定的30km/h速度,那如果目标速度是30km/h,误差积分*参数I=50%

参数I是一个非常难调节的部分,调小了,就和没有I控制差不多,调大了,控制会剧烈抖动。得到了I的含义的后,处理方法就简单了,预先算出一条控制量和控制效果的曲线,比如舵机控制量和飞行速度曲线,代入PD算法,然后就可以把I扔了。
48
发表于 2011-10-18 09:48 | 只看该作者
中毒了,受不了了,冲动呀。

马上去买个ATOM或者二手小本本,搞飞控。:em24:

感谢楼主分享快乐。
49
发表于 2011-10-18 12:18 | 只看该作者
算法必须定点化,否则AVR可跑不动
50
发表于 2011-10-26 15:13 | 只看该作者

四元数微分方程求解

四元数微分方程有四个,怎么求解啊?
51
发表于 2011-10-26 15:15 | 只看该作者
你的捷联算法很特别,与解微分方程相比,哪一个精度高?
52
发表于 2011-10-26 15:30 | 只看该作者
各位朋友,我是新手请多多指教,用龙格库塔法解四元数的微分方程怎么解啊?
53
发表于 2011-10-26 17:14 | 只看该作者
dstdx72先生,把你的四元数微分方程贴出来,让大家见识见识吧。
54
 楼主| 发表于 2011-10-26 17:22 | 只看该作者
四阶龙格-库塔法,如http://wenku.baidu.com/view/9721 ... 9.html?from=related

我看过,但没看懂,问题在于它里面用了矢量相乘还是矩阵相乘,所以公式上虽然简单,但转换为实际算法,我不行。

但我现在找到的4元数算法,90%的可能就是四阶龙格-库塔法的实现。至于是不是,要请使用四阶龙格-库塔法的其他TX晒一下代码,比较一下才能知道了。
55
发表于 2012-1-16 14:02 | 只看该作者
dongfang
你的程序中没用加速度去修正陀螺仪误差,即使用四元数,可能运行一会下来误差比较大吧
56
发表于 2012-1-16 15:16 | 只看该作者
:em26:   对于技术人才必须干的事情是 顶顶顶
57
发表于 2012-1-16 17:57 | 只看该作者
学习了
58
发表于 2012-1-28 02:36 | 只看该作者
最近有时间也玩一下姿态解算。楼主看下我的理解正确么
Quaternion nowQ;                    //获得原始姿态的四元数  [a]
void loop() {                       //进入循环
  int intx, inty,intz;
  float  pitch,roll,yaw;

  gyro.ReadGyroOutCalibrated_Radian(&pitch, &roll, &yaw);   //读取陀螺输出。并且校准(弧度)

  EulerAngle dt;                                     //获得dt。就是采样刷新time
  dt.fRoll=roll;                                     //计算roll的变化量 (gyrox*dt)
  dt.fPitch=pitch;                                     //计算pitch的变化量(gyroy*dt)
  dt.fYaw=-yaw;                                        //计算yaw的变化量(有反向,和安装方向有关)(gyroz*dt)

  Quaternion dQ;                                        //计算当前姿态的四元数
  dQ.FromEulerAngle(dt);                                //把dt的欧拉转换为四元数   
  nowQ=nowQ.Multiply(dQ);                                //做四元数的乘法运算,得到新的四元数(nowQ=nowQ*dQ(是dt转换得到))[a=a*b]


  count++;                                              //计数器++
  if (count>1000){                                       //如果count大于1000则将nowQ四元转换为欧拉角
    EulerAngle nowG=nowQ.ToEulerAngle();

    Serial.print(nowG.fRoll/3.1415926535*180,11);//横滚
    Serial.print(",");                                            //将弧度转换为度,串口输出
    Serial.print(nowG.fPitch/3.1415926535*180,11);//俯仰
    Serial.print(",");
    Serial.print(nowG.fYaw/3.1415926535*180,11);//偏航
    Serial.print(",");
    Serial.print(nowQ.getS(),11);//偏航
    Serial.println();
    count=0;
  }
}
有点迷惑的是这里:
Quaternion dQ;                                        //计算当前姿态的四元数
  dQ.FromEulerAngle(dt);                                //把dt的欧拉转换为四元数   
既然后面做四元乘法用的是a=a*b。那Quaternion dQ;       //计算当前姿态的四元数
有什么用呢。
后面的计算就是将上一次的nowq作为原始姿态和更新的dt做乘法。这样就用三轴陀螺计算出姿态,如果要做acc的融合的话就另说了。
找到了一个算法:
//=====================================================================================================
// IMU.c
// S.O.H. Madgwick
// 25th September 2010
//=====================================================================================================
// Description:
//
// Quaternion implementation of the 'DCM filter' [Mayhony et al].
//
// User must define 'halfT' as the (sample period / 2), and the filter gains 'Kp' and 'Ki'.
//
// Global variables 'q0', 'q1', 'q2', 'q3' are the quaternion elements representing the estimated
// orientation.  See my report for an overview of the use of quaternions in this application.
//
// User must call 'IMUupdate()' every sample period and parse calibrated gyroscope ('gx', 'gy', 'gz')
// and accelerometer ('ax', 'ay', 'ay') data.  Gyroscope units are radians/second, accelerometer
// units are irrelevant as the vector is normalised.
//
//=====================================================================================================

//----------------------------------------------------------------------------------------------------
// Header files

#include "IMU.h"
#include <math.h>

//----------------------------------------------------------------------------------------------------
// Definitions

#define Kp 2.0f                        // proportional gain governs rate of convergence to accelerometer/magnetometer
#define Ki 0.005f                // integral gain governs rate of convergence of gyroscope biases
#define halfT 0.5f                // half the sample period

//---------------------------------------------------------------------------------------------------
// Variable definitions

float q0 = 1, q1 = 0, q2 = 0, q3 = 0;        // quaternion elements representing the estimated orientation
float exInt = 0, eyInt = 0, ezInt = 0;        // scaled integral error

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

void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az) {
        float norm;
        float vx, vy, vz;
        float ex, ey, ez;         
       
        // normalise the measurements
        norm = sqrt(ax*ax + ay*ay + az*az);      
        ax = ax / norm;
        ay = ay / norm;
        az = az / norm;      
       
        // estimated direction of gravity
        vx = 2*(q1*q3 - q0*q2);
        vy = 2*(q0*q1 + q2*q3);
        vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
       
        // error is sum of cross product between reference direction of field and direction measured by sensor
        ex = (ay*vz - az*vy);
        ey = (az*vx - ax*vz);
        ez = (ax*vy - ay*vx);
       
        // integral error scaled integral gain
        exInt = exInt + ex*Ki;
        eyInt = eyInt + ey*Ki;
        ezInt = ezInt + ez*Ki;
       
        // adjusted gyroscope measurements
        gx = gx + Kp*ex + exInt;
        gy = gy + Kp*ey + eyInt;
        gz = gz + Kp*ez + ezInt;
       
        // integrate quaternion rate and normalise
        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;  
       
        // normalise quaternion
        norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
        q0 = q0 / norm;
        q1 = q1 / norm;
        q2 = q2 / norm;
        q3 = q3 / norm;
}

//====================================================================================================
// END OF CODE
//====================================================================================================
这个四元貌似有acc的融合功能???请指教,谢谢

[ 本帖最后由 峰回路转 于 2012-1-28 02:38 编辑 ]
59
发表于 2012-1-28 07:38 | 只看该作者
楼主没有考虑线加速度对角速度的影响吧?
60
 楼主| 发表于 2012-1-28 10:51 | 只看该作者
原帖由 峰回路转 于 2012-1-28 02:36 发表
最近有时间也玩一下姿态解算。楼主看下我的理解正确么
Quaternion nowQ;                    //获得原始姿态的四元数  [a]
void loop() {                       //进入循环
  int intx, inty,intz;
  float  pi ...


你好,Quaternion dQ,也就是a=a*b中的那个b,是自上一个姿态计算后,发生旋转(增量delta)的角度,可以从角速度读数乘以增量时间得到dt(这里的dt不是时间,是增量角度),再转换成四元数得到。

你的那段带ACC融合的代码看上去不错,但肯定不是标准的四元数算法,因为没看到三角函数,有机会我试一试。
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

关闭

【站内推荐】上一条 /1 下一条

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