文章目录

  • 惯性卫星组合模型
  • 四元数与欧拉角之间的协方差阵转换 - 理论
  • 四元数与欧拉角之间的协方差阵转换 - 代码
  • 姿态四元数的初始协方差阵设置
  • 参考

本篇博客主要是记录自己的一些思考:在惯性卫星组合导航系统中,如果以姿态四元数作为EKF的状态量,该如何设置初始协方差阵,以及如何利用四元数的协方差阵得到姿态角协方差阵的问题。

惯性卫星组合模型

在惯性卫星组合导航中,不同的算法选取不同的卡尔曼滤波状态量:

  • 如PSINS的test_SINS_GPS_153.m,该demo中状态量为15维(包括失准角3维、速度误差3维、位置误差3维、陀螺常值误差3维、加速度计常值误差3维)
  • 而在PX4 ECL中如果仅考虑GPS,忽略其他传感器,那么EKF的状态量为16维(姿态四元数4维、速度误差3维、位置误差3维、陀螺常值误差3维、加速度计常值误差3维)
  • 当然还有其它模型,如乘性四元数误差做为状态量的模型,卡尔曼滤波状态量15维(姿态四元数误差3维、速度误差3维、位置误差3维、陀螺常值误差3维、加速度计常值误差3维)

对于姿态来说,采用失准角作为卡尔曼滤波状态量,在进行初始值以及不确定度的设置(即初始的协方差阵P)时都有比较明确的物理意义。

如果采用四元数作为EKF的状态量:

1.初始值的设置比较明确,可以通过初始对准后的姿态角直接计算得到初始的姿态四元数
2. 初始姿态四元数的协方差阵应该如何计算呢?
3. EKF滤波后,如何通过四元数状态量的协方差阵计算得到姿态角的协方差阵呢?

四元数与欧拉角之间的协方差阵转换 - 理论

在3-2-1的旋转顺序下,四元数与欧拉角之间的旋转关系如下[1]:

参考问题what-does-the-covariance-of-a-quaternion-mean的回答[2],以及参考原文献[3],要利用四元数的协方差阵计算姿态角协方差,需要根据上述转换公式,计算姿态角相对于四元数的偏导,形成雅可比矩阵,并在四元数的协方差阵上左乘该雅可比矩阵,右乘雅可比矩阵的转置。

原文献如下所示,不过需要注意的是该文献中的旋转顺序为3-1-2,所以雅可比矩阵与3-2-1不同,但是计算的思想是一致的。

四元数与欧拉角之间的协方差阵转换 - 代码

与上述理论一致,在PX4 ECL的matlab脚本RunFilter.m中可以看到,该仿真代码通过如下方式,利用姿态四元数的协方差阵计算欧拉角的协方差阵:

        % output equivalent euler angle varianceserror_transfer_matrix = quat_to_euler_error_transfer_matrix(states(1),states(2),states(3),states(4));euler_covariance_matrix = error_transfer_matrix * covariance(1:4,1:4) * transpose(error_transfer_matrix);for i=1:3output.euler_variances(covIndex,i) = euler_covariance_matrix(i,i);end

其中quat_to_euler_error_transfer_matrix函数代码如下:

function error_transfer_matrix = quat_to_euler_error_transfer_matrix(q0,q1,q2,q3)
%QUAT_TO_EULER_ERROR_TRANSFER_MATRIX
%    ERROR_TRANSFER_MATRIX = QUAT_TO_EULER_ERROR_TRANSFER_MATRIX(Q0,Q1,Q2,Q3)%    This function was generated by the Symbolic Math Toolbox version 6.2.
%    13-Jul-2017 08:41:41t8 = q0.*q1.*2.0;
t9 = q2.*q3.*2.0;
t2 = t8+t9;
t4 = q0.^2;
t5 = q1.^2;
t6 = q2.^2;
t7 = q3.^2;
t3 = t4-t5-t6+t7;
t10 = t3.^2;
t11 = t2.^2;
t12 = t10+t11;
t13 = 1.0./t12;
t14 = 1.0./t3;
t15 = 1.0./t3.^2;
t17 = q0.*q2.*2.0;
t18 = q1.*q3.*2.0;
t16 = t17-t18;
t19 = t16.^2;
t20 = -t19+1.0;
t21 = 1.0./sqrt(t20);
t24 = q0.*q3.*2.0;
t25 = q1.*q2.*2.0;
t22 = t24+t25;
t23 = t4+t5-t6-t7;
t26 = t23.^2;
t27 = t22.^2;
t28 = t26+t27;
t29 = 1.0./t28;
t30 = 1.0./t23;
t31 = 1.0./t23.^2;
error_transfer_matrix = reshape([t10.*t13.*(q1.*t14.*2.0-q0.*t2.*t15.*2.0),q2.*t21.*2.0,t26.*t29.*(q3.*t30.*2.0-q0.*t22.*t31.*2.0),t10.*t13.*(q0.*t14.*2.0+q1.*t2.*t15.*2.0),q3.*t21.*-2.0,t26.*t29.*(q2.*t30.*2.0-q1.*t22.*t31.*2.0),t10.*t13.*(q3.*t14.*2.0+q2.*t2.*t15.*2.0),q0.*t21.*2.0,t26.*t29.*(q1.*t30.*2.0+q2.*t22.*t31.*2.0),t10.*t13.*(q2.*t14.*2.0-q3.*t2.*t15.*2.0),q1.*t21.*-2.0,t26.*t29.*(q0.*t30.*2.0+q3.*t22.*t31.*2.0)],[3, 4]);

姿态四元数的初始协方差阵设置

关于如何设置姿态四元数的初始协方差阵,目前还没有找到理论相关的文献。大多数使用四元数作为状态量的论文中,没有解释就直接设了初始不确定度,或者几乎不提及这个问题。如果有同学看到相关理论的参考文献,欢迎交流。

在PX4 ECL的matlab代码,给出的参数也是直接设置四元数的不确定度,而在C代码中给出的参数是设置初始对准后的角度不确定度,再根据角度不确定度来设置四元数的协方差阵,这给了我们一个参考方向。

相关代码如下,可以看到:

  • 在covariance.cpp中,初始化协方差函数initialiseCovariance调用resetQuatCov函数
  • 而resetQuatCov函数根据设置的初始对准角度误差不确定_params.initial_tilt_err,利用在ekf_helper.cpp中的initialiseQuatCovariances函数来计算四元数的协方差阵
  • 观察initialiseQuatCovariances可以发现,此时四元数的协方差阵并不是一个对角阵
  • initialiseQuatCovariances函数的输入实际上并不是姿态角的不确定度,而是旋转矢量的不确定度
// Sets initial values for the covariance matrix
// Do not call before quaternion states have been initialised
void Ekf::initialiseCovariance()
{P.zero();_delta_angle_bias_var_accum.setZero();_delta_vel_bias_var_accum.setZero();const float dt = FILTER_UPDATE_PERIOD_S;resetQuatCov();// velocityP(4,4) = sq(fmaxf(_params.gps_vel_noise, 0.01f));P(5,5) = P(4,4);P(6,6) = sq(1.5f) * P(4,4);// positionP(7,7) = sq(fmaxf(_params.gps_pos_noise, 0.01f));P(8,8) = P(7,7);if (_control_status.flags.rng_hgt) {P(9,9) = sq(fmaxf(_params.range_noise, 0.01f));} else if (_control_status.flags.gps_hgt) {P(9,9) = getGpsHeightVariance();} else {P(9,9) = sq(fmaxf(_params.baro_noise, 0.01f));}// gyro biasP(10,10) = sq(_params.switch_on_gyro_bias * dt);P(11,11) = P(10,10);P(12,12) = P(10,10);// accel bias_prev_dvel_bias_var(0) = P(13,13) = sq(_params.switch_on_accel_bias * dt);_prev_dvel_bias_var(1) = P(14,14) = P(13,13);_prev_dvel_bias_var(2) = P(15,15) = P(13,13);resetMagCov();// windP(22,22) = sq(_params.initial_wind_uncertainty);P(23,23) = P(22,22);}
void Ekf::resetQuatCov(){zeroQuatCov();// define the initial angle uncertainty as variances for a rotation vectorVector3f rot_vec_var;rot_vec_var.setAll(sq(_params.initial_tilt_err));initialiseQuatCovariances(rot_vec_var);
}
/ initialise the quaternion covariances using rotation vector variances
// do not call before quaternion states are initialised
void Ekf::initialiseQuatCovariances(Vector3f &rot_vec_var)
{// calculate an equivalent rotation vector from the quaternionfloat q0,q1,q2,q3;if (_state.quat_nominal(0) >= 0.0f) {q0 = _state.quat_nominal(0);q1 = _state.quat_nominal(1);q2 = _state.quat_nominal(2);q3 = _state.quat_nominal(3);} else {q0 = -_state.quat_nominal(0);q1 = -_state.quat_nominal(1);q2 = -_state.quat_nominal(2);q3 = -_state.quat_nominal(3);}float delta = 2.0f*acosf(q0);float scaler = (delta/sinf(delta*0.5f));float rotX = scaler*q1;float rotY = scaler*q2;float rotZ = scaler*q3;// autocode generated using matlab symbolic toolboxfloat t2 = rotX*rotX;float t4 = rotY*rotY;float t5 = rotZ*rotZ;float t6 = t2+t4+t5;if (t6 > 1e-9f) {float t7 = sqrtf(t6);float t8 = t7*0.5f;float t3 = sinf(t8);float t9 = t3*t3;float t10 = 1.0f/t6;float t11 = 1.0f/sqrtf(t6);float t12 = cosf(t8);float t13 = 1.0f/powf(t6,1.5f);float t14 = t3*t11;float t15 = rotX*rotY*t3*t13;float t16 = rotX*rotZ*t3*t13;float t17 = rotY*rotZ*t3*t13;float t18 = t2*t10*t12*0.5f;float t27 = t2*t3*t13;float t19 = t14+t18-t27;float t23 = rotX*rotY*t10*t12*0.5f;float t28 = t15-t23;float t20 = rotY*rot_vec_var(1)*t3*t11*t28*0.5f;float t25 = rotX*rotZ*t10*t12*0.5f;float t31 = t16-t25;float t21 = rotZ*rot_vec_var(2)*t3*t11*t31*0.5f;float t22 = t20+t21-rotX*rot_vec_var(0)*t3*t11*t19*0.5f;float t24 = t15-t23;float t26 = t16-t25;float t29 = t4*t10*t12*0.5f;float t34 = t3*t4*t13;float t30 = t14+t29-t34;float t32 = t5*t10*t12*0.5f;float t40 = t3*t5*t13;float t33 = t14+t32-t40;float t36 = rotY*rotZ*t10*t12*0.5f;float t39 = t17-t36;float t35 = rotZ*rot_vec_var(2)*t3*t11*t39*0.5f;float t37 = t15-t23;float t38 = t17-t36;float t41 = rot_vec_var(0)*(t15-t23)*(t16-t25);float t42 = t41-rot_vec_var(1)*t30*t39-rot_vec_var(2)*t33*t39;float t43 = t16-t25;float t44 = t17-t36;// zero all the quaternion covariancesP.uncorrelateCovarianceSetVariance<2>(0, 0.0f);P.uncorrelateCovarianceSetVariance<2>(2, 0.0f);// Update the quaternion internal covariances using auto-code generated using matlab symbolic toolboxP(0,0) = rot_vec_var(0)*t2*t9*t10*0.25f+rot_vec_var(1)*t4*t9*t10*0.25f+rot_vec_var(2)*t5*t9*t10*0.25f;P(0,1) = t22;P(0,2) = t35+rotX*rot_vec_var(0)*t3*t11*(t15-rotX*rotY*t10*t12*0.5f)*0.5f-rotY*rot_vec_var(1)*t3*t11*t30*0.5f;P(0,3) = rotX*rot_vec_var(0)*t3*t11*(t16-rotX*rotZ*t10*t12*0.5f)*0.5f+rotY*rot_vec_var(1)*t3*t11*(t17-rotY*rotZ*t10*t12*0.5f)*0.5f-rotZ*rot_vec_var(2)*t3*t11*t33*0.5f;P(1,0) = t22;P(1,1) = rot_vec_var(0)*(t19*t19)+rot_vec_var(1)*(t24*t24)+rot_vec_var(2)*(t26*t26);P(1,2) = rot_vec_var(2)*(t16-t25)*(t17-rotY*rotZ*t10*t12*0.5f)-rot_vec_var(0)*t19*t28-rot_vec_var(1)*t28*t30;P(1,3) = rot_vec_var(1)*(t15-t23)*(t17-rotY*rotZ*t10*t12*0.5f)-rot_vec_var(0)*t19*t31-rot_vec_var(2)*t31*t33;P(2,0) = t35-rotY*rot_vec_var(1)*t3*t11*t30*0.5f+rotX*rot_vec_var(0)*t3*t11*(t15-t23)*0.5f;P(2,1) = rot_vec_var(2)*(t16-t25)*(t17-t36)-rot_vec_var(0)*t19*t28-rot_vec_var(1)*t28*t30;P(2,2) = rot_vec_var(1)*(t30*t30)+rot_vec_var(0)*(t37*t37)+rot_vec_var(2)*(t38*t38);P(2,3) = t42;P(3,0) = rotZ*rot_vec_var(2)*t3*t11*t33*(-0.5f)+rotX*rot_vec_var(0)*t3*t11*(t16-t25)*0.5f+rotY*rot_vec_var(1)*t3*t11*(t17-t36)*0.5f;P(3,1) = rot_vec_var(1)*(t15-t23)*(t17-t36)-rot_vec_var(0)*t19*t31-rot_vec_var(2)*t31*t33;P(3,2) = t42;P(3,3) = rot_vec_var(2)*(t33*t33)+rot_vec_var(0)*(t43*t43)+rot_vec_var(1)*(t44*t44);} else {// the equations are badly conditioned so use a small angle approximationP.uncorrelateCovarianceSetVariance<1>(0, 0.0f);P.uncorrelateCovarianceSetVariance<3>(1, 0.25f * rot_vec_var);}
}

参考

[1] https://handwiki.org/wiki/Conversion_between_quaternions_and_Euler_angles
[2] https://stats.stackexchange.com/questions/119780/what-does-the-covariance-of-a-quaternion-mean
[3] https://www.ucalgary.ca/engo_webdocs/GL/96.20096.JSchleppe.pdf

关于四元数与欧拉角协方差阵转换的一些思考相关推荐

  1. 转换矩阵、平移矩阵、旋转矩阵关系以及python实现旋转矩阵、四元数、欧拉角之间转换

    文章目录 1. 转换矩阵.平移矩阵.旋转矩阵之间的关系 2. 缩放变换.平移变换和旋转变换 2. python实现旋转矩阵.四元数.欧拉角互相转化 由于在平时总是或多或少的遇到平移旋转的问题,每次都是 ...

  2. 【Unity3D 灵巧小知识点】☀️ | Unity 四元数、欧拉角 与 方向向量 之间转换

    Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 . 包括游戏开发.美术.建筑.汽车设计.影视在内的所有创作者,借助 Unity 将创意 ...

  3. 无人机姿态解算:四元数及其与欧拉角的转换

    无人机姿态解算:四元数及其与欧拉角的转换 引言:获得无人机飞行时的飞行姿态对于无人机稳定控制来说至关重要.无人机主要通过传感器数据融合来进行状态估计,常用于无人机的传感器包括:MPU(包含了三轴加速度 ...

  4. 四元数转换为欧拉角(多解问题)

    车辆行驶状态估计(4)中车辆横摆角信息在顺时针转向时存在明显的错误,进行记录输出 2023-05-25-aft02.txt 四元数: -0.00201210.00115721 -0.000596761 ...

  5. Matlab ——旋转矩阵,四元数,欧拉角之间的转换

    最近要用这方面的东西,整理,记录,分享一下 基于Matlab现有函数下的内容 Matlab --旋转矩阵,四元数,欧拉角之间的转换 旋转矩阵 dcm R 四元数 quat q = [q0 q1 q2 ...

  6. matlab和Eigen库中的一些旋转矩阵(方向余弦矩阵)、四元数和欧拉角之间的转换和绘图的注意事项

    最近用matlab和Eigen库中的一些旋转矩阵(方向余弦矩阵).四元数和欧拉角之间的转换和绘图,弄得我有些头疼,把遇到的问题记录一下,以防以后又脑阔疼....有不同的理解可以再评论区批评指正- 主要 ...

  7. eigen 编译_头条 | 使用eigen实现四元数、欧拉角、旋转矩阵、旋转向量间的转换...

    点击上方蓝字,关注本公众号,获得更多资源上一篇文章介绍了四元数.欧拉角.旋转矩阵.轴角如何相互转换,本篇文章介绍如何用eigen来实现. 旋转向量 1,初始化旋转向量:旋转角为alpha,旋转轴为(x ...

  8. ROS中四元数、欧拉角、旋转矩阵等格式转换

    未完- ROS接收到odometry格式消息: nav_msgs::Odometry pos_msg 具有: pos_msg.pose.pose.orientation.x; // xyzw pos_ ...

  9. 四元数,欧拉角,旋转矩阵相互转换

    #include <TransForms3d/TransForms.h>/*---------------------------------------角度弧度转换----------- ...

  10. unity 四元数和欧拉角的相互转换

    四元数和欧拉角相互转换 //四元数转化成欧拉角 Vector3 v3=transform.rotation.eulerAngles; //欧拉角转换成四元数 Quaternion rotation = ...

最新文章

  1. Spring整合Redis时报错:java.util.NoSuchElementException: Unable to validate object
  2. TortoiseGit入门(图文教程) Git,Github,puttygen,SSH
  3. Keras【Deep Learning With Python】更优模型探索Keras实现CNN
  4. 23设计模式简介笔记
  5. linux kernel基本构成的内容有下列哪些项_Linux_GUI加速(2)_Linux中的DRM-KMS分析
  6. linux awk 教程,Linux awk使用案例教程
  7. python画圆并填充图形颜色_如何使用python设计语言graphics绘制圆形图形
  8. 滞后分析rstudio_使用RStudio进行A / B测试分析
  9. 关于纯HTML格式写入word
  10. MyFlash使用总结
  11. Git:错误:error:src refspec master does not match any
  12. 设计模式---面向对象的设计原则概述
  13. c语言结构体菜单显示框架,请教c语言结构体嵌套问题。field `atItem' has incomplete type...
  14. 图解算法之排序算法(3)——插入排序
  15. 2020 年物联网设备达 500 亿台!AI、区块链技术加持,优秀开发者稀缺!
  16. oracle查询属主下对象,SQL优化
  17. activiti(7.0) 组任务流程CandidateUsers
  18. awakeFromNib 与 viewDIdLoad 自己小结
  19. 百度地图 - js获取行政区边界范围
  20. 伯克利CS61A-Sum2019-Week1

热门文章

  1. 蚁群算法原理及matlab代码实现
  2. matlab tiff 压缩方式,无法打开以这种方式压缩的tiff文件(2) - imageJ / FIJI
  3. go语言反汇编linux,Go语言函数的底层实现
  4. 3ds Max 文件修改版本工具
  5. STM32通过IIC驱动MAX30102心率血氧传感器
  6. 倒计时 分秒 小程序 方法_微信小程序 倒计时
  7. Java中类与对象的定义与使用
  8. GIS数据恢复(ArcMap)地理数据库误删
  9. termios结构体详解
  10. 快鲸六大私域运营服务,赋能企业业绩长效增长