作者:WZY
时间 2013 年 2 月 2 日 11:57:37
项目进展了这么久第一次写日志,总结一下这一段时间的经验。首先,我通过李想的 stm32 教学视频对 stm32 进行了简单的了解,发现 stm32 用起来比 51 都方便,原来一直被“arm 难学”误导了,单片机只是工具,真正编算法才是难点,所以以后在做项目时不应该过分考 虑单片机是否好用这个问题,只要适合项目的单片机就应该拿来用。
李想视频里编译环境是 MDK,所以在编程时一直使用 MDK 编译,感觉和学 51 时用的 keil 一模一样,比较好上手。由于项目所要做的第一步是要做姿态解算,所以在初步了解 stm32 原理以后,就开始从 MPU6050 传感器读数据。MPU6050 是一个集成了加速度计和陀螺仪的 传感器,使用 I2C 和单片机进行通信,总体来说读取数据还是比较简单的。但是也遇到一些 比较烦人的问题,卡了好久。一个是变量类型搞错了
这是一段读取 MPU6050 陀螺仪 x 轴数据的程序,先通过 I2C 函数把陀螺仪 X 轴数据的低 8 位和高 8 位读取出来,分别放入 BUF[0]和 BUF[1]中,在通过移位把两个数据合成一个数据传 入 G_X 变量,G_X 是一个 short 型变量,而 imu_measure.gx 是一个 double 型变量,编译器 编译是自动把 G_X 转成 double 型除以 16.4 赋值给 imu_measure.gx。曾经犯过一个错误就是 把 BUF 数组数据相合后直接除以 16.4 然后赋值给 imu_measure.gx,结果通过串口传回来的 数据就出现了错误。以后要避免这种错误。
在新添加文件后要记着把文件添加进工程,否则编译会出错。 至于为什么除
以 16.4,参考《MPU-6050 寄存器映射》第 32 页
在 MPU6050 初始化时把 Full Scale Range 设置为 ±2000°/s,所以灵敏度为 16.4 LSB/°/s, 所以在读出寄存器值的基础上除以 16.4 就是角速度。
而对于加速度,设置为±8g,灵敏度为 4096,所以在读出值的基础上除以 4096 就是加速 度,单位为 g,再乘以 9.8 单位就是 m/s^2,所以 8192/9.8=835.066,除以这个值就是加速度 (m/s^2)。同理,在理解 MPU6050 初始化的设置时,参考这本手册即可。
要设置为+-4g 即 0000100=0x08
还有一个就是 extern 变量的使用。正确的用法是在初始化的地方定义(函数外定义,如 果在函数内则会是局部变量),然后在 External_Variable.h 文件中用 extern 关键字再定义一遍 (注意,这里不要赋值),告诉编译器,这个变量在其他地方已经定义过,直接使用即可。 然后需要用到全局变量的文件开头进行#Include “External_Variable.h”,就可以了。
MPU6050 传感器初始化时,使用 I2C 总线函数即可,例如:
Single_Write(MPU6050_Addr,PWR_MGMT_1, 0x00);
//解除休眠状态
分别写入 MPU6050 地址,寄存器地址,和写入的值即可。出现一个问题就是 MPU6050 的 I2C 地址在手册上写的是 7 位固定,为 0x68(1101000),但有的例程上给的是直接写入 0x68, 实际在使用过程中写入 0xD0(11010000)才有反应,即 7 为固定位加一位硬件设置的地址 位(BIT0=0)。
在 MPU6050 初始化后就可以不停的读取传感器值进行姿态解算了。在姿态解算前,我先 对四元数进行了初始化,即飞控板在静止状态下通过加速度计解算欧拉角,再通过四元数公 式计算(即函数 quat_init())。其实感觉这里不初始化也可以,因为姿态解算速度很快,第 一次的值对以后影响并不大。
随后就开始真正的姿态解算了,首先要对读取的传感器值进行移动均值滤波。定义了
Filter_ACC 结构体,先把读取值加到这个结构体变量里,每加一次,积分标记位加 1。当定 时器中断触发。姿态解算周期到来时,进入 if(IMUupdate_flag == TRUE){}里面求平均值并对 变量清零,完成移动均值滤波。
滤波过后,就开始用 IMUupdate()函数进行解算,这个函数是参考
http://www.amobbs.com/forum.php?mod=viewthread&tid=5492189&highlight=??·%
E8????ˉ?ˉ?
在实际编程中发现,在输入 IMUupdata()函数前如果角速度不除以一个比例系数,解算出 的姿态角就会出现超调或者,但是如果系数过大就会出现调不够的现象,所以实验的几次以 后找到了一个经验值。
进行使用的,基本原理是把加速度计解算出的姿态和上次解算出的姿态(认为是正确的)进 行向量叉乘,得到两个向量的差,然后把这个差乘以比例系数和角速度数据融合得到认为是 正确的角速度里,将正确的角速度代入到龙格库塔方程里推算出当前正确的姿态。方程里所 需的半周期 halfT 是由 TIM2 中断产生的(TIM2 每 2ms 中断一次,即 T=2ms,halfT=1ms)。 在这个过程里还引入里积分环节来消除静差。
比如陀螺 X 轴读取时始终有个 -32 °/s 的误差存在,在姿态解算后,滚转角始终不是平 的,会有一个误差,但是会发现这个误差会逐渐减小,这就是积分环节在起作用。
其实在一开始,通过上位机看 stm32 姿态解算的状态并不是很好,最后发现是 uart1 传输 函数里面有个 Delayms(1),晕死,本来对速度的要求就很高,结果每传输一次就延时 1ms, 不出问题才怪。结果吧这个延时函数去掉以后干脆不出数据了,卡了好久,发现是自己思维 进入死胡同了!忘记串口传输完毕是要等待传输结束的:
结果加上这句话后形式一片大好~顺利的解算出了姿态,而且效果很好。
这里使用的上位机软件是阿莫论坛上一位大虾提供的,很好用,不足的地方就是传送速率过 快会卡,不能迅速显示,不过功能还是挺强大的,可以数据保存截图什么的。
下一步的任务就是使用 HMC5883 对偏航角进行修正,由于加速度计不能读出偏航角的数 据,所以偏航角由于陀螺仪误差的缘故会一直向一个方向偏。再然后就是读取气压高度。
2013 年 2 月 3 日 23:14:52
今天主要解决的是全姿态罗盘。说来很惭愧,大部分时间卡在一个很细小的问题上,就是 HMC5883L 的 I2C 总线地址上。一开始翻看 MWC 的程序,磁阻仪的地址上 0x1E,于是用 I2C 向磁阻仪写入 0x1E,结果一点反应都木有啊~试了各种方法,一度以为是 MPU6050 的 I2C 辅助位没有设置好(其实设置是没问题的,让 MPU6050 的 I2C_Master 功能 disable,ByPass 功能打开,主芯片可以直接控制 HMC5883L,这两个寄存器分别在 0x37 和 0x6A 两个寄存器