MPU9255移植DMP到LPC & 上电后数据规律性变化15秒后才稳定的原因
很久之前买了两块MPU9250 模块名称是GY-91,拿到手之后各种尝试都无法读取,一番debug之后发现这芯片竟然不是MPU9250而是MPU9255 芯片id=0x73 。无语.... 后来就把这件事先放下了,最近又把它拿了出来,打算把官方的DMP库移植过来,因为之前用过MPU6050的DMP库 发现经过DMP解算出来的波形非常好,响应速度也很快,所以就打算把MPU9255也用DMP库来驱动。
结果嘛,当然是成功啦。。。不过浪费了我四五天时间,各种问题。为了防止以后再踩同样的坑,现在把它来总结一下!
首先是从官网下载最新版本的DMP例程 motion_driver_6.12 ,我是基于里面对STM32F4的例程进行的移植 最后移植到了LPC4337上
需要的文件不多 下面这些就足够啦
接下来修改了头文件 连接了一些定义 大功告成~
调试到 0 error我还激动了一小会QAQ 。
定义部分我采用的是MPU9250的定义 因为这两个传感器相差无几
修改了WHO_I_AM_I 为0x73
开心的上电、启动
首先第一个问题是初始化之后经常跳到 堆栈\内存溢出中断 中去,说明有内存溢出了
经过排查是 DMP_FEATURE_TAP| DMP_FEATURE_ANDROID_ORIENT| 这两个功能造成的 查询了一下百度
驱动程序 DMP MAP 支持包括:
a) DMP_FEATURE_LP_QUAT: 这是一个低功率 (陀螺角) 三个轴四元数从 200 hz 内DMP 的陀螺仪数据计算。b) DMP_FEATURE_6X_LP_QUAT: 这是六轴传感器融合输出从 200 hz 内 DMP 的陀螺仪和加速度计的数据计算出来的低功耗。
c) DMP_FEATURE_TAP: 这是水龙头的在哪里一个可以检测等单水龙头双击) 或方向水龙头事件和意义基本功能的"龙头,"手势功能。
d) DMP_FEATURE_ANDROID_ORIENT: T他的特点是执行情况作为与谷歌运动设备驱动程序兼容的显示方向。此功能包括一个状态机的计算显示方向。
e) DMP_PEDOMETER: 这是一步计数功能,一直是在和上主处理机同时 DMP 运行提供动
力。运动驱动库可以重置计步器步计数值,查询的步行时间,并返回步骤数。还有 7 天
的滞后时间步骤之前更新一步数和步行的时间,以提高精度和尽量减少虚假检测。只要启用了 DMP,总是启用此功能。
f) DMP_FEATURE_GYRO_CAL: 此功能启用时将校准陀螺仪偏差,只要设备中没有运动状态
超过 8 秒钟。g) DMP_FEATURE_SEND_RAW_ACCEL: 将原始加速度计数据添加到 FIFO 和加速度计数据的是芯片坐标
h) DMP_FEATURE_SEND_RAW_GYRO: 将原料陀螺数据添加到 FIFO。陀螺仪坐标是芯片坐标。i) DMP_FEATURE_SEND_CAL_GYRO: 将校准的陀螺数据添加到 FIFO。不能使用与
DMP_FEATURE_SEND_RAW_GYRO 的组合。输出是在设备框架或身体框架而不是芯片框架中。
手册上有这个介绍
3轴低功率四元数 - 仅陀螺四元数。启用此功能后,将以200Hz的频率整合陀螺仪数据,同时以用户请求的速率将传感器融合数据输出到FIFO。 200Hz积分将允许更准确的传感器融合数据。在MD6中,如果启用此功能,驱动程序会将3轴四元数推入MPL库,MPL将处理加速度和罗盘集成。
6轴低功率四元数 - 陀螺仪和加速四元数。与3轴LPQ类似,以200Hz采样速率集成加速度和陀螺仪将以用户请求的速率输出到FIFO。 3轴LPQ和6轴LPQ是互斥的,不应同时运行。如果启用,则可以将6轴四元数推入MPL库,MPL将处理9轴的罗盘集成。
方向手势识别 - 使用传感器数据检测设备方向是否有纵向,横向,反向纵向和反向方向的变化。非常依赖于方向矩阵。
点击手势识别 - 设备上的多方向点击检测。此功能将让用户知道检测到哪个轴位置或负值。它可以检测多达4个多抽头.PSP可用于配置此功能的阈值,死区时间和分接头数。
计步器手势识别 - 简单的计步器,提供步数和时间戳。此功能会自动启用,但在检测到连续5秒的步骤后才会触发。 5秒钟后,计数和时间戳将开始,数据可以从DMP存储器中读出。
DMP中断 - 可以将中断配置为在准备好传感器数据(即FIFO输出速率)时,或者在检测到点击或方向手势时生成
这两个开关定义是用作敲击次数和方向识别支持安卓设备的,然后我追踪到了这个功能的实现,发现了问题所在:
static int decode_gesture(unsigned char *gesture)
{
unsigned char tap, android_orient;
android_orient = gesture[3] & 0xC0;
tap = 0x3F & gesture[3];
if (gesture[1] & INT_SRC_TAP) {
unsigned char direction, count;
direction = tap >> 3;
count = (tap % 8) + 1;
if (dmp.tap_cb)//这是一个函数指针 指向了空 所以访问它可能造成溢出
dmp.tap_cb(direction, count);
}
if (gesture[1] & INT_SRC_ANDROID_ORIENT) {
if (dmp.android_orient_cb)//这也是一个函数指针 指向了空 所以访问它可能造成溢出
dmp.android_orient_cb(android_orient >> 6);
}
return 0;
}
发现了两个指向NULL的函数空指针,这两个指针才是造成我这次溢出的根本原因 屏蔽掉之后就好了。
仔细观察发现这是敲击检测功能的解码函数,其中一个是给Android的 我们根本用不到所以直接屏蔽掉就好,如果需要使用dmp自带的敲击检测 只需要给dmp.tap_cb这个函数指针写实现并添加到初始化就可以了。
数据不在溢出之后我才开始观察波形,结果竟然发现波形前15s出现了漂移,一个轴从初始化之后的0逐步增加到了180。(另一种自检方式造成了一个周期性的奇怪的波形,也是大约15s后稳定恢复功能)。这个问题困扰了我很久。
后来我尝试屏蔽了自检 run_self_test(); 虽然还在漂移,但数据稳定了很多,没有周期波形了,最后也在15s左右变成了稳定值,晃动传感器的时候能反映传感器的动作,虽然能用了但是还是肯定有问题的。
第二天,通过查阅资料怀疑可能是初始化的时候dmp方向初始话有问题,因为我直接给了默认设置。而实际上的位置可能和预设的位置颠倒。
于是我直接将MPU9250模块翻了过来。数据就正常了。。。。而且是立刻就稳定了下来和我之前用的dmp是一致的。
原来是我MPU9255放的姿态和预设的初始姿态不一致造成的数据开始漂移!
接下来通过修改初始状态位置矩阵
static signed char gyro_orientation[9] = { 1, 0, 0,
0, 1, 0, //正常设置
0, 0, 1 };
为
static signed char gyro_orientation[9] = { 0, 1, 0,
1, 0, 0, //颠倒设置
0, 0, -1 };
计算原理是:
这样我们就得到了与我的传感器对应的实际的XYZ轴向 替换后大功告成!MPU9255驱动完成。
通过上位机实时反馈,可以看到模型能随着传感器的运动做同样的运动。而且实时性相当不错呢!
最后 把磁力计也驱动起来 使用的库里自带的读取函数mpu_get_compass_reg(compass, ×tamp); 直接就可以用~完美~
总结起来就是认真读手册,读它的例程,就轻松能完成移植啦~