MPU6050姿态解算2-欧拉角旋转矩阵 -->相关推导

IMU姿态解算
IMU,即惯性测量单元,一般包含三轴陀螺仪与三轴加速度计。之前的文章 MPU6050姿态解算1-DMP方式已将对MPU6050这款IMU作了简单的介绍,并通过其内部的DMP处理单元直接得到姿态解算的四元数结果。本篇将通过软件解算的方式,利用欧拉角与旋转矩阵来对陀螺仪与加速度计的原始数据进行姿态求解,并将两种姿态进行互补融合,最终得到IMU的实时姿态。

本篇的姿态解算选用的旋转顺序为ZYX,即IMU坐标系初始时刻与大地坐标系重合,然后依次绕自己的Z、Y、X轴进行旋转,这里先自定义一下每次的旋转名称和符号:

绕IMU的Z轴旋转:航向角yaw, 转动 y 角度
绕IMU的Y轴旋转:俯仰角pitch,转动 p 角度
绕IMU的X轴旋转:横滚角row, 转动 r 角度
三次旋转的示意图如下:

 另外,横滚roll,俯仰pitch,偏航yaw的实际含义如下图:

 旋转矩阵
旋转矩阵的知识请先参阅 3维旋转矩阵推导与助记这里只列出本篇需要用到的3个旋转矩阵,注意这3个旋转矩阵是坐标变换的旋转矩阵。

欧拉角旋转
欧拉角旋转的知识请先参阅 欧拉角旋转这里需要说明的是,本篇需要用到的绕着自己运动的轴,以ZYX顺序旋转。

加速度计解算姿态角
加速度计测量的是其感受到的加速度,在静止的时候,其本身是没有加速运动的,但因为重力加速度的作用,根据相对运动理论,其感受的加速度与重力加速度正好相反,即读到的数据是竖直向上的。加速度计的英文简写为acc,下面用首字母a代表加速度计数据。

加速度利用静止时刻感受到重力加速度,计算姿态:

当加速度计水平放置,即Z轴竖直向上时,Z轴可以读到1g的数值(g为重力加速度),X轴和Y轴两个方向读到0,可以记作(0,0,g)。

当加速度计旋转一定的姿态时,重力加速度会在加速度的3个轴上产生相应的分量,其本质是大地坐标系下的(0,0,g)在新的加速度计自身坐标系下的坐标,加速度计读到的3个值就是(0,0,g)向量的新坐标。

姿态的旋转选用ZYX顺序的3次旋转方式,则上述描述可表示为:
 

 

 解这个方程,可以得到roll和pitch角(由于绕Z旋转时,感受到的重力加速度是不变的,因此加速度计无法计算yaw角)

 

 3次旋转过程的分解过程如下图:

 

陀螺仪解算姿态角
陀螺仪测量的绕3个轴转动的角速度,因此,对角速度积分,可以得到角度。陀螺仪的英文简写为gyro,下面用首字母g代表陀螺仪数据。

如下图,IMU在第n个时刻的姿态角度为r、p、y,其含义为IMU坐标系从初始位置,经过绕Z旋转y角度,绕Y旋转p角度,绕X旋转r角度,得到了最终的姿态,此时需要计算下一个时刻(n+1)的姿态。设n+1时刻的姿态角为r+Δr、p+Δp、y+Δy,该姿态也是经历了3次旋转。要想计算n+1时刻的姿态,只要在n时刻姿态的基础上,加上对应的姿态角度变化量即可。姿态角度的变化量可以通过角速度与采用时间周期积分即可。

这里红框中dr/dt等角速度实际是假想的角速度,用于姿态更新,姿态更新是以大地坐标系为参考,而陀螺仪在第n个状态读出的角速度是以它自己所在的坐标系为参考,需要将读到的gyro陀螺数据经过变换,才能用于计算更新第n+1次的姿态。

那dr/dt等角速度该怎样理解呢?看下面这个图,还是将其分解为3次旋转:

 

 

首先来看dy/dt,它是3次旋转过程中绕Z轴的yaw角的角速度,3次旋转首先就是绕着Z轴旋转,Z轴方向的单位向量可表示为[0 0 1]T,T表示向量转置,因此[0 0 dy/dt]T表示在图中状态①的坐标中绕Z的角速度。由于之后该坐标系还要经历绕Y和绕X的两次旋转,因此这里[0 0 dy/dt]T角速度在经历两次旋转后,在最终的坐标系(状态③)中的坐标也要经历两次变换。图中的[gx_Z gy_Z gz_Z]T表示3次旋转过程中绕Z轴的yaw角的角速度在最终姿态中的等效转动角速度,实际就是状态①坐标系中绕Z轴的角速度在状态③坐标系中的新的坐标。

同理,dp/dt还需要经历1次旋转变换,而dr/dt不需要经历旋转。

将dy/dt,dp/dt,dr/dt三者都变换到状态③坐标系中的新的坐标相加,实际就是状态③时刻陀螺仪自己读到的gyro数据。

所以,从dr/dt等角速度到陀螺仪读到的角速度gx等的转换关系推导过程如下:

 进一步,再把这里的状态③理解为状态n,则根据状态n时刻读到的陀螺仪数据,反解dy/dt等角速度数据,即可更新得到状态n+1的姿态。反解就是求逆矩阵,即:

 

姿态融合
由上面的分析可知,加速度计在静止时刻,根据感受到的重力加速度,可以计算出roll和pitch角,并且角度计算只与当前姿态有关。而陀螺仪是对时间间隔内的角速度积分,得到每一次的角度变换量,累加到上一次的姿态角上,得到新的姿态角,陀螺仪可以计算roll、pitch、yaw三个角。

实际上,加速度仅在静止时刻可以得到较准确的姿态,而陀螺仪仅对转动时的姿态变化敏感,且陀螺仪若本身存在误差,则经过连续的时间积分,误差会不断增大。因此,需要结合两者计算的姿态,进行互补融合。当然,这里只能对roll和pitch融合,因为加速度计没有得到yaw。

K为比例系数,需要根据实际来调整,如选用0.4。

MATLAB公式推导
上面的一些推导计算过程,可用MATLAB来辅助计算,防止手工计算出错:

先定义3个旋转矩阵Y

% 旋转顺序:Z,Y,X(从大地坐标系到IMU坐标系)% 定义一些符号 r=row p=pitch y=yaw
syms r p y% 3个旋转矩阵(坐标系旋转,注意负号的位置!)
M_x = [  1,       0,      0;0,  cos(r), sin(r); 0, -sin(r), cos(r)];M_y = [cos(p),   0, -sin(p);0,   1,       0;sin(p),   0,  cos(p)]; M_z = [ cos(y),  sin(y),  0;-sin(y),  cos(y),  0;0,       0,   1]; 

推导陀螺仪的变换矩阵

%% 推导陀螺仪的变换矩阵%定义一些符号 drdt dpdt dydt 指的是分别对 roll pitch yaw求导,也就是角速度
syms drdt dpdt dydt% 绕x轴转动 row 的角速度
dr_t = [drdt;0;0]; % 绕y轴转动 pitch 的角速度
dp_t = [   0;dpdt;0];% 绕z轴转动 yaw 的角速度
dy_t = [   0;0;dydt]; % [矩阵X*矩阵Y*yaw角速度(绕Z)] + [矩阵X*pitch角速度(绕Y)] + [roll角速度(绕X)]
% IMU_gyro实际就是IMU测得的3个陀螺仪数据
IMU_gyro = M_x*M_y*dy_t + M_x*dp_t + dr_t;
fprintf('M_x*M_y*dy_t + M_x*dp_t + dr_t=\r\n')
disp(IMU_gyro)
% roll pitch yaw角速度组成的列向量,这个实际是要求的大地坐标系的3个角速度
rpy_t = [drdt;dpdt;dydt]; %手动分解IMU_gyro为矩阵M_gyro与列向量rpy_t相乘的形式
%根据IMU_gyro写出M_gyro,该矩阵将大地坐标系的角速度转换为IMU坐标系
M_gyro = [ 1,     0,       -sin(p);0, cos(r),cos(p)*sin(r);0,-sin(r),cos(p)*cos(r)];
%验证一下
if M_gyro * rpy_t==IMU_gyrofprintf('M_gyro is true\r\n');
elsefprintf('M_gyro is false\r\n');
end
fprintf('M_gyro=\r\n')
disp(M_gyro)% 对M_gyro求逆矩阵,用于将IMU坐标系的陀螺仪角速度值转换到大地坐标系
M_gyro_inv = inv(M_gyro);
fprintf('M_gyro_inv=\r\n')
disp(M_gyro_inv)% matlab求解的逆矩阵需要在再手工化简
M_gyro_inv_ =[ 1, (sin(p)*sin(r))/cos(p), (cos(r)*sin(p))/cos(p);0,                 cos(r),                -sin(r);0,          sin(r)/cos(p),          cos(r)/cos(p)];% 验证一下,M_gyro_inv_ * M_gyro_inv应该是单位矩阵
fprintf('M_gyro_inv_ * M_gyro=\r\n')
disp(M_gyro_inv_ * M_gyro)
fprintf('M_gyro_inv_ =\r\n')
disp(M_gyro_inv_)

运行后的输出结果:

M_x*M_y*dy_t + M_x*dp_t + dr_t=drdt - dydt*sin(p)dpdt*cos(r) + dydt*cos(p)*sin(r)dydt*cos(p)*cos(r) - dpdt*sin(r)M_gyro is trueM_gyro=[ 1,       0,       -sin(p)]
[ 0,  cos(r), cos(p)*sin(r)]
[ 0, -sin(r), cos(p)*cos(r)]M_gyro_inv=[ 1, (sin(p)*sin(r))/(cos(p)*cos(r)^2 + cos(p)*sin(r)^2), (cos(r)*sin(p))/(cos(p)*cos(r)^2 + cos(p)*sin(r)^2)]
[ 0,                        cos(r)/(cos(r)^2 + sin(r)^2),                       -sin(r)/(cos(r)^2 + sin(r)^2)]
[ 0,          sin(r)/(cos(p)*cos(r)^2 + cos(p)*sin(r)^2),          cos(r)/(cos(p)*cos(r)^2 + cos(p)*sin(r)^2)]M_gyro_inv_ * M_gyro=[ 1,                   0, cos(r)^2*sin(p) - sin(p) + sin(p)*sin(r)^2]
[ 0, cos(r)^2 + sin(r)^2,                                          0]
[ 0,                   0,                        cos(r)^2 + sin(r)^2]M_gyro_inv_ =[ 1, (sin(p)*sin(r))/cos(p), (cos(r)*sin(p))/cos(p)]
[ 0,                 cos(r),                -sin(r)]
[ 0,          sin(r)/cos(p),          cos(r)/cos(p)]

程序先计算出了M_x*M_y*dy_t + M_x*dp_t + dr_t,然后手工分解为M_gyro与rpy_t相乘的形式,最后求得M_gyro的逆矩阵M_gyro_inv_,即得到用于将IMU坐标系的陀螺仪角速度值转换到大地坐标系的旋转矩阵。

推导加速度计的变换矩阵

%% 推导加速度计的变换矩阵M_acc=M_x*M_y*M_z;
fprintf('M_acc=\r\n')
disp(M_acc)%重力向量
syms g
acc = [0;0;g]; 
IMU_acc=M_acc*acc;
fprintf('IMU_acc=\r\n')
disp(IMU_acc)

运行后的输出结果:

M_acc=[                        cos(p)*cos(y),                        cos(p)*sin(y),       -sin(p)]
[ cos(y)*sin(p)*sin(r) - cos(r)*sin(y), cos(r)*cos(y) + sin(p)*sin(r)*sin(y), cos(p)*sin(r)]
[ sin(r)*sin(y) + cos(r)*cos(y)*sin(p), cos(r)*sin(p)*sin(y) - cos(y)*sin(r), cos(p)*cos(r)]IMU_acc=-g*sin(p)g*cos(p)*sin(r)g*cos(p)*cos(r)


计算得到的IMU_acc即是加速度计感受到的重力加速度向量在IMU最终姿态所在坐标系中的坐标。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/255461.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vector Quantized Diffusion Model for Text-to-Image Synthesis

Vector Quantized Diffusion Model for Text-to-Image Synthesis Shuyang Gu, University of Science and Technology of China, Microsoft, CVPR2022, Cited: 340, Code, Paper 1. 前言 我们提出了用于文本到图像生成的矢量量化扩散(Vector Quantized Diffusion Model&…

由于找不到xinput1_3.dll,无法继续执行代码的多种解决方法指南,xinput1_3.dll文件修复

当玩家或用户在启动某些游戏和应用程序时,可能会遭遇到一个系统错误提示:“由于找不到xinput1_3.dll,无法继续执行代码l”。这种情况通常指出系统中DirectX组件存在问题。以下我们将介绍几种常用的解决方法,并提供详细的操作步骤。 一.找不到…

ROS 动态坐标变换

在ROS 中,坐标变换是一个重要的概念,因为它允许系统中的不同节点和模块以统一的方式描述物体的位置和方向。 动态坐标变换指的是当机器人或其环境中物体的位姿(位置和姿态)发生变化时,能够实时更新这些信息的过程。 …

【React Hooks】useReducer()

useReducer 的三个参数是可选的,默认就是initialState,如果在调用的时候传递第三个参数那么他就会改变为你传递的参数,实际开发不建议这样写。会增加代码的不可读性。 使用方法: 必须将 useReducer 的第一个参数(函数…

分享一个基础面试题---手写call

分享一个基础面试题---手写call 手写call笔记第一步第二步第三步 手写call笔记 call():在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。 let foo {value:1 }; function bar(){console.log(this.value); } bar.call(foo);//1注意两点&…

微信小程序开发之原生小程序开发和uniapp开发的区别,两种开发方式语法上的区别

目前小程序开发有两种形式,分别是原生小程序开发和使用uniapp开发, uniapp和小程序原生开发都有各自的优缺点,开发者可以根据具体需求选择合适的开发方式。 一、两者区别如下: 编程语言:uniapp使用Vue语法编写应用程序…

内测分发平台支持应用的异地容灾的重要性

大家好,我是咕噜-凯撒,随着网络社会的发展,人们对于应用程序的依赖程度越来越高。无论是企业用户还是个人用户,都希望能够随时随地访问到需要使用的应用。所以对于内测分发平台来说保证应用的连续性和可靠性是非常的关键。内侧分发…

惠普台式机如何关闭UEFI

惠普台式机如何关闭UEFI 1、开机一直按按ESC,出现以下界面后,再按F10进入BIOS。 2.选择安全–>安全引导配置–>按F10接受 3.把旧支持 启用,安全引导 禁用 按F10接受 4.保存并退出更改 5.重启后看一下引导顺序,如果旧引导源已…

[MySQL] MySQL中的内置函数

本篇文章主要是对MySQL中常见的内置函数进行了详细解释。例如有日期类函数、字符串类函数、数学类函数等等。希望本篇文章会对你有所帮助。 文章目录 一、日期类函数 1、1 使用详解 1、2 实例演示 二、字符串函数 2、1 使用详解 2、2 实例演示 三、数学函数 四、其他函数 &…

Java 实现TCP一对一聊天,UDP协议实现群聊

用TCP编程实现一对一式聊天,并用多线程解决了处于同一线程中的问题。 客户端代码:mport java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.ut…

python深浅拷贝

【 一 】Python 深拷贝和浅拷贝概念理解 个人见解: 浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。 深拷贝,是指重新分配一块内存,创建一个新的对象&…

Axure动态面板控制

首先创建一个项目,拖拽几个矩形喝一个动态面板 然后双击动态面板添加状态state1,state2,state3 然后分别在state1,state2,state3编辑导航对应的内容。 接下来就是添加交互事件,将不同导航对应不同的state. 点击“交互”->鼠标点击->进入交互编辑…