状态估计算法-卡尔曼滤波用于陀螺仪加速度计数据融合

状态估计算法-卡尔曼滤波用于陀螺仪加速度计数据融合

image

附赠自动驾驶学习资料和量产经验:链接

在许多姿态估计和导航应用中,陀螺仪和加速度计是两个常用的传感器。然而,单独使用它们可能会受到各种噪声和误差的影响。为了获得更准确和稳定的姿态信息,通常会将两者的数据进行融合。我们将使用史上最经典状态估计算法,也就是卡尔曼滤波来来解决相同的问题,我们将从原理、系统模型到C代码实现全过程讲解,让你一篇文章就搞懂如何实战卡尔曼滤波算法。

卡尔曼滤波算法

算法思想

当我们想要通过传感器的测量获取物体的状态(比如位置、速度或者角度)时,常常会遇到各种问题,比如传感器的误差、噪声等。这些问题会导致我们得到的数据不够准确或者不稳定。卡尔曼滤波的思想很简单,它不只是单纯地采用传感器提供的数据,还结合了我们对物体运动规律的认识或者经验。比如,如果我们知道物体的在做匀速运动,那么即使传感器提供的速度数据有问题,但是我们任然也可以通过这个运动规律来修正它。

让我们来想象一个常见的情景:

image

开车定位

假设你正在开车匀速直线行驶,我们可以通过车上的GPS系统来获取车的位置。但是由于GPS系统不够准确,你可能会得到一些不太可信的位置信息。这时候,你就可以使用卡尔曼滤波来纠正这些位置估计的错误。

卡尔曼滤波会首先根据你的车速和方向,预测你在下一个时刻的位置。然后,当GPS系统提供新的位置信息时,卡尔曼滤波会将这个观测值与预测值进行比较。如果观测值与预测值相符,那么卡尔曼滤波就会相信GPS系统提供的位置信息;但如果观测值与预测值有很大的偏差,那么卡尔曼滤波就会调整你的位置估计,使之更接近实际情况。

通过不断地重复这个过程,卡尔曼滤波可以逐渐提高对你的位置的准确度,即使GPS系统偶尔出错。这样,你就能更可靠地了解自己的位置,从而更安全地行驶。

算法步骤

卡尔曼滤波通过两个重要的步骤来实现:预测更新,这个实现步骤和算法思想是息息相关的。

image

算法步骤

预测:

  1. 状态预测:

image

状态预测

2. 协方差预测:

image

协方差预测

在预测步骤中,我们根据系统模型(由状态转移矩阵 F 和控制输入矩阵 B 描述)来预测下一个状态的值,并且根据过程噪声的协方差矩阵 Q 来估计预测的不确定性。

更新:

3. 计算卡尔曼增益:

image

增益计算

4. 更新状态估计:

image

更新状态估计

5. 更新协方差:

image

更新协方差矩阵

在更新步骤中,我们将预测的状态值与实际观测值进行比较,根据观测噪声的协方差矩阵 R 来估计观测值的不确定性,并计算出一个卡尔曼增益,用来权衡预测值和观测值。最后,我们使用卡尔曼增益来更新状态的估计值和协方差矩阵,以获得更准确的状态估计值。

总的来说,卡尔曼滤波通过动态地结合系统模型和观测值,以及它们的不确定性信息,来得到对系统状态更准确的估计。这使得卡尔曼滤波在处理带有噪声的测量数据时能够提供更可靠的估计结果。

总结一下,首先利用系统的模型,基于上一次的最优结果来预测当前状态值,然后结合观测数据来进一步修正当前状态值,从而得到这一次最优结果值。

Q和R取值的意义

矩阵 Q 表示系统模型的误差的协方差,即在预测步骤中,我们对状态的预测有多不确定。一般来说,Q 的值越小,表示我们对系统模型的信任度越高,即我们认为系统的动态规律是比较可靠的,预测的结果也就更加可信。

如果系统的动态变化比较缓慢,那么 Q 的值可以设置得比较小;如果系统的动态变化很快,那么 Q 的值可能需要设置得比较大,以反映出系统的不确定性。通常情况下,Q 的取值是根据经验或者系统特性进行调整的。

矩阵 R 表示观测误差的协方差,即在更新步骤中,我们对观测值的信任程度。R 的取值大小取决于传感器的精度和环境噪声等因素。一般来说,R 的值越小,表示我们对观测值的信任度越高,即我们认为传感器的测量结果是比较可靠的,更新的结果也就更加可信。

如果传感器的精度很高,环境噪声很小,那么 R 的值可以设置得比较小;如果传感器存在较大的测量误差,或者环境噪声比较大,那么 R 的值可能需要设置得比较大,以反映出观测值的不确定性。同样,R 的取值通常是需要根据实际情况进行调整的。

陀螺仪加速度计滤波角度估计

要得到平衡车的倾斜角度,其实就是传感器绕着平行于轮轴的轴旋转的角度。这里我们以此陀螺仪旋转轴的角速度newGyro输出作为系统输入u,我们知道对角度积分能得到角度值,利用这个先验模型来预测更新系统状态。然后把加速度计估计重力加速度在物体局部坐标系下的投影反正切计算得到角度值作为观测值。这样我们就可以利用卡尔曼算法来得到更准确的角度估计。

下面我们就按照上面讲到的算法步骤按部就班来实现:

1.预测当前角度

我们知道,对角速度积分是旋转角度,于是有:

image

其中angle为绕轴旋转角度,bias表示角速度偏差值。newGyro是陀螺仪旋转轴的角速度值,这里作为系统输入。dt为传感器采样时间,比如0.01秒。

定义系统状态向量为:

image

那么系统的状态模型可以写成如下矩阵形式:

image

我们可以通过 上面公式来预测当前角度。

2.预测协方差矩阵

由协方差方程

image

其中由上面系统模型可知,

image

定义系统过程协方差噪声

image

image

注意,前面讲到,Q_angle和Q_bias是常数,表征角度值和角速度值的误差方差不确定性,具体可以有经验整定出来。

将Q和F代入公式有:

image

展开公式有:

image

image

image

image

3.测量方程

系统测量方差:

image

Zk是实际测量值,我们这里是加速度计算出来的角度值。H是测量系数矩阵,表示测量值与状态量xk的转换关系的,Vk是测量噪声。

其中H=[1 0] .因为测量值是角度,与角速度偏差bias无关,所以H第二项是0。

设加速度计角度计算值为newAngle,那么Zk=newAngle。

4.计算卡尔曼增益K

根据上面,

image

定义R=R_measure,为常数,表示角速度计角度的测量方差。因为观测只有一个数据,所以R是1*1矩阵。

所以代入R,P,H矩阵,可以得到:

image

image

K为2*1列向量,k0为第一项,k2为第二项。

5.更新状态估计

由更新状态估计公式可得:

image

展开矩阵:

image

image

6.更新协方差矩阵

根据上面公式,可得:

image

展开矩阵可得:

image

C代码实现

下面我们把上述过程转成C代码实现:

#include <stdio.h>

// 状态向量
typedef struct {
    float angle;  // 姿态角度
    float bias;   // 角速度偏差
} State;

// 卡尔曼滤波器结构
typedef struct {
    State state;  // 状态
    float P[2][2]; // 协方差矩阵
    float Q_angle; // 过程噪声协方差
    float Q_bias;
    float R_measure; // 观测噪声协方差
    float dt; // 时间步长
} KalmanFilter;

// 初始化滤波器
void kalman_init(KalmanFilter *kf, float Q_angle, float Q_bias, 
                 float R_measure, float dt) {
    kf->state.angle = 0.0;
    kf->state.bias = 0.0;
    kf->P[0][0] = 0.0;
    kf->P[0][1] = 0.0;
    kf->P[1][0] = 0.0;
    kf->P[1][1] = 0.0;
    kf->Q_angle = Q_angle;
    kf->Q_bias = Q_bias;
    kf->R_measure = R_measure;
    kf->dt = dt;
}

// 卡尔曼滤波算法
float kalman_filter(KalmanFilter *kf, float new_angle, float new_Gyro) {
    // 预测
    //先验估计
    kf->state.angle += kf->dt * (new_Gyro - kf->state.bias);
    //协方差估计
    kf->P[0][0] += kf->dt * (kf->dt*kf->P[1][1] - kf->P[0][1]
                             + kf->P[1][0] )+ kf->Q_angle;
    kf->P[0][1] -= kf->dt * kf->P[1][1];
    kf->P[1][0] -= kf->dt * kf->P[1][1];
    kf->P[1][1] += kf->Q_bias;

    // 更新
  	//角度差
    float y = new_angle - kf->state.angle;
    //K增益矩阵计算
    float S = kf->P[0][0] + kf->R_measure;
    float K[2];
    K[0] = kf->P[0][0] / S;
    K[1] = kf->P[1][0] / S;
    //后验状态更新
    kf->state.angle += K[0] * y;
    kf->state.bias += K[1] * y;
    //后验协方差误差更新
    kf->P[0][0] -= K[0] * kf->P[0][0];
    kf->P[0][1] -= K[0] * kf->P[0][1];
    kf->P[1][0] -= K[1] * kf->P[0][0];
    kf->P[1][1] -= K[1] * kf->P[0][1];

    return kf->state.angle;
}

int main() {
    // 设置卡尔曼滤波器参数
    float Q_angle = 0.00005;
    float Q_bias = 0.00015;
    float R_measure = 0.5;
    float dt = 0.005;//传感器实际采样频率

    KalmanFilter kf;
    kalman_init(&kf, Q_angle, Q_bias, R_measure, dt);

    // 陀螺仪和加速度计数据
    float gyro_data = 0.1;  // 陀螺仪数据,通过I2C读取
    float accel_data = 0.0; // 加速度计数据,通过I2C读取

    float angle = kalman_filter(&kf, accel_data, gyro_data);
    printf("Filtered Angle: %.2f\n", angle);

    return 0;
}

通过调节超参数取值到Q_angle = 0.00005,Q_bias = 0.00015,R_measure = 0.5时,滤波效果比较不错。如下图:

image

融合效果

我们将小车静置桌面下测得的实际效果数据。图中白色线是陀螺仪先验估计角度,黄色线是加速度计测量计算得到角度数据,而红色线是卡尔曼滤波融合之后的数据,红色线完美抑制了白线的漂移,同时滤掉了黄色加速度数据的毛刺,效果非常完美!

  • 24
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
卡尔曼滤波算法是一种常用于融合多个传感器数据的方法。在融合加速度计陀螺仪数据时,可以将加速度计数据作为观测量,将陀螺仪数据作为状态量,然后利用卡尔曼滤波算法进行融合。 具体步骤如下: 1. 定义状态量和观测量 在这种情况下,状态量可以定义为三维旋转向量,表示设备的旋转状态;观测量可以定义为三维向量,表示设备在三个轴上的加速度。 2. 定义状态转移矩阵和观测矩阵 状态转移矩阵描述了状态量如何随时间演变,观测矩阵描述了观测量和状态量之间的关系。在这种情况下,状态转移矩阵可以根据陀螺仪的输出计算得到,观测矩阵可以根据加速度计的输出计算得到。 3. 定义过程噪声和观测噪声 过程噪声和观测噪声分别表示状态转移矩阵和观测矩阵中的不确定性。可以通过实验或者经验确定它们的大小。 4. 初始化状态量和协方差矩阵 状态量和协方差矩阵的初始值可以通过设置为0或者根据实验数据估计得到。 5. 利用卡尔曼滤波算法进行融合 在每个时间步中,根据陀螺仪的输出更新状态量和协方差矩阵,然后根据加速度计的输出进行观测,利用卡尔曼滤波算法进行融合,得到最终的旋转状态。 需要注意的是,卡尔曼滤波算法的性能受到多方面因素的影响,例如传感器的精度、采样率、滤波器参数等。在实际应用中需要根据具体情况进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值