姿态解算之四元数

一、四元数定义
顾名思义,四元数是由四个元构成的数。
这里写图片描述
其中,q0、q1、q2、q3是实数,i、j、k即使互相正交的单位向量,又是虚单位向量。
二、四元数的表达方式
复数式
这里写图片描述
可视为一个超复数,Q的共轭复数记为

矩阵式
这里写图片描述
三、四元数的大小——范数
四元数的大小用四元数的范数来表示:
这里写图片描述
若||Q||=1,则Q称为规范化四元数。
四、四元数的运算

这里写图片描述
1)加法
这里写图片描述
2)乘法
这里写图片描述
——以上来自《惯性导航》
四元数与姿态解算关系
——详细请看《惯性导航》中的9.2.2四元数与姿态阵间的关系 里面涉及到很多公式,我也没有真正看懂。只是明白一个单位四元数可以表示一个旋转。一个坐标系到另一个坐标系的变换可以通过绕一个定义在参考坐标系中的矢量的单次转动来实现,四元数提供了这种数学描述。捷联惯导中的姿态更新实质上是如何计算四元数Q。
其中转换公式如下:
这里写图片描述
从四元数q0-q3转成方向余弦矩阵:
这里写图片描述
再由方向余弦矩阵转换为欧拉角:
这里写图片描述

下面在看看四元数、方向余弦矩阵、欧拉角三者之间的关系吧
欧拉角
欧拉角的定义不仅仅和旋转角度有关系,还和旋转轴的旋转顺序有关系,任何一种旋转顺序都是合法的。根据定义,欧拉角有12种选择顺序(维基),一个物体通过任何一种旋转顺序都可以达到同样的姿态,在各个学科里所以为了统一,航空航天领域规定XYZ为欧拉角的旋转顺序。
欧拉角的定义很直观而且容易理解,也利于我们计算,因为我我们用的惯性器件也是按照单个轴向运动来测量的。定义上的欧拉角还和我们所说的Yaw、Pitch、Roll不是一回事。因为定义上的欧拉角就是刚体绕三个轴的旋转角度,欧拉旋转和外界的东西(参考系)是没有关系的。Yaw、Pitch、Roll是载体相对于参考系来说的。因为选定了参考系为地球,这样就产生了Gimbal Lock(万向节死锁)。这个我也没有弄明白不做什么说明。
方向余弦
一个向量在坐标系中的位置可以用方向余弦表示,也就是这个向量分别到三个坐标轴的夹角余弦值,实际上就是这个向量到各个坐标轴的投影啦。所以推广到载体坐标系和参考坐标系当中,我们就有了载体坐标轴xyz分别与参考轴XYZ的方向余弦。
三者的关系:
这里写图片描述
通过比较上述等式的各个元素,四元数可以直接用欧拉角或余弦表示,同样欧拉角也可用方向余弦或四元数表示。
用方向余弦表示四元数:
这里写图片描述
用欧拉角直接表示四元数:
这里写图片描述
用方向余弦表示欧拉角:
这里写图片描述

上面这些就是姿态解算用到的四元数及四元数求解欧拉角的方法了。基本思路是四元数—>方向余弦—>欧拉角。这样就又有问题了四元数的q0-q3数据来源是什么呢?又是如何填充q0-q3呢?(这个下次在继续搬砖吧)

### MPU6050 使用 DMP 进行姿态并获得四元数 #### 原理概述 MPU6050 的 DMP (Digital Motion Processor) 是一种嵌入式的协处理器,能够独立处理来自传感器的数据流。DMP 可以执行复杂的运动融合法而不需要主机微控制器的干预。对于姿态而言,DMP 能够直接提供经过校准后的四元数值,这些值代表了设备的空间方向。 当启用 DMP 后,该模块会自动读取内部陀螺仪和加速计数据,并利用内置法计出精确的姿态信息——通常是以四元数形式表示[^1]。四元数是一种用于描述三维空间中的旋转的有效工具,在避免万向锁问题方面优于传统的欧拉角表达方式[^2]。 #### 示例代码实现 为了展示如何配置 MPU6050 并从其 DMP 获取四元数输出,以下是 Python 和 Arduino C++ 两种不同平台下的示例程序: ##### Python 实现(基于 `mpu6050` 库) ```python import smbus from mpu6050 import mpu6050 sensor = mpu6050(0x68) def setup(): sensor.dmp_initialize() def loop(): packet = sensor.get_integrated_dmp_data() q_w, q_x, q_y, q_z = packet['quaternion'] print(f'Quaternion: w={q_w}, x={q_x}, y={q_y}, z={q_z}') ``` ##### Arduino C++ 实现(基于 I2CdevLib 库) ```cpp #include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" MPU6050 accelgyro; uint8_t dmpPacketSize; void setup() { Serial.begin(9600); while (!Serial); Wire.begin(); accelgyro.initialize(); devStatus = accelgyro.dmpInitialize(); if (devStatus == 0) { dmpPacketSize = accelgyro.dmpGetFIFOPacketSize(); fifoCount = accelgyro.getFIFOCount(); } } void loop() { uint8_t *fifoBuffer; if (accelgyro.dmpGetCurrentFIFOPacket(fifoBuffer)) { Quaternion q; accelgyro.dmpGetQuaternion(&q, fifoBuffer); Serial.print("w:"); Serial.print(q.w); Serial.print("\tx:"); Serial.print(q.x); Serial.print("\ty:"); Serial.print(q.y); Serial.print("\tz:"); Serial.println(q.z); } } ``` 上述两段代码展示了初始化 MPU6050 设备以及周期性地请求最新的四元数更新的过程。Python 版本依赖于第三方库来简化通信过程;Arduino 则更接近底层硬件接口编程,提供了更多控制选项。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值