质量块在body坐标系下的坐标为:
body坐标系为imu坐标系 惯性系为世界坐标系
只考虑旋转 旋转到惯性系下:
对时间求导 如下:
其中
对 R R R的求导 有如下推导:
其中 [ w b ] × = w ∧ [w^b]_\times=w^{\wedge} [wb]×=w∧
[ w b ] × r = w b × r [w^b]_\times r =w^b\times r [wb]×r=wb×r
对坐标求二阶导 得出:
其中 R ˙ i b w b = R i b [ w b ] × w b = R i b w b × w b = 0 \dot{R}_{ib}w^b =R_{ib}[w^b]_\times w^b =R_{ib}w^b\times w^b =0 R˙ibwb=Rib[wb]×wb=Ribwb×wb=0 自身和自身的叉乘为零
imu中包含两种测量模型:加速度计和陀螺仪
加速度计用来测量加速度的大小 陀螺仪用来测量角速度的大小
这里用弹簧模型理解 实际中会使用电容器
加速度的坐标系通常为东北天坐标系:
g = ( 0 , 0 , − 9.81 ) T g = (0, 0, -9.81)^T g=(0,0,−9.81)T
静止时 加速度计测得加速度为0 重力加速度为g
自由落体时 加速度计测得加速度为g 重力加速度为0
加速度计不需要考虑科氏力的影响 因为在某一时刻科氏力会等于0 达到平衡状态
测量 a 和 v 可以求出 w
但是会受到科氏力的影响 所以会采用音叉陀螺 将科氏力抵消掉
IMU误差分为确定性误差和随机误差
确定性误差主要分为:bias和scale
bias即经常说的零偏:理论上没有外力作用时 IMU的传感器输出应为0 但实际上会出现一个偏置bias
scale可以看成实际数据与传感器输出数据之间的一个比值
以及还有xyz轴不重合的误差
常使用六面法标定加速度计和陀螺仪 不过多介绍
随机误差分为高斯白噪声和bias随机游走
狄拉克函数:当 t 1 = t 2 t_1 = t_2 t1=t2时为1 其他时刻均为0 说明了每段时间的独立性
我们认为它的导数为高斯白噪声 w w w为方差为1均值为0的白噪声
一个单轴角速度受到高斯白噪声和bias的影响:
当传感器采集信号时 认为采样时间段内信息为常数
我们无法确定随机误差的积分是否为常数 所以单独对这两种随机误差进行分别积分:
高斯白噪声的方差(这里为什么要平方? 因为这就是方差的定义 详见《矩阵分析与应用》)
我们认为:
其中:
可以得出结论:对比高斯白噪声的连续时间和离散时间的 n d [ k ] n_d[k] nd[k],高斯白噪声的连续时间和离散时间相差一个 1 Δ t \frac{1}{\sqrt{\Delta t}} \quad Δt1 其中 Δ t \Delta t Δt为传感器的采集时间(1/HZ)
bias积分部分:
协方差为:
上面都不重要
结果:
其中:
得出结论:同样这里对比的是 b d [ k ] b_d[k] bd[k] bias随机游走的噪声方差从连续时间到离散时间需要乘以一个 Δ t \sqrt{\Delta t} Δt
实际操作时 我们会使用kalibr_allan对imu进行标定 算出高斯白噪声误差和bias随机游走误差(即 σ \sigma σ)
使用ROS 生成imu数据包 再使用kalibr_allan将数据包转换为mat文件 再输入进kalibr_allan
其中b为bias随机游走误差 n为高斯白噪声
w b w^b wb为理想值 w ~ b \tilde{w}^b w~b为测量值 a同理
//delta_q = [1 , 1/2 * thetax , 1/2 * theta_y, 1/2 * theta_z]
Eigen::Quaterniond dq;
Eigen::Vector3d dtheta_half = imupose.imu_gyro * dt /2.0;
dq.w() = 1;
dq.x() = dtheta_half.x();
dq.y() = dtheta_half.y();
dq.z() = dtheta_half.z();
dq.normalize();
/// imu 动力学模型 欧拉积分
Eigen::Vector3d acc_w = Qwb * (imupose.imu_acc) + gw; // aw = Rwb * ( acc_body - acc_bias ) + gw
Qwb = Qwb * dq;
Pwb = Pwb + Vw * dt + 0.5 * dt * dt * acc_w;
Vw = Vw + acc_w * dt;
//delta_q = [1 , 1/2 * thetax , 1/2 * theta_y, 1/2 * theta_z]
Eigen::Quaterniond dq;
Eigen::Vector3d dtheta_half = (imupose.imu_gyro + imudata[i - 1].imu_gyro)/2.0 * dt /2.0;
dq.w() = 1;
dq.x() = dtheta_half.x();
dq.y() = dtheta_half.y();
dq.z() = dtheta_half.z();
dq.normalize();
/// 中值积分
Eigen::Vector3d acc_w = (Qwb * dq * imupose.imu_acc + gw + Qwb * imudata[i - 1].imu_acc + gw)/2.0;
Qwb = Qwb * dq;
Pwb = Pwb + Vw * dt + 0.5 * dt * dt * acc_w;
Vw = Vw + acc_w * dt;