MPU6050姿态解算1-DMP方式
MPU6050的姿态解算方法有多种,包括硬件方式的DMP解算,软件方式的欧拉角与旋转矩阵解算,软件方式的轴角法与四元数解算。本篇先介绍最易操作的DMP方式。
MPU6050基本功能
3轴陀螺仪
陀螺仪,测量的是绕xyz轴转动的角速度,对角速度积分可以得到角度。
3轴加速度计
加速度计,测量的是xyz方向受到的加速度。在静止时,测量到的是重力加速度,因此当物体倾斜时,根据重力的分力可以粗略的计算角度。在运动时,除了重力加速度,还叠加了由于运动产生的加速度。
DMP简介
就是MPU6050内部的运动引擎,全称Digital Motion Processor,直接输出四元数,可以减轻外围微处理器的工作负担且避免了繁琐的滤波和数据融合。Motion Driver是Invensense针对其运动传感器的软件包,并非全部开源,核心的算法部分是针对ARM处理器和MSP430处理器编译成了静态链接库,适用于MPU6050/MPU6500/MPU9150/MPU9250等传感器。
四元数转欧拉角
四元数可以方便的表示3维空间的旋转,但其概念不太好理解,可以先类比复数,复数表示的其实是2维平 ...
欧拉角旋转
欧拉角是一种表示三维旋转的描述方法,欧拉角的计算需要借助旋转矩阵,关于旋转矩阵的知识可先参考前两篇文章:3维旋转矩阵推导与助记与3维旋转矩阵推导与助记-补充篇
欧拉角旋转静态定义对于在三维空间里的一个参考系,任何坐标系的取向,都可以用三个欧拉角来表现。
参考系又称为实验室参考系,是静止不动的,可以先简单的理解理解为大地坐标系,也称惯性坐标系。
坐标系则固定于刚体,随著刚体的旋转而旋转,比如飞行器自身的坐标系,也称载体坐标系。
如上图为一种ZYZ顺序旋转的欧拉角示意图:
设蓝色的xyz-轴为惯性系的参考轴,即大地坐标系的3个轴。
设红色的XYZ轴为载体系的参考轴,即飞行器坐标系的3个轴。
称xy-平面与XY-平面的相交为交点线,用英文字母N表示。
图中的角度符号:
α是x-轴与交点线的夹角,载体坐标系先绕Z轴旋转了α角度(范围0~2Pi弧度)。
β是z-轴与Z-轴的夹角,载体坐标系又绕当前的Y轴旋转了β角度(范围0~Pi弧度)。
γ是交点线与X-轴的夹角,载体坐标系又绕当前的Z轴旋转了γ角度(范围0~2Pi弧度)。
这里角度的正负是按照右手定则,如右手大拇指指向z-轴,四 ...
3维旋转矩阵推导与助记-补充篇
这篇文章是对上篇3维旋转矩阵推导与助记的补充,上篇介绍的旋转矩阵是在同一个坐标系下,向量旋转所对应的旋转矩阵,本篇分析坐标系旋转对应的旋转矩阵。
平面二维旋转如下图,xy坐标系中,有一向量OP,其坐标可表示为(x,y),该向量与X轴夹角为α。然后,坐标系绕原点逆时旋转了β角度,形成新的坐标系x’y’,此时OP在新的坐标系中的坐标表示为(x’,y’),根据几何关系,可以得到如下推导,最终得到绿色虚框的旋转矩阵。对比上篇文章的旋转矩阵,可以发现:本篇坐标系旋转的旋转矩阵与上篇向量旋转的旋转矩阵正好是转置的关系(实际上是逆矩阵,因为正交阵的逆矩阵与转置矩阵相同),因为这两种旋转本质上是相对运动,互为逆过程。
三维旋转同样,三维情况下的坐标系旋转的旋转矩阵,与上篇向量旋转的旋转矩阵也是逆矩阵的关系,下面是绕3种轴的情况。
绕Z轴
绕Y轴
绕X轴
3维旋转矩阵推导与助记
旋转矩阵的应用范围比较广,是姿态变换,坐标变换等的基础。本篇先介绍旋转矩阵的推导过程与助记方法。
平面二维旋转如下图,XY坐标系中,向量OP旋转β角度到了OP’的位置:
根据三角函数关系,可以列出向量OP与OP’的坐标表示形式:
对比上面个两个式子,将第2个式子展开:
用矩阵形式重新表示为:
这就是二维旋转的基本形式,中间的矩阵即二维旋转的旋转矩阵,坐标中的某一向量左乘该矩阵后,即得到这个向量旋转β角后的坐标。
三维旋转三维旋转可借助二维旋转来理解,由于三维空间中可以任意轴旋转,为方便分析与使用,只考虑绕X、Y、Z轴的旋转。
绕Z轴参照上面的图,添加一个Z轴,则上面的二维旋转实际上就是绕Z轴的三维旋转
照搬上面的推导公式,并添加Z坐标的变换关系(实际是没有变),然后改写成矩阵形式,红色方框即为绕Z轴的旋转矩阵。
绕Y轴绕Y轴旋转同理,这里直接改变坐标轴的符号表示,注意坐标顺序要符合右手系,我这里用颜色区分了不同的轴。最终的矩阵形式要进一步改写成XYZ的顺序。红色方框即为绕Y轴的旋转矩阵。
绕X轴参照绕Y轴的推导,可以得到绕X轴的结果。红色方框即为绕 ...
从IIC实测波形入手,搞懂IIC通信
玩单片机的朋友都知道IIC通信这个工具,但好多人只是会用,内部的原理不求甚解,或是想要了解其原理,但却对抽象的时序描述一头雾水。本文将从实测的IIC波形入手,带你看到真实的IIC样子,进而去理解IIC的通信原理。
IIC基础知识首先复习一下IIC基础知识,这部分看不懂的请先带着疑问,然后我们通过分析IIC的真实波形,这些疑问可能就豁然开朗了~
IIC是什么IIC(Inter Integrated Circuit,集成电路总线)是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU (单片机)与IIC模块之间、IIC模块与IIC模块之间进行双向传送。
IIC的一些特点:
IIC是半双工,而不是全双工
IIC是真正的多主机总线,(对比SPI在每次通信前都需要把主机定死,而IIC可以在通讯过程中,改变主机),如果两个或更多的主机同时请求总线,可以通过冲突检测和仲裁防止总线数据被破坏
起始和终止信号都是由主机发出的,连接到I2C总线上的器件,若具有I2C总线的硬件接口,则很容易检 ...
FreeRTOS例程4-串口DMA收发不定长数据
基础知识点DMADMA(Direct Memory Access),即直接内存存储,在一些数据的传输中,如串口、SPI等,采用DMA方式,传输过程不需要CPU参与,可用让CPU有更多的时间处理其他的事情。
STM32F4的DMA通道选择如下:
接下来的程序思路如下:
编程要点DMA发送串口DMA发送配置由于是发送不定长的数据,先不需要配置发送的长度,在每次的发送时,再配置。
1234567891011121314151617181920212223242526272829303132333435363738394041//=======================================//串口DMA发送配置//=======================================void dma_uart_tx_init(){ DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 DMA_DeInit( ...
FreeRTOS例程3-串口中断接收不定长的数据与二值信号量的使用
FreeRTOS下,串口中断与二值信号实现不定长数据接收。
基础知识点串口中断种类串口中断属于STM32本身的资源,不涉及到FreeRTOS,但可与FreeRTOS配合使用。
串口接收中断中断标志为:USART_IT_RXNE,即rx none empty,串口只要接收到数据就触发中断,如果是接收一个字符串,则每接收到一个字符就触发一次中断。
串口空闲中断中断标志为:USART_IT_IDLE,idle即空闲的意思,串口空闲时触发的中断,当然也不是说串口空闲时就一直触发中断,而实在每个连续的接收完成后,触发中断,如果是接收一个字符串,则接收完整个字符串后,触发一次中断。
所以,这两个中断可以配合使用,串口接收中断实时接收数据,接受完一串数据后,空闲中断被触发,就可以对接收的一串数据分析处理了。这种方式不需要知道每次字符串的具体长度,因而可以接收不定长的串口数据。
信号量FreeRTOS中的信号量是一种任务间通信的方式,信号量包括:二值信号量、互斥信号量、计数信号量,本次只使用二值信号量。
二值信号量二值信号量只有两种状态,可以先通俗的理解为它就是个标志,0或1。信号量用于任务间的同 ...
C语言字符串相关函数使用示例 strtok_r strstr strtok atoi
通过一个实际小应用,记录C语言中4个字符串操作相关的函数及其用法:
strtok_r
strstr
strtok
atoi
问题引出先贴一段变量定义:
1char str[] = "led,100,0,80,15";//一个字符串,第一个逗号前的字符串设定为某个命令,后面的是参数
假设某种应用场景,接收到一串字符串,如上面的str[] = "led,100,0,80,15",以逗号为分割,假设该字符串的第一个字符串led表示一种指令,如打开led,后面的数字表示参数,如不同led的亮度值。
那么,计算机该如何区分得到各个字符串,并且获得对应的数值型参数呢?
下面就介绍C语言中的几种函数来解决这个问题。
函数介绍与示例strtok_r首先需要将字符串切分为指令和参数形式,需要用到strtok_r函数。
函数定义:
1char *strtok_r(char * __restrict__ _Str, const char * __restrict__ _Delim, char ** __restrict__ __last);
参数:原始字 ...
C语言将float拆分为4个hex传输与重组
问题引出实际的编程应用中,特别是数据传输通信等场合,需要传输float等类型的数据,而常用的数据传输形式一般为hex格式或字符串格式,通常我们会选用hex格式,更接近计算机的2进制,而这种传输方式就需要将float转换为hex格式了。
在计算机中,float占用4个字节,因此可以考虑将float拆分为4个hex格式的16进制数,完成数据传输后,接收方再将4个hex重组为float即可还原出原来的数据,这有点像数据的编码和解码的意味。
分步测试float型的2进制形式float的计算机中占用4个字节,具体是如何在计算机中存储的可以参考上一篇笔记:C语言打印数据的二进制格式-原理解析与编程实现,上次的int数据打印2进制的函数这里也可以用来测试,只需将参数类型改成float:
12345678910111213141516171819void printf_bin(float num)//注意这次这里的参数类型改成了float{ int i, j, k; unsigned char *p = (unsigned char*)&num + 3; for (i = 0; ...
C语言打印数据的二进制格式-原理解析与编程实现
问题引出C语言中,在需要用到16进制数据的时候,可以通过printf函数的%x格式打印数据的16进制形式。在某些位标记、位操作的场合,需要用到2进制格式的数据,但printf函数不能输出2进制格式,虽然可以通过使用itoa或_itoa的方法转为2进制的字符串打印,但显示的长度是不固定的,无法显示有效数位前面的0。
例如:现在需要打印数字258的2进制格式,且需要将32位全部显示出来,即想要得到结果00000000 00000000 00000001 00000010,而使用_itoa的方法和打印结果为:
1234int a = 258; char s[32];_itoa(a, s, 2);printf("a --> %s\n", s);
1a --> 100000010
不是我们想要的格式!
数据存储原理探析那要怎么办呢?自己写个小程序吧,思路如下:
首先弄清楚数据在计算机中是如何存储的,对应int型数字,在32或64位计算机中都占4个字节,而计算机中的数据存储是以字节(Byte)为单位,1个字节包含8个位(bit),例如,数字258的16进制形 ...