对IMU数据进行卡尔曼滤波

 我们要使用IMU数据,必须对数据进行预处理,卡尔曼滤波就是很好的方式。

对IMU数据进行卡尔曼滤波

1.卡尔曼滤波

卡尔曼滤波(Kalman filtering)是一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的算法。由于观测数据中包括系统中的噪声和干扰的影响,所以最优估计也可看作是滤波过程。

其原理可以参考b站的视频:

从放弃到精通!卡尔曼滤波从理论到实践~_哔哩哔哩_bilibili

2.代码实现

#include 
#include 
#include "sensor_msgs/Imu.h"
#include "Eigen/Dense"

double a_x; //x方向的加速度
double a_y; //y方向的加速度
double a_z; //z方向的加速度

Eigen::MatrixXd X = Eigen::MatrixXd(3,1); //创建一个3*1矩阵

using namespace std;

class kalman_filter
{
private:
    Eigen::MatrixXd A; //系统状态矩阵
    Eigen::MatrixXd P; //协方差
    Eigen::MatrixXd Q; //测量过程噪音(预测)
    Eigen::MatrixXd R; //真实传感器噪音
    Eigen::MatrixXd H; //测量矩阵

    bool isinitized = false; //判断是否进行了初始化

public:
    kalman_filter();
    Eigen::MatrixXd predictAndupdate( Eigen::MatrixXd x,Eigen::MatrixXd z);
    ~kalman_filter();
};

Eigen::MatrixXd kalman_filter::predictAndupdate(Eigen::MatrixXd x,Eigen::MatrixXd z)
{
    if(!isinitized)
    {
        P = Eigen::MatrixXd(3,3); //协方差 3*3矩阵
        P<< 1,0,0,
            0,1,0,
            0,0,1; //协方差的初始化
        isinitized=true;
    }
    x = A*x; // 状态一步预测方程
    P = A*P*(A.transpose())+Q; //一步预测协方差阵
    Eigen::MatrixXd  K = P*(H.transpose())*((H*P*(H.transpose())+R).inverse()); //kalman增益
    x = x+K*(z-H*x); //状态更新:
    int x_size = x.size();
    Eigen::MatrixXd I = Eigen::MatrixXd::Identity(x_size, x_size);
    P = (I-K*H)*P; // 协方差阵更新:
    return x;
}

kalman_filter::kalman_filter()
{
//参数初始化设置
    A=Eigen::MatrixXd(3,3); //系统状态矩阵
    A<< 1,0,0,
        0,1,0,
        0,0,1;
    H=Eigen::MatrixXd(3,3); //测量矩阵
    H<< 1,0,0,
        0,1,0,
        0,0,1;
    Q=Eigen::MatrixXd(3,3); //(预测)过程噪音
    Q<< 0.03,0,0,
        0,0.03,0,
        0,0,0.03;
    R=Eigen::MatrixXd(3,3); //真实传感器噪音
    R<<3.65,0,0,            //R太大,卡尔曼滤波响应会变慢
       0,3.65,0,
       0,0,3.65;     
}

kalman_filter::~kalman_filter(){}
//订阅发布者主要订阅imu信息并调用前面的卡尔曼滤波处理后再发布信息
class SubscribeAndPublish
{
public:
    SubscribeAndPublish()
    {
        imu_info_sub = n.subscribe("/imu/data_raw", 10, &SubscribeAndPublish::imuInfoCallback,this);
        IMU_kalman_pub = n.advertise("/imu_kalman", 10);
    }
    void imuInfoCallback(const sensor_msgs::Imu::ConstPtr& msg)
    {
        // 第一次将接收到的消息打印出来
        if(first)
        {
            // 三个方向的线性加速度
            double a_x_m = msg->linear_acceleration.x;
            double a_y_m = msg->linear_acceleration.y;
            double a_z_m = msg->linear_acceleration.z;
            // 用X存第一帧三个方向的线性加速度
            X<header;
            IMU_kalman_pub.publish(M);
            first=false;
            cout<< "first farm"<linear_acceleration.x;
            double a_y_m = msg->linear_acceleration.y;
            double a_z_m = msg->linear_acceleration.z;
            Eigen::MatrixXd z;
            z = Eigen::MatrixXd(3,1);
            z<header;
            cout<< "linear_acceleration.x = " << a_x <<"linear_acceleration.y = " << a_y <<"linear_acceleration.z = " << a_z << endl;
            IMU_kalman_pub.publish(M);
        }
    }
private:
    ros::NodeHandle n;
    ros::Publisher IMU_kalman_pub;
    ros::Subscriber imu_info_sub;
    bool first=true;
};
//接收IMU话题,通过卡尔曼滤波参数进行数据处理,然后发布处理后的数据作为一个话题。
int main(int argc, char **argv)
{
    ros::init(argc, argv, "subscribe_and_publish");

    SubscribeAndPublish SAPObject;

    ros::spin();
    return 0;
}

获得发布后的数据后,需要对于数据作图处理,ros中的作图工具不是很好,可以通过录制bag包的方式,再将.bag文件转为.csv的格式通过命令:rostopic echo -b -p > .csv

该代码用的最基础卡尔曼滤波算法,且没有进行调参。MATLAB/simulink中自带有封装好了的卡尔曼滤波代码,通过ros/tool工具可以直接接收IMU的信息,用MATLAB内置滤波器实现滤波。

3.matlab内置滤波器

将主机和车载ros系统连接在同一个局域网下,用ip地址对二者进行连接。可以通过MATLAB自带的demo,选取需要发布的信息。

下载MATLAB-control库,找到建立好的卡尔曼滤波器的simulink模块,将输入端与imu接口连接,后面的可视化模块就能显示滤波后的效果。

模块和效果图如下:

对IMU数据进行卡尔曼滤波

对IMU数据进行卡尔曼滤波

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://www.net2asp.com/cae5d19f00.html