IMU的轨迹解算和航迹显示

基于ros操作系统,调用IMU数据包,利用数据解算小车运动的轨迹,并在rviz中实现轨迹的可视化。其中IMU四元数对于位移速度和加速度的转换。

轨迹解算和换机显示的代码:

//IMU航迹推算
#include <ros/ros.h>
#include <sensor_msgs/Imu.h>
#include <tf/transform_datatypes.h>
#include <tf/tf.h>//关于坐标系解算的一个消息库
#include "nav_msgs/Path.h"
#include "ctime"

using namespace std;

int imuReceivedNumber = 0;

//时间戳
double time_k, time_k_1, dt;
//重力加速度
const tf::Vector3 g(0,0,9.81);

tf::Vector3 acc_b_k, acc_b_k_1;
tf::Vector3 w_b_k, w_b_k_1;

//k+1时刻的线加速度,经过旋转及中值近似后
tf::Vector3 acc_k_1;
//k+1时刻的角速度,经过旋转及中值近似后
tf::Vector3 w_k_1;
//k及k+1时刻的速度
tf::Vector3 velo_k, velo_k_1;
//k及k+1时刻的位置
tf::Vector3 position_k, position_k_1;
//k及k+1时刻的姿态,用四元数来表示
tf::Quaternion q_k,q_k_1;

ros::Publisher pubdatadisplay;
nav_msgs::Path path;
//接受位置,实现可视化,并发布
void pubPathmsg(tf::Vector3 position_, tf::Quaternion quaternion_){
    geometry_msgs::PoseStamped display_imu;
    display_imu.header.stamp = ros::Time::now();
    display_imu.header.frame_id = "display";

    display_imu.pose.position.x = position_.getX();
    display_imu.pose.position.y = position_.getY();
    display_imu.pose.position.z = position_.getZ();

    geometry_msgs::Quaternion q_msgs;
    q_msgs.x = quaternion_.getX();
    q_msgs.y = quaternion_.getY();
    q_msgs.z = quaternion_.getZ();
    q_msgs.w = quaternion_.getW();
    display_imu.pose.orientation = q_msgs;

    path.poses.push_back(display_imu);
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "display";
    pubdatadisplay.publish(path);
}

//接受imu消息,并对消息进行解算处理,得到推算航迹需要用到的信息
void imuHandler(const sensor_msgs::Imu::ConstPtr &imuIn){
    if(imuReceivedNumber == 0){
        acc_b_k[0] = imuIn->linear_acceleration.x;
        acc_b_k[1] = imuIn->linear_acceleration.y;
        acc_b_k[2] = imuIn->linear_acceleration.z;

        w_b_k[0] = imuIn->angular_velocity.x;
        w_b_k[1] = imuIn->angular_velocity.y;
        w_b_k[2] = imuIn->angular_velocity.z;

        time_k = imuIn->header.stamp.toSec();

        velo_k[0] = 0;
        velo_k[1] = 0;
        velo_k[2] = 0;

        position_k[0] = 0;
        position_k[1] = 0;
        position_k[2] = 0;

        q_k.setX(0);
        q_k.setY(0);
        q_k.setZ(0);
        q_k.setW(1);

        pubPathmsg(position_k, q_k);//接受k时刻IMU的消息
        imuReceivedNumber++;
    }else if(imuReceivedNumber == 1){
        acc_b_k_1[0] = imuIn->linear_acceleration.x;
        acc_b_k_1[1] = imuIn->linear_acceleration.y;
        acc_b_k_1[2] = imuIn->linear_acceleration.z;

        w_b_k_1[0] = imuIn->angular_velocity.x;
        w_b_k_1[1] = imuIn->angular_velocity.y;
        w_b_k_1[2] = imuIn->angular_velocity.z;

        time_k_1 = imuIn->header.stamp.toSec();

        dt = time_k_1 - time_k;

        w_k_1 = (w_b_k + w_b_k_1) / 2;
        tf::Quaternion dw;//姿态信息

        dw.setX(w_k_1[0] * dt);
        dw.setX(w_k_1[1] * dt);
        dw.setZ(w_k_1[2] * dt);
        dw.setW(1);//接收k+1时刻IMU的消息
//主要用了中值法来估计求得
        //求姿态
        q_k_1 = q_k * dw;
//求加速度时也需要知道姿态的信息
        //求加速度
        tf::Vector3 acc_b_k_r = acc_b_k.rotate(q_k.getAxis(), q_k.getAngle());
        tf::Vector3 acc_b_k_1_r = acc_b_k_1.rotate(q_k_1.getAxis(), q_k_1.getAngle());
        acc_k_1 = (acc_b_k_r - g + acc_b_k_1_r - g) / 2;

        //求位置,用的加速度平均值
    position_k_1 = position_k + velo_k * dt + (acc_k_1 * dt) * (acc_k_1 * dt) / 2;

    //求速度,同样用加速度平均值
    velo_k_1 = velo_k + acc_k_1 * dt;
        
//调用上面的可视化发布函数
    pubPathmsg(position_k_1, q_k_1);
//将k=1时刻的值变成下一个k时刻
    w_b_k_1 = w_b_k;
    acc_b_k = acc_b_k_1;
    time_k = time_k_1;
    q_k = q_k_1;
    position_k = position_k_1;
    velo_k = velo_k_1;
    cout << "dt: " << dt << " x: " << position_k_1[0] << " y: " << position_k_1[1] << " z: " << position_k_1[2] << endl;
}
}
//初始化节点并执行上面的回调函数
    int main(int argc, char **argv){
    ros::init(argc, argv, "scanRegistration");
    ros::NodeHandle nh;

    ros:: Subscriber subImu = nh.subscribe<sensor_msgs::Imu>("/imu/data_raw", 50, imuHandler);

    pubdatadisplay = nh.advertise<nav_msgs::Path>("/display", 100);

    ros::spin();

    return 0;
}

代码中有IMU的坐标变化,同时利用四元数求得加速度、速度和位移,其中平均加速度存在估计的成分。在每个时间步长循环中,体现了微积分估计的思想。关于四元数的理解和定义可以参考这一篇文章:

可视化理解四元数,愿你不再掉头发 - 知乎 (zhihu.com)

  • 2
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
基于扩展卡尔曼滤波的IMU轨迹是一种常用的方法,用于融合惯性测量单元(IMU)的数据以估计物体的姿态和位置。扩展卡尔曼滤波(EKF)是一种递归滤波器,可以在非线性系统中进行状态估计。 在IMU轨迹中,通常使用三个加速度计和三个陀螺仪来测量物体在三个轴上的线性加速度和角速度。这些测量值会受到噪声和漂移的影响,因此需要进行滤波和校正。 基于EKF的IMU轨迹的主要步骤如下: 1. 初始化状态:初始时,需要估计物体的初始位置、速度和姿态,并设置协方差矩阵。 2. 预测步骤:根据上一时刻的状态估计和控制输入(如加速度、角速度),使用运动模型进行状态的预测,并更新协方差矩阵。 3. 测量更新步骤:根据当前时刻的IMU测量值,使用观测模型将预测的状态映射到测量空间,并计预测测量值。然后,将实际测量值与预测测量值进行比较,得到测量残差。根据测量残差和协方差矩阵,使用卡尔曼增益来更新状态估计和协方差矩阵。 4. 重复步骤2和步骤3,直到达到所需的精度或满足停止条件。 通过不断迭代预测和更新步骤,基于扩展卡尔曼滤波的IMU轨迹可以提供相对准确的物体姿态和位置估计。然而,由于IMU存在漂移等问题,长时间的轨迹估计可能会积累误差。因此,在实际应用中,通常会结合其他传感器(如GPS)或使用视觉里程计等方法来进一步提高轨迹的准确性。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值