【行人惯性导航】关于行人导航中IMU位姿推导的知识点及相关代码
IMU姿态惯性推导
- 最近从事行人惯性导航的研究,本人也是一个小白,其中看了很多文献,有很多个人思考很费时间的地方,撰写此随笔的目的不仅是给自己做一个笔记,也是给各位有需要的仁兄一点个人理解。
- 本文只关于使用IMU传感器为主的行人导航算法。
- 本文为一篇行人惯性导航的入门,主要针对其中重要的涉及的知识点之间的解释、串联,包括航向更新、速度更新、位置更新、坐标变换原理即代码,不深究其推导。要是有什么讲得不对的地方,请给予指正,谢谢。
引言
以IMU为主,其他传感器(多为磁力计、高度计、气压计、压力传感器、肌肉电传感器等)为辅的行人导航研究中,主要有两种方案(这里忽略SLAM、激光雷达之类的,)。一个是基于航迹推移的方案(SHS,step-and-heading systems),另一个是基于惯性积分的方案(INS,inertial navigation systems)。个人研究的技术方向属于后者(INS),所以后面将会着重介绍后者的技术细节。
SHS
也就是常见的航迹推移算法(PDR,Pedestrian Dead Reckoning),根据计算出来的步长和航向,通过三角函数关系递推下一步的位置。所以该方案的核心就是求步长和航向,同时也是该算法的两个主要误差来源。求步长有诸多步长估计模型,比如Weinberg模型[1]
\]
或者Scarlet模型[2]
\]
等等,详细细节可自行了解。但是无论使用哪一个步长模型,这里面的参数(比如k)都跟个体参数(步频、步长、腿长等)的不同而不同,即需要对人体进行运动学建模,这也是这种模型最大的一个弊端(个人觉得)[3]。
关于航向修正放在后面(INS)一起总结,因为无论是SHS,还是INS,航向漂移都是两者的痛点。
INS
基于惯性递推的技术方案,给出常见的递推公式[4]便一目了然。
v_k^n = v_{k-1}^n+\{R(q_{k-1})f^b + g^n\}\Delta T \\
q_{b,k}^n = \Omega(\omega_k \Delta t)q_{b,k-1}^n
\]
其中\(n\)、\(b\)分别表示导航坐标系和载体坐标系,\(p\)、\(v\)、\(q\)分别表示位置、速度、姿态四元数(对应欧拉角,俯仰角pitch、滚转角raw、航向角yaw)。这里是一个简化后的模型,忽略了地球自转、经纬度等因素的影响,因为这些因素对低精度的惯性器件影响可以忽略不计,具体细节可以参考文献[7],这里不再展开。
INS特点:
- 基于惯性递推的方案相比于航迹推移算法,其本身的姿态推导不需要为人体运动学建模,适用性更好;
- 基于惯性递推的方案误差随时间的立方根次增长,这是其最大的弊端;
- 基于惯性递推的方案一般结合零速修正技术,使用卡尔曼滤波器将两者进行融合,限制误差的增长。
关于INS方法的技术点
- 零速修正
- 使用零速修正技术,重点是使用什么检测器检测零速条件!
- 当前有很多零速检测器,比SHOE、ARED、MBGTD等,其中SHOE公认精度是最好的[6]。
- 航向修正
- 无论是SHS还是INS,在航向修正方面所遇到的问题都基本相同,及决方案大致一样,要么借助磁力计,要么是HDR/iHDR,或者其他的方案。
干货
下面所讲的内容是个人所经历的,也是本文的重点。如果看惯性导航参考书[5]的话,你一般都会看到复杂的推导,容易搞蒙,尤其是涉及到坐标系的转换关系,除非死磕硬骨头才能拿下。其实有一本不错的讲义[8],本人的大多数困惑都能从上边找到答案。
- 姿态更新
- 首先要明白IMU测的是相对于惯性坐标系 \(i\) 的加速度和角速度,不是相对于导航系 \(n\) ,这之间存在转换。这也是为什么我早期一直很困惑的原因。具体的推导比较复杂,本文只给出关键结果。姿态的更新一般用四元数、旋转矩阵或旋转向量表示。本文以旋转矩阵进行说明。不同表达形式,都有各自的优缺点。旋转矩阵存在万向锁问题,四元数存在交换不可逆误差等。一般在使用的时候结合使用。
\]
其中,\(C_{b(k)}^{b(k-1)}\) 表示以i
系作为参考基准,b
系从 \(t_{k-1}\) 时刻到 \(t_{k}\) 时刻的旋转变化,\(C_{b(k)}^{b(k-1)}\) 由角速度 \(w_{ib}^b\) 确定;\(C_{n(k)}^{n(k-1)}\) 表示以i
系作为参考基准,n
系从 \(t_{k-1}\) 时刻到 \(t_{k}\) 时刻的旋转变化,\(C_{n(k-1)}^{n(k)}\) 由计算角速度 \(-w_{in}^n\) 确定;\(C_{n(k-1)}^{n(k-1)}\) 和 \(C_{b(k)}^{n(k)}\) 分别表示 \(t_{k-1}\) 和 \(t_{k}\) 时刻的捷联姿态矩阵。通常在导航更新周期 \([t_{k-1},t_k]\) 内,可认为速度和位置引起的 \(w_{in}^n\) 计算角速度很小,即可视为常值[8];通常在更新周期 \([t_{k-1},t_k]\) 内,导航系的变化很缓慢,所以 \(C_{n(k-1)}^{n(k)} \approx I_{3 \times 3}\)[5]。从这个角度应该能更好的理解坐标系之间的变化关系。
用四元数表示为:
q(\omega_k \Delta t) = cos\cfrac{\phi}{2} + \cfrac{\overrightarrow{\phi}}{\phi}sin\cfrac{\phi}{2}
\]
其中 \(Q\) 为四元数,表示载体的姿态,\(\phi\) 是旋转矢量 \(\overrightarrow{\phi}\) 的模长,四元数、旋转矢量、旋转矩阵可以互相转换。这里所写的形式和之前的递推公式没有什么区别,只是一个是四元数的左乘,一个是四元数的右乘。为什么四元数需要结合旋转向量使用,就是弥补各自的缺点(建议看书,这里面存在一个理论推导)。
- 速度更新
- 速度的更新也存在一个坐标系的转换;
- 其实只要理解的旋转矩阵的更新,后面的推导都是在旋转矩阵更新的基础上的得到;
- 关于速度更新,更注意的一点是剔除重力因素的影响。
- 上面的递推公式 \(v_k^n = v_{k-1}^n+\{R(q_{k-1})f^b + g^n\}\Delta T\),其中 \(R(q_{k-1})f^b\) 对所测到的加速度 \(f^b\)(一般称为比力) 进行坐标变换,\(R(q_{k-1})\) 表示对四元数转换为旋转矩阵。
- 位置更新
- 这就不用说了,一眼明了。
相关代码(Python)
v_k^n = v_{k-1}^n+\{R(q_{k-1})f^b + g^n\}\Delta T \\
q_{b,k}^n = \Omega(\omega_k \Delta t)q_{b,k-1}^n
\]
def nav_eq(self, xin, imu, qin, dt):
# imu[0:3] acc 加速度
# imu[3:6] gyro 角速度
# imu[6:9] attitude 航向
# update Quaternions
x_out = np.copy (xin) # initialize the output
# 这里是求 omega,即 wt 的
omega = np.array ([[0, -imu[3], -imu[4], -imu[5]],
[imu[3], 0, imu[5], -imu[4]],
[imu[4], -imu[5], 0, imu[3]],
[imu[5], imu[4], -imu[3], 0]])
# 求角速度的二范数,即模长
# qout输出旋转矩阵 $\Omega$
# 定时增量法,四元数微分方程的毕卡求解法,四元数的更新为了避免其自身的不可交换误差,会先计算旋转矢量,利用旋转矢量更新四元数,具体参考文献[8]
norm_w = LA.norm (imu[3:6])
if (norm_w * dt != 0):
q_out = (np.cos (dt * norm_w / 2) * np.identity (4) + (1 / (norm_w)) * np.sin (dt * norm_w / 2) * omega).dot (qin)
else:
q_out = qin
attitude = quat2euler (q_out, 'sxyz') # update euler angles
x_out[6:9] = attitude
Rot_out = quat2mat (q_out) # 将更新后的四元数转换成旋转矩阵
acc_n = Rot_out.dot (imu[0:3]) # 对所测的加速度进行坐标变换
acc_n = acc_n + np.array ([0, 0, self.config["g"]]) # 剔除重力影响
x_out[3:6] += dt * acc_n # 速度更新
x_out[0:3] += dt * x_out[3:6] + 0.5 * np.power (dt, 2) * acc_n # 位置更新
return x_out, q_out, Rot_out
在此感谢大佬的开源pyshoe。如果是小白,强烈推荐这个开源,因为其还有对标论文,可以便看边上手。同时还需要感谢大佬实验室OpenSHOE。这两个开源项目给我的研究带来了巨大的飞跃,在此重重感谢。
总结
关于IMU的行人导航技术,还有很多研究的热点,比如初始校准、高程问题、航向问题、多运动模型的问题等等。以上只是个人的理解,如果有什么不对的地方,请大佬尽管之处,虚心请教。欢迎各位同学留言,互相学习、探讨。
参考文献
[1] Weinberg H. Using the ADXL202 in pedometer and personal navigation applications[J].
[2] Scarlett J. Enhancing the performance of pedometers using a single accelerometer[J].
[3] 潘献飞, 穆华, 胡小平. 单兵自主导航技术发展综述[J]. 导航定位与授时, 2018, 5(1):11.
[4] Wagstaff B , Peretroukhin V , Kelly J . Robust Data-Driven Zero-Velocity Detection for Foot-Mounted Inertial Navigation[J]. IEEE Sensors Journal, 2019, PP(99):1-1.
[5] 秦永元. 惯性导航.第2版[M]. 科学出版社, 2014.
[6] Wahlstrm J , Skog I . Fifteen Years of Progress at Zero Velocity: A Review[J]. 2020.
[7] Muhammad I , Kuk C , Seung-Ho B , et al. Drift Reduction in Pedestrian Navigation System by Exploiting Motion Constraints and Magnetic Field[J]. Sensors (Basel, Switzerland), 2016, 16(9).
[8] 捷联惯导算法与组合导航原理讲义. 严恭敏,翁浚 编著.
【行人惯性导航】关于行人导航中IMU位姿推导的知识点及相关代码的更多相关文章
- 在ECSHOP后台左侧导航中增加新菜单
在ECSHOP后台左侧导航中增加新菜单 ECSHOP教程/ ecshop教程网(www.ecshop119.com) 2011-11-08 有个别高级用户(懂PHP的),提到这样的问题: 在后台管 ...
- 鼠标经过导航中li时,一个彩色模块跟着鼠标移动
1.鼠标经过导航中li时,一个活动的li跟随鼠标移动,最终移动到鼠标的停留的位置.(如需鼠标离开后让活动的li回到初始位置,则用jq hover事件,当鼠标离开时,给活动的li设置left是0) 2. ...
- 如何删除帝国cms面包屑导航中首页链接的/index.html
前面一篇"帝国cms面包屑导航的首页链接锚文本改成关键字"中xmyanke有写到改首页链接的方法,但是感觉比较麻烦,这里就说说如何删除帝国cms面包屑导航中首页链接的/index. ...
- Bootstrap历练实例:导航中的表单
Bootstrap历练实例:导航中的表单,它是使用class.navbar-form类,这确保了表单适当的垂直对齐和在较窄的视口中折叠的行为,使用这个对齐方式选项来决定导航栏中的内容放置在哪里. 实例 ...
- Java学习过程中的总结的小知识点(长期更新)
Java学习过程中的总结的小知识点 (主要是自己不会的知识和容易搞错的东西) 计算某个程序运行的时间 long stime=System.currentTimeMillis(); copy3(file ...
- 可控制导航下拉方向的jQuery下拉菜单代码
效果:http://hovertree.com/texiao/nav/1/ 代码如下: <!DOCTYPE html> <html> <head> <meta ...
- 借One-Class-SVM回顾SMO在SVM中的数学推导--记录毕业论文5
上篇记录了一些决策树算法,这篇是借OC-SVM填回SMO在SVM中的数学推导这个坑. 参考文献: http://research.microsoft.com/pubs/69644/tr-98-14.p ...
- 在Sublime Text 3 中安装SublimeLinter,Node.js进行JS&CSS代码校验
转载自:http://www.wiibil.com/website/sublimelinter-jshint-csslint.html 在Sublime Text中安装SublimeLinter,No ...
- css中的大小、定位、轮廓相关属性
css中的大小.定位.轮廓相关属性 1.通过height.width属性控制组件大小 height:高度,可以设置任何有效的距离值: width:宽度,可以设置任何有效的属性值: max-height ...
随机推荐
- DP 习题
一.简单基础dp 这类dp主要是一些状态比较容易表示,转移方程比较好想,问题比较基本常见的.主要包括递推.背包.LIS(最长递增序列),LCS(最长公共子序列),下面针对这几种类型,推荐一下比较好的学 ...
- layui日期选择无效的问题
解决layui引入时间控件无效的问题 - 简书 (jianshu.com) 原因是因为在使用日期选择器的时候,layui源码里有一个laydate.css文件找不到 将下载的文档文件里的css文件夹, ...
- 安卓gradle时报错"ERROR: Plugin with id 'com.android.application' not found."
在build.gradle中更改gradle插件版本号 buildscript { repositories { google() jcenter() } dependencies { //版本号请根 ...
- 【原创】自制string类型(已完成)
这篇文章首发于360doc http://www.360doc.com/content/21/0526/17/73755266_979099504.shtml ,其实360doc里面的那个也是我的帐号 ...
- 【PHP数据结构】交换排序:冒泡、快排
上篇文章中我们好好地学习了一下插入类相关的两个排序,不过,和交换类的排序对比的话,它们真的只是弟弟.甚至可以说,在所有的排序算法中,最出名的两个排序都在今天要介绍的交换排序中了.不管是冒泡.还是快排, ...
- 深入学习Composer原理(二)
本系列的第二篇文章,这次我们聊聊:spl_autoload_register()函数 PHP的SPL库作为扩展库,已经于5.3.0版本后默认保持开启,成为PHP的一组强大的核心扩展库.大家有时间可以多 ...
- mybatis的mapper特殊字符转移以及动态SQL条件查询
前言 我们知道在项目开发中之前使用数据库查询,都是基于jdbc,进行连接查询,然后是高级一点jdbcTemplate进行查询,但是我们发现还是不是很方便,有大量重复sql语句,与代码偶合,效率低下,于 ...
- Shell系列(12)- 预定义变量(5)
预定义变量 作用 $? 常用:最后一次执行的命令的返回状态. 如果这个变量的值为0,证明上一个命令正确执行:如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了 $$ ...
- windows 根据 端口号 找到进程ID PID
List process by port number netstat -ano | findstr 8080 Proto Local Address Foreign Address State PI ...
- 简述编写Django应用的基本步骤
(1)创建项目,cd到一个你想要放置你代码的目录.Django -admin startproject mysite. Django project即一个Django项目实例需要的设置项的集合,包括数 ...