首先,已MPU6050为例:
三轴加速度:
重力矢量分解(物体倾斜时,将重力分解在三维坐标系中),通过三角函数关系,得到的Z轴与X轴的角度(Roll),Z轴与X轴的角度(Pitch),这两个是绝对角度,不会因为初始化位置不同而不同!!同时无法获得Yaw角度(与Z轴平行)。
三轴角速度:
单位时间,对角速度进行积分,即可直接得出三个角度,这三个角度是相对角度,因初始化位置不同而不同。
获取代码:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4)
{
MPU_Get_Accelscope(accel_original);
MPU_Get_Gyroscope(gyro_original);
//通过加速度计算角度 => (Ax = 原始数据 / 灵敏度)2g == 16384 LSB/g : 4g == 8192 LSB/g
float ax = accel_original[0] / ACCEl_RATIO; //X轴加速度
float ay = accel_original[1] / ACCEl_RATIO; //Y轴加速度
float az = accel_original[2] / ACCEl_RATIO; //Z轴加速度
//计算俯仰角(pitch) - 绕Y轴旋转
pitch_a = atan2f(-ax, sqrtf(ay * ay + az * az)) * (180.0f / PI);
//横滚角(roll) - 绕X轴旋转
roll_a = atan2f(ay, sqrtf(ax * ax + az * az)) * (180.0f / PI);
//通过角速度计算角度 => Anglerate = ADCrate /灵敏度 250°/s == 131 LSB * s/° 500°/s == 65.5 LSB * s/°
float gx = gyro_original[0] * GYROSCOPE_RATIO ;
float gy = gyro_original[1] * GYROSCOPE_RATIO ;
float gz = gyro_original[2] * GYROSCOPE_RATIO ;
pitch_g += gy * 0.02;
roll_g += gx * 0.02;
yaw_g += gz * 0.02;
}
}
注意:
1,旋转这三个角度时,顺序非常重要,因为不同的顺序可能导致完全不同的旋转效果
2,欧拉角还存在耦合问题,也被称为“万向节锁”(当物体的Pitch角度为±90度时,Roll和Yaw就会发生耦合,导致一个自由度的丢失)。
3,但使用四元数表示姿态时,不存在万向锁问题,同时数学运算中更为稳定,并且计算效率较高,因此可以更稳定地表示物体的任意姿态。
4,除了四元数还有旋转矩阵,轴角等,其中欧拉角是最直观,最符合人类思维的,欧拉角又分为动态欧拉角(坐标系随旋转而改变)又称内旋,与静态欧拉角(世界坐标系)又称外旋。
为什么三轴角速度能获得三个角度,还要使用各种算法进行多传感器融合?
陀螺仪有噪声,会漂移,时间间隔对其影响大,同时单一使用加速度获得pitch与roll适合慢速变化,是不完美的。
加速度与磁力噪声主要集中在高频段,角速度噪声主要集中在低频段
//关于-178到+178 的PID误差计算
在PID控制中,角度的误差计算应该是最小角度差(即最短路径)。例如,从179度到-179度,实际差2度(而不是358度)。所以,在计算角度误差时,应该使用如下方法:
假设目标角度为target(度),反馈角度为feedback(度),两者都在-180~180度范围内。
计算误差:error = target - feedback
然后,将error调整到-180~180度范围内:
if (error > 180) error -= 360;
if (error < -180) error += 360;
这样,179到-179的误差计算:target=-179, feedback=179 -> error = -179-179 = -358 -> 调整:-358+360=2度。
在文档1的PID计算中,并没有看到对角度误差进行这样的调整。在Pid_Calc函数中(文档2)是直接使用reference - feedback计算误差。因此,如果角度跨越180度,会导致很大的误差值,从而引起控制问题。
所以,如果使用-180~180度的范围,必须在计算角度误差之前进行上述调整。否则,当角度跨越180度时,控制会出现问题。
另一种方案是使用0~360度的范围,同样需要处理跨越0度的情况。例如,从1度到359度,实际差2度(而不是-358度)。处理方式类似:error = target - feedback
if (error > 180) error -= 360;
if (error < -180) error += 360;