Home » Default » 多轴飞行器姿态的欧拉角算法

多轴飞行器中姿态有多种解算方式,最为常见的为四元数,欧拉角,矩阵和轴角。其中用的最多的是四元数和欧拉角,姿态解算的最核心之处在于多轴飞行器的旋转。姿态解算中使用四元数来保存飞行器的姿态,包括旋转和方位。在获得四元数之后,会将其转化为欧拉角,然后再输入到姿态控制算法中。

姿态控制算法的输入参数必须是欧拉角。其中AD值是指MPU6050陀螺仪角速度和加速度,3个维度的角速度值和3个维度的加速度值,每个值为16位精度。AD必须先转化为四元数,然后通过四元数转化为欧拉角。

使用欧拉角表示姿态,令Φ,θ和Φ代表ZYX 欧拉角,分别称为偏航角、俯仰角和横滚角 。 载体坐标系下的 加 速 度(axB,ayB,azB)和参考坐标系下的加速度(axN, ayN, azN)之间的关系可表示为(1)。其中 c 和 s 分别代表 cos 和 sin。axB,ayB,azB就是mpu读出来的三个值。

这个矩阵就是三个旋转矩阵相乘得到的,因为矩阵的乘法可以表示旋转。

欧拉角算法1

欧拉角表示姿态程序部分

void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az){  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;if(ax*ay*az==0)  return;  norm = sqrt(ax*ax + ay*ay + az*az);       //acc数据归一化  ax = ax /norm;  ay = ay / norm;  az = az / norm;  // estimated direction of gravity and flux (v and w)                vx = 2*(q1q3 - q0q2); //四元素中xyz的  vy = 2*(q0q1 + q2q3);  vz = q0q0 - q1q1 - q2q2 + q3q3 ;  // error is sum of cross product between reference direction of fields and direction measured by sensors  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;  // adjusted gyroscope measurements  gx = gx + Kp*ex + exInt;     //将误差PI后补偿到陀螺仪,即补偿零点漂移  gy = gy + Kp*ey + eyInt;  gz = gz + Kp*ez + ezInt;     //这里的gz由于没有观测者进行矫正会产生漂移,表现出来的就是积分自增或自减  // 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;  //Q_ANGLE.Yaw = atan2(2 * q1 * q2 + 2 * q0 * q3, -2 * q2*q2 - 2 * q3* q3 + 1)* 57.3; // yaw  Q_ANGLE.Y  = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch  Q_ANGLE.X = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll}

欧拉角算法2

程序解释1:

  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;

这段程序就是为了把需要用到的姿态矩阵的元素求出来给出的。

程序解释2:

  vx = 2*(q1q3 - q0q2); /  vy = 2*(q0q1 + q2q3);  vz = q0q0 - q1q1 - q2q2 + q3q3 ;

可以看到vx,vy,vz为CRb的最后一列的三项,四元数矩阵带入(1)式得vx,vy,vz分别是axB,ayB,azB每一项g前的系数。且静止情况下vx,vy,vz组成向量模长基本可以认为为1.

程序解释3:

  norm = sqrt(ax*ax + ay*ay + az*az);       //acc数据归一化  ax = ax /norm;  ay = ay / norm;  az = az / norm;

以上已说,由四元数倒推回去的加速度,向量模长为1,为了比较误差进行归1化,算的由加计得出的向量。

程序解释4:

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

接着可以通过叉乘(向量外积)计算误差

程序解释5

  exInt = exInt + ex * Ki;  eyInt = eyInt + ey * Ki;  ezInt = ezInt + ez * Ki;

对误差进行积分

程序解释6:

  gx = gx + Kp*ex + exInt;      gy = gy + Kp*ey + eyInt;  gz = gz + Kp*ez + ezInt;

进行pi滤波,其实就是互补滤波

程序解释7:

  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;

龙格库塔法。。。就是方程的数值解法。。近似解。。一阶解法 这个跟四元数的微分方程对应有兴趣的看看书。。。。

程序解释8:

 norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);  q0 = q0 / norm;  q1 = q1 / norm;  q2 = q2 / norm;  q3 = q3 / norm;

对四元数进行规范化,即化为模长为1 ,因为只有规范化的四元数才能表示刚体旋转。

程序解释9:

  Q_ANGLE.Y  = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch  Q_ANGLE.X = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll

仍旧一一对应关系发现2(q1q3 -q0q2)刚好跟欧拉角对应,由此利用自带库函数即可求得俯仰角,横滚角类似,偏航角由于没有罗盘进行校正求没有意义,控制中采用采用PD控制。

补充,由于陀螺仪会有零点漂移开始一定要进行补偿。这段是在mpu6050.c中程序,对直流偏执进行了补偿。

MPU6050_ACC_LAST.X=((((int16_t)mpu6050_buffer[0]) << 8) | mpu6050_buffer[1]) - ACC_OFFSET.X;MPU6050_ACC_LAST.Y=((((int16_t)mpu6050_buffer[2]) << 8) | mpu6050_buffer[3]) - ACC_OFFSET.Y;MPU6050_ACC_LAST.Z=((((int16_t)mpu6050_buffer[4]) << 8) | mpu6050_buffer[5]) - ACC_OFFSET.Z;MPU6050_GYRO_LAST.X=((((int16_t)mpu6050_buffer[8]) << 8) | mpu6050_buffer[9]) - GYRO_OFFSET.X;MPU6050_GYRO_LAST.Y=((((int16_t)mpu6050_buffer[10]) << 8) | mpu6050_buffer[11]) - GYRO_OFFSET.Y;MPU6050_GYRO_LAST.Z=((((int16_t)mpu6050_buffer[12]) << 8) | mpu6050_buffer[13]) - GYRO_OFFSET.Z;

这里还要说一点,这里加速计的数据用的是滑动平均值滤波法,一定要有这个。。不然由于机械振动造成的影响非常大。。。

void Prepare_Data(void){static uint8_t filter_cnt=0;int32_t temp1=0,temp2=0,temp3=0;uint8_t i;MPU6050_Read();MPU6050_Dataanl();ACC_X_BUF[filter_cnt] = MPU6050_ACC_LAST.X;ACC_Y_BUF[filter_cnt] = MPU6050_ACC_LAST.Y;ACC_Z_BUF[filter_cnt] = MPU6050_ACC_LAST.Z;for(i=0;i

欧拉角-MPU6050接线图

MPU6050脚的AD0是IIC地址,接低的时候who am i为0x68,为高的时候0x69 CPout 的电容要为22Pf才行,这个电容比较特殊,详情请见手册

标签: none

添加新评论

V