STM32 HAL库移植MPU6050 DMP库(跟着做就能成功)

STM32移植MPU6050 DMP库(跟着做就能成功)

  • 0.前言
  • 一、使用CubeMX建立工程
  • 二、移植DMP库
    • 修改:
      • 注意:
    • 使用
  • 三、总结


0.前言

  最近捣鼓FreeRTOS时需要使用一个MPU6050姿态传感器,到处扒拉例程时发现各式各样的教程都不太满意,感觉差点意思,所以自己慢慢摸索整了一个移植教程,有疏漏的地方还请希望各位读者进行指正。

一、使用CubeMX建立工程

  有关的理论部分这里就不进行赘述了,此篇文章目的是为了实现STM32F103RCT6驱动MPU6050传感器,并通过串口发送解析完成的数据,在I2C1总线上挂载MPU6050外设和OLED屏幕,试试读取并显示数据。
以下是CubeMX的配置:
使能I2C1:
在这里插入图片描述
使能UART1串口:
在这里插入图片描述
时钟及其他外设请按需使能,这里笔者额外添加了FreeRTOS的CMSIS_V2版本,实际并未使用相关组件,可忽略。

二、移植DMP库

MotionDriver_V6.1下载:https://os.mbed.com/users/oprospero/code/MotionDriver_6_1
下载后会得到一个基于MSP430的工程,主要需要移植以下文件:
在这里插入图片描述
需要将红框中的文件添加进工程,motion_driver_test.c为测试程序,不需要添加,不过可以仿照其编写自己的测试程序。

修改:

在官方的MSP430相关的代码基础上进行修改,首先在inv_mpu.h中添加所需要的宏,并排除掉影响不大的报错:
在这里插入图片描述
其中STM32_MPU6050为后续需要使用的自定义宏,MPU6050为DMP库中指定的陀螺仪型号,下方的结构体没有使用到,添加此参数排除报错。

在inv_mpu.c中修改原本的宏定义,并实现自己的相关函数:
在这里插入图片描述
在这里插入图片描述

如果未使用FreeRTOS则将毫秒延时定义为HAL_Delay()函数,并去除此文件中的reg_int_cb()部分(未使用)。

同样在inv_mpu_dmp_motion_driver.c文件中也修改为自己的操作函数,并将__no_operation()函数改为__NOP():
在这里插入图片描述
在这里插入图片描述
至此,DMP的初步移植工作已完成,能够编译通过。

注意:

经过笔者实测,如果想要成功读取传感器数据,还需要把inv_mpu.c中的MPU6050设备地址修改为0xD0,否则会找不到设备。
在这里插入图片描述

使用

参考motion_driver_test.c文件中的相关流程,新建my_mpu6050.c和my_mpu6050.h文件,实现MPU初始化和数据获取。
my_mpu6050.c:

#include "my_mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "math.h"/* The sensors can be mounted onto the board in any orientation. The mounting* matrix seen below tells the MPL how to rotate the raw data from thei* driver(s).* TODO: The following matrices refer to the configuration on an internal test* board at Invensense. If needed, please modify the matrices to match the* chip-to-body matrix for your particular set up.*/
static signed char gyro_orientation[9] = {-1, 0, 0,0,-1, 0,0, 0, 1};/* These next two functions converts the orientation matrix (see* gyro_orientation) to a scalar representation for use by the DMP.* NOTE: These functions are borrowed from Invensense's MPL.*/
static unsigned short inv_row_2_scale(const signed char *row)
{unsigned short b;if (row[0] > 0)b = 0;else if (row[0] < 0)b = 4;else if (row[1] > 0)b = 1;else if (row[1] < 0)b = 5;else if (row[2] > 0)b = 2;else if (row[2] < 0)b = 6;elseb = 7;      // errorreturn b;
}static unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx)
{unsigned short scalar;/*XYZ  010_001_000 Identity MatrixXZY  001_010_000YXZ  010_000_001YZX  000_010_001ZXY  001_000_010ZYX  000_001_010*/scalar = inv_row_2_scale(mtx);scalar |= inv_row_2_scale(mtx + 3) << 3;scalar |= inv_row_2_scale(mtx + 6) << 6;return scalar;
}static int run_self_test(void)
{int result;long gyro[3], accel[3];result = mpu_run_self_test(gyro, accel);if (result == 0x3) {/* Test passed. We can trust the gyro data here, so let's push it down* to the DMP.*/float sens;unsigned short accel_sens;mpu_get_gyro_sens(&sens);gyro[0] = (long)(gyro[0] * sens);gyro[1] = (long)(gyro[1] * sens);gyro[2] = (long)(gyro[2] * sens);dmp_set_gyro_bias(gyro);mpu_get_accel_sens(&accel_sens);accel[0] *= accel_sens;accel[1] *= accel_sens;accel[2] *= accel_sens;dmp_set_accel_bias(accel);} else {return -1;}return 0;
}int MPU6050_DMP_init(void)
{int ret;struct int_param_s int_param;//mpu_initret = mpu_init(&int_param);     if(ret != 0){return ERROR_MPU_INIT;}//设置传感器ret = mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL);if(ret != 0){return ERROR_SET_SENSOR;}//设置fiforet = mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);if(ret != 0){return ERROR_CONFIG_FIFO;}//设置采样率ret = mpu_set_sample_rate(DEFAULT_MPU_HZ);if(ret != 0){return ERROR_SET_RATE;}//加载DMP固件ret = dmp_load_motion_driver_firmware();if(ret != 0){return ERROR_LOAD_MOTION_DRIVER;}//设置陀螺仪方向ret = dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));if(ret != 0){return ERROR_SET_ORIENTATION;}//设置DMP功能ret = dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_TAP |DMP_FEATURE_ANDROID_ORIENT | DMP_FEATURE_SEND_RAW_ACCEL | DMP_FEATURE_SEND_CAL_GYRO | DMP_FEATURE_GYRO_CAL);if(ret != 0){return ERROR_ENABLE_FEATURE;}//设置输出速率ret = dmp_set_fifo_rate(DEFAULT_MPU_HZ);if(ret != 0){return ERROR_SET_FIFO_RATE;}//自检ret = run_self_test();if(ret != 0){return ERROR_SELF_TEST;}//使能DMPret = mpu_set_dmp_state(1);if(ret != 0){return ERROR_DMP_STATE;}return 0;
}int MPU6050_DMP_Get_Date(float *pitch, float *roll, float *yaw)
{float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;short gyro[3];short accel[3];long quat[4];unsigned long timestamp;short sensors;unsigned char more;if(dmp_read_fifo(gyro, accel, quat, &timestamp, &sensors, &more)){return -1;}if(sensors & INV_WXYZ_QUAT){q0 = quat[0] / Q30;q1 = quat[1] / Q30;q2 = quat[2] / Q30;q3 = quat[3] / Q30;*pitch = asin(-2 * q1 * q3 + 2 * q0 * q2) * 57.3; // pitch*roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2 * q2 + 1) * 57.3; // roll*yaw = atan2(2 * (q0 * q3 + q1 * q2), q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3) * 57.3; // yaw}return 0;
}

my_mpu6050.h:

#ifndef __MY_MPU6050_H__
#define __MY_MPU6050_H__#define ERROR_MPU_INIT      -1
#define ERROR_SET_SENSOR    -2
#define ERROR_CONFIG_FIFO   -3
#define ERROR_SET_RATE      -4
#define ERROR_LOAD_MOTION_DRIVER    -5 
#define ERROR_SET_ORIENTATION       -6
#define ERROR_ENABLE_FEATURE        -7
#define ERROR_SET_FIFO_RATE         -8
#define ERROR_SELF_TEST             -9
#define ERROR_DMP_STATE             -10#define DEFAULT_MPU_HZ  100
#define Q30  1073741824.0fint MPU6050_DMP_init(void);
int MPU6050_DMP_Get_Date(float *pitch, float *roll, float *yaw);#endif

然后在主函数中对数据进行获取即可:
在这里插入图片描述
到此即移植完成。
在这里插入图片描述

三、总结

  本文中还存在一些优化空间,例如没有使用DMA进行数据传输,笔者在使用DMA时出现I2C总线读写超时的问题,经过多方查找也没有解决,猜测是每次读写的间隔太小导致,有一种办法是调用HAL_I2C_Mem_Transfer_DMA()后使用while()阻塞等待传输完成信号,不过这样就和直接使用I2C没有区别了,所以最后也没有使用。除此之外也没有对偏航角进行补偿,有需求的还需要自己花时间研究。
  后续打算使用拓展卡尔曼进行姿态解算,所以本篇暂时先做到这里。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

游戏 CP 专访| InOutPath 技术干货分享!

“ 编辑语&#xff1a;STEAM 上的 3D 解密游戏《InOutPath》以其清新的画面&#xff0c;独特的玩法&#xff0c;受到了广大 STEAM 玩家&#xff0c;以及 Cocos 开发者们的关注。今天有幸邀请到了这款游戏的开发商&#xff0c;为大家做一次技术分享。希望能够对在用 Cocos Creat…

【数据结构与算法】(14)基础算法 之AVL 树相关示例 详细代码讲解

目录 3.4 红黑树概述历史红黑树特性 实现插入情况删除情况完整代码小结 3.4 红黑树 概述 历史 红黑树是一种自平衡二叉查找树&#xff0c;最早由一位名叫Rudolf Bayer的德国计算机科学家于1972年发明。然而&#xff0c;最初的树形结构不是现在的红黑树&#xff0c;而是一种称…

关于js [GDOUCTF 2023]hate eat snake

查看页面源代码 发现snake.js文件 打开js文件 第7行定义了游戏的速度this.speed this.oldSpeed speed || 10 ; 全文搜索speed&#xff0c;在第237行发现自增代码this.speed; 注释或者删除自增代码 回到游戏页面 重玩游戏&#xff0c;等待60s即可 得到flag

Swift Combine 使用 handleEvents 操作符调试管道 从入门到精通二十五

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

【微服务】mybatis typehandler使用详解

目录 一、前言 二、TypeHandler简介 2.1 什么是TypeHandler 2.1.1 TypeHandler特点 2.2 TypeHandler原理 2.3 mybatis自带的TypeHandler 三、环境准备 3.1 准备一张数据表 3.2 搭建一个springboot工程 3.2.1 基础依赖如下 3.2.2 核心配置文件 3.2.3 测试接口 四、T…

d3dcompiler_47.dll是什么,电脑出现d3dcompiler_47.dll丢失如何解决

当打开软件时提示“d3dcompiler_47.dll丢失”时&#xff0c;用户通常会看到类似于以下的错误消息&#xff1a; “无法启动此程序&#xff0c;因为计算机中丢失了d3dcompiler_47.dll。尝试重新安装该程序以解决此问题。” “找不到d3dcompiler_47.dll文件&#xff0c;因此应用…

破译一致性难题:Raft日志复制技术及成员变更问题详解

一、日志复制 Raft 算法是一种用于实现分布式系统中一致性状态机复制的共识算法。在 Raft 中&#xff0c;日志复制是保证集群数据一致性的关键机制。每个节点&#xff08;服务器&#xff09;都维护着一个日志&#xff0c;其中包含一系列的日志条目&#xff08;Log Entry&#x…

在 where子句中使用子查询(二)

目录 ANY ANY &#xff1a;功能上与 IN 是没有任何区别的 >ANY &#xff1a;比子查询返回的最小值要大 ALL >AL &#xff1a;比子查询返回的最大值要大 EXISTS() 判断 NOT EXISTS Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209…

Open3D 点云法向量计算与可视化 (25)

Open3D 点云法向量计算与可视化 (25) 一、算法原理二、算法实现三、可视化显示和长度调节一、算法原理 通常计算点云的法向量可以使用以下两种常见的方法: 最小二乘法(Least Squares Method):该方法通过拟合局部表面的平面来计算法向量。对于给定点周围的邻域,可以通过…

Peter算法小课堂—动态规划

Peter来啦&#xff0c;好久没有更新了呢 今天&#xff0c;我们来讨论讨论提高组的动态规划。 动态规划 动态规划有好多经典的题&#xff0c;有什么背包问题、正整数拆分、杨辉三角……但是&#xff0c;如果考到陌生的题&#xff0c;怎么办呢&#xff1f;比如说2000年提高组的…

apache 模式、优化、功能 与 nginx优化、应用

一、I/O模型——Input/Output模型 1.同步/异步 A程序需要调用B程序的某一个功能&#xff0c;A发送一个请求需要B完成一个任务 同步&#xff1a;B不会主动去通知A是否完成需要A自己去问 异步&#xff1a;B会主动通知A是否完成 2.阻塞/非阻塞 A发送一个请求需要B完成一个任务 …

勇宝趣学JavaScript ES6第三章(字符串的拓展)

已经写到系列教程的第三章了&#xff0c;本章节我们一起来探讨字符串的那些事。在我们的日常工作中&#xff0c;经常会用到模板字符串&#xff0c;还有一些字符串的方法&#xff0c;我们今天就来好好的品一品。 谢谢大家的点赞和收藏。 文章目录 一、字符串的方法1.1 charAt和c…

消息队列-RabbitMQ:延迟队列、rabbitmq 插件方式实现延迟队列、整合SpringBoot

十六、延迟队列 1、延迟队列概念 延时队列内部是有序的&#xff0c;最重要的特性就体现在它的延时属性上&#xff0c;延时队列中的元素是希望在指定时间到了以后或之前取出和处理&#xff0c;简单来说&#xff0c;延时队列就是用来存放需要在指定时间被处理的元素的队列。 延…

软考45-上午题-【数据库】-数据操纵语言DML

一、INSERT插入语句 向SQL的基本表中插入数据有两种方式&#xff1a; ①直接插入元组值 ②插入一个查询的结果值 1-1、直接插入元组值 【注意】&#xff1a; 列名序列是可选的&#xff0c;若是所有列都要插入数值&#xff0c;则可以不写列名序列。 示例&#xff1a; 1-2、插…

暑期宅家?计算机专业必看的8部电影!一定要安利给你们!

代码编程看上去枯燥乏味&#xff0c;但也是艺术的&#xff0c;感性的&#xff0c;计算机编程的许多概念被应用于电影中&#xff0c;其中有些非常之酷炫&#xff0c;它们甚至能帮助开发人员理解一些编程概念。 所以今天学姐来给大家推荐几部心中top级的编程人必看电影&#xff0…

matlab倒立摆小车LQR控制动画

1、内容简介 略 54-可以交流、咨询、答疑 2、内容说明 略 摆杆长度为 L&#xff0c;质量为 m 的单级倒立摆(摆杆的质心在杆的中心处)&#xff0c;小车的质量为 M。在水平方向施加控制力 u&#xff0c;相对参考系产生位移为 y。为了简化问题并且保其实质不变&#xff0c;忽…

数据结构:链表的冒泡排序

法一&#xff1a;修改指针指向 //法二 void maopao_link(link_p H){if(HNULL){printf("头节点为空\n");return;}if(link_empty(H)){printf("链表为空\n");return;}link_p tailNULL;while(H->next->next!tail){link_p pH;link_p qH->next;while(q…

抖音视频提取软件使用功能|抖音视频下载工具

我们的抖音视频提取软件是一款功能强大、易于操作的工具&#xff0c;旨在解决用户在获取抖音视频时需要逐个复制链接、下载的繁琐问题。我们的软件支持通过关键词搜索和分享链接两种方式获取抖音视频&#xff0c;方便用户快速找到自己感兴趣的内容。 主要功能模块&#xff1a;…

进程线程信号通道

4> 使用消息队列完成两个进程间相互通信 usr1代码&#xff1a; #include <myhead.h> //定义一个消息类型 struct msgbuf {long mtype;//消息类型char mtext[1024];//消息正文 }; #define MSGSIZE sizeof(struct msgbuf)-sizeof(long) int main(int argc, const char …

物奇ENC算法开关接口修改方法

物奇ENC算法开关接口修改 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)&#xff1f;可加我微信hezkz17, 本群提供音频技术答疑服务&#xff0c;群赠送语音信号处理降噪算法&#xff0c;蓝牙耳机音频&#xff0c;DSP音频项目核心开发资料, 1 配置工具事件接口 2 代…