平衡车 -- MPU6050

🌈个人主页:羽晨同学

💫个人格言:“成为自己未来的主人~” 

传感器原理

此外,用陀螺仪获取x,y,z轴的加速度。

初始化

我们现在对MPU6050进行初始化,MPU6050通过I2C总线与单片机进行通信,通过的是PB8和PB9,并且PB8和PB9需要通过重映射,才可以发挥出I2C总线的功能。

//
// @简介: 对MPU6050进行初始化
//
void App_Mpu6050_Init(void)
{//1. 初始化I2C总线,PB8、PB9 -I2C1//将I2C1的引脚重映射到PB8到PB9RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);//初始化PB8和PB9 - AF_ODRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);}

这个是对I2C1的初始化

	//2. 初始化I2C1// 开启I2C1的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//设置I2C的参数I2C_InitTypeDef I2C_InitStruct = {0};I2C_InitStruct.I2C_ClockSpeed = 400000;//I2C通信速度I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//占空比I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;I2C_Init(I2C1,&I2C_InitStruct);

我们对I2C1的速度设置为40000hz,也就是快速模式,然后选择的I2C的模式是标准I2C模式,占空比为2比1.我们选用快速模式的时候,一般选择的占空比就是2比1的。

寄存器部分

接下来,我们要配置寄存器部分。

所以,我们接下来封装一下读写寄存器的函数。

//
// @简介:写寄存器函数
// @参数 reg - 要写入的寄存器的地址
// @参数 value - 要写入的值
//
static void reg_write(uint8_t reg,uint8_t value)
{uint8_t bytesToSend[] = {reg,value};My_I2C_SendBytes(I2C1,0xd0,bytesToSend,2);
}
//
// @简介:读寄存器函数
// @参数 reg - 要读取的寄存器的地址
// @返回值:表示读取到的值
//
static uint8_t reg_read(uint8_t reg)
{My_I2C_SendBytes(I2C1,0xd0,&reg,1);uint8_t regValue;My_I2C_ReceiveBytes(I2C1,0xd0,&regValue,1);return regValue;
}

然后,我们对寄存器的参数进行配置

	// 2. 设置MPU6050的参数reg_write(0x6b,0x80);//复位Delay(100);reg_write(0x1b,0x18);//将陀螺仪的量程设置为+-2000°/sreg_write(0x1c,0x00);//将加速度计的量程设置为+-2g

接下来,我们对MPU6050的值进行更新

//
//@简介: MPU6050的数据更新函数
//
void App_MPU6050_Update(void)
{int16_t ax_raw = (int16_t)((reg_read(0x3b)<<8)+reg_read(0x3c));//ax的原始数据int16_t ay_raw = (int16_t)((reg_read(0x3d)<<8)+reg_read(0x3e));//ay的原始数据int16_t az_raw = (int16_t)((reg_read(0x3f)<<8)+reg_read(0x40));//az的原始数据int16_t temperature_raw = (int16_t)((reg_read(0x41)<<8)+reg_read(0x42));//温度的原始数据int16_t gx_raw = (int16_t)((reg_read(0x43)<<8)+reg_read(0x44));//gx的原始数据int16_t gy_raw = (int16_t)((reg_read(0x45)<<8)+reg_read(0x46));//gy的原始数据int16_t gz_raw = (int16_t)((reg_read(0x47)<<8)+reg_read(0x48));//gz的原始数据	
}

然后我们对数值进行更新:

void App_MPU6050_Update(void)
{int16_t ax_raw = (int16_t)((reg_read(0x3b)<<8)+reg_read(0x3c));//ax的原始数据int16_t ay_raw = (int16_t)((reg_read(0x3d)<<8)+reg_read(0x3e));//ay的原始数据int16_t az_raw = (int16_t)((reg_read(0x3f)<<8)+reg_read(0x40));//az的原始数据ax = ax_raw * 6.1035e-5f;ay = ay_raw * 6.1035e-5f;az = az_raw * 6.1035e-5f;int16_t temperature_raw = (int16_t)((reg_read(0x41)<<8)+reg_read(0x42));//温度的原始数据//temperature = temperature_raw/340 +36.53;//MPU6050temperature = temperature_raw/333.87f+21.0f;//MPU6500int16_t gx_raw = (int16_t)((reg_read(0x43)<<8)+reg_read(0x44));//gx的原始数据int16_t gy_raw = (int16_t)((reg_read(0x45)<<8)+reg_read(0x46));//gy的原始数据int16_t gz_raw = (int16_t)((reg_read(0x47)<<8)+reg_read(0x48));//gz的原始数据	gx = gx_raw * 6.1035e-2f;gy = gy_raw * 6.1035e-2f;gz = gz_raw * 6.1035e-2f;
}

然后我们创建一个接口函数,将更新到的值进行导出

float App_MPU6050_GetAx(void)
{return ax;
}
float App_MPU6050_GetAy(void)
{return ay;
}
float App_MPU6050_GetAz(void)
{return az;
}
float App_MPU6050_Temperature(void)
{return temperature;
}
float App_MPU6050_GetGx(void)
{return gx;
}
float App_MPU6050_GetGy(void)
{return gy;
}
float App_MPU6050_GetGz(void)
{return gz;
}

解算欧拉角

陀螺仪解算欧拉角

static float yaw,pitch,roll;//单位是°
//
// @简介:MPU6050的进程函数,计算欧拉角
//
void App_MPU6050_Proc(void)
{static uint32_t nxt = 0;//下次程序运行的时间if(GetTick() < nxt) return;App_MPU6050_Update();//通过陀螺仪的测量结果计算欧拉角yaw = yaw + gz * 0.005;pitch = pitch + gx * 0.005;roll = roll - gy * 0.005;nxt += 5;
}
//

这样,我们就会每5ms来执行一次这个程序

为了简化这个步骤,我们也可以这样子写

//
// @简介:MPU6050的进程函数,计算欧拉角
//
void App_MPU6050_Proc(void)
{PERIODIC(5);App_MPU6050_Update();//通过陀螺仪的测量结果计算欧拉角yaw = yaw + gz * 0.005;pitch = pitch + gx * 0.005;roll = roll - gy * 0.005;}

接下来,我们对这个部分进行测试

//
// @简介: 用来测试欧拉角
//
void MPU6050_EularAngleTest(void)
{App_Usart_Init();App_Mpu6050_Init();	while(1){App_MPU6050_Proc();Uasrt2_Proc();}}
static void Uasrt2_Proc(void)
{PERIODIC(10)float ax = App_MPU6050_GetAx();float ay = App_MPU6050_GetAy();float az = App_MPU6050_GetAz();float temperature = App_MPU6050_Temperature();float gx = App_MPU6050_GetGx();float gy = App_MPU6050_GetGy();float gz = App_MPU6050_GetGz();float yaw = App_MPU6050_GetYaw();float pitch = App_MPU6050_GetPitch();float roll = App_MPU6050_GetRoll();My_USART_Printf(USART2,"%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n",ax,ay,az,temperature,gx,gy,gz,yaw,pitch,roll);
}

加速度计解算欧拉角

我们一般是会使用加速度计来计算俯仰角和翻滚角,一般不会使用加速度计来计算偏航角,因为重力对于平面上的影响是非常小的。重力向量在设备坐标系中的投影变化,直接反映了设备的Pitch和Roll角度。重力是这些角度的“绝对参考”。重力向量与设备的偏航角是完全解耦的,它不提供任何关于偏航方向的信息。所以我们不会用来计算偏航角。

	//通过加速度计解算欧拉角yaw = 0;pitch = atan2(ay,az) / 3.1415927f * 180.0f;roll = atan2(ax,az) / 3.1415927f * 180.0f;

用陀螺仪是有漂移问题的,而加速度计有噪声,所以我们用互补滤波器来解决这种问题。

//
// @简介:MPU6050的进程函数,计算欧拉角
//
void App_MPU6050_Proc(void)
{PERIODIC(5);App_MPU6050_Update();//通过陀螺仪的测量结果计算欧拉角float yaw_g = yaw + gz * 0.005;float pitch_g = pitch + gx * 0.005;float roll_g = roll - gy * 0.005;//通过加速度计解算欧拉角float yaw_a = 0;float pitch_a = atan2(ay,az) / 3.1415927f * 180.0f;float roll_a = atan2(ax,az) / 3.1415927f * 180.0f;//使用互补滤波器yaw = yaw_g;pitch = 0.95238 * pitch_g + (1-0.95238) * pitch_a;roll = 0.95238 * roll_g + (1-0.95238) * roll_a;
}

好了,今天的内容就到这里,明天再见

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在电路浪涌测试中,TVS(瞬态电压抑制二极管)的防护效果确实会受到陪测设备中去耦网络(Decoupling Network,DN)的显著影响

在电路浪涌测试中&#xff0c;TVS&#xff08;瞬态电压抑制二极管&#xff09;的防护效果确实会受到陪测设备中去耦网络&#xff08;Decoupling Network&#xff0c;DN&#xff09;的显著影响&#xff0c;这一现象与浪涌能量的传递路径、阻抗匹配及信号完整性密切相关。结合 AD…

Redis之分布式锁与缓存设计

1、分布式锁 1.1、超卖问题/*** 存在库存超卖的不安全问题*/private void deductStock() {int stockTotal Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stockTotal > 0) { // 这里存在多个线程、进程同时判断通过&#xff0c;然后超买…

静态住宅IP的特点

稳定性高&#xff1a;与动态IP地址相比&#xff0c;静态住宅IP不会不定时变更&#xff0c;能确保业务在网络环境中的一致性和连贯性&#xff0c;适合需要长期维持同一身份的场景&#xff0c;如跨境电商业务等3。安全性强&#xff1a;由于其住宅属性&#xff0c;看起来更像是正常…

Linux 编译 Android 版 QGroundControl 软件并运行到手机上

Linux 编译 Android 版 QGroundControl 软件并运行到手机上环境说明操作步骤一、参考上一篇文章在电脑端把环境搭建好二、配置 Qt Creator 的 Android 环境环境说明 电脑系统 Ubuntu 22.04 qgroundcontrol master 分支 Qt 6.8.3 操作步骤 一、参考上一篇文章在电脑端把环境搭…

Python 2025:量化金融与智能交易的新纪元

当Python遇见金融大数据&#xff0c;算法交易正迎来前所未有的技术变革在2025年的技术浪潮中&#xff0c;Python已经从一个"胶水语言"蜕变为金融科技领域的核心驱动力。根据GitHub 2025年度报告&#xff0c;Python在量化金融项目中的使用率增长了217%&#xff0c;在对…

[论文阅读] 人工智能 + 软件工程 | TDD痛点破解:LLM自动生成测试骨架靠谱吗?静态分析+专家评审给出答案

TDD痛点破解&#xff1a;LLM自动生成测试骨架靠谱吗&#xff1f;静态分析专家评审给出答案 论文信息项目详情论文原标题Evaluation of Large Language Models for Generating RSpec Test Skeletons in Ruby on Rails论文链接https://arxiv.org/pdf/2509.04644一段话总结 该研究…

开源PSS解析器1

本章介绍另一个开源PSS解析工具zuspec&#xff1a; zuspec 提供了一组用于处理 actions relationship level 的工具 &#xff08;ARL&#xff09; 模型&#xff0c;主要是使用 Accellera 便携式测试和刺激 &#xff08;PSS&#xff09; 语言描述的模型。ARL 模型用于为数字设计…

26考研——内存管理_内存管理策略(3)

408答疑 文章目录一、内存管理策略1、内存管理的基本原理和要求1.1、相关概念1.2、逻辑地址与物理地址1.3、程序的链接与装入1.4、进程的内存映像1.5、内存保护1.6、内存共享1.7、内存分配与回收1.8、在存储管理中涉及到两个问题2、连续分配管理方式2.1、相关概念2.2、单一连续…

Python爬虫实战:研究Event Handling机制,构建在线教育平台的课程数据采集和分析系统

1. 引言 1.1 研究背景与意义 在大数据时代,互联网作为全球最大的信息载体,蕴含着海量有价值的数据。这些数据涵盖了商业交易、用户行为、社会趋势等多个领域,对企业决策、学术研究和社会管理具有重要参考价值。如何高效、准确地获取这些数据并进行深度分析,成为当前数据科…

docker 安装 redis 并设置 volumes 并修改 修改密码(四)

设置新密码: 127.0.0.1:6379> CONFIG SET requirepass newpassword OK验证新密码: 127.0.0.1:6379> AUTH newpassword OK更新配置文件: 编辑主机的配置文件/data/redis/conf/redis.conf,将requirepass的值修改为新密码: requirepass newpassword重启容器以使配置…

NBA球星知识大挑战:基于 PyQt5 的球星认识小游戏

NBA球星知识大挑战&#xff1a;基于 PyQt5 的球星认识小游戏 代码详见&#xff1a;https://github.com/xiaozhou-alt/NBA_Players_Recognition 文章目录 NBA球星知识大挑战&#xff1a;基于 PyQt5 的球星认识小游戏一、项目介绍二、文件夹结构三、项目实现1. 自定义动画按钮&a…

电磁波成像(X射线、CT成像)原理简介

电磁波成像&#xff08;X射线、CT成像&#xff09;原理简介一、图像形成的一般形式二、可见光成像2.1可见光2.2可见光成像三、其他电磁波成像3.1X射线成像3.2CT成像3.2.1CT成像原理3.2.2CT成像与X射线成像对比3.2.3CT生成三维描述3.3PET成像一、图像形成的一般形式 大多数图像…

k8s部署2:前置条件:docker部署

前两天发布了k8s的前置发布条件,对于防火墙的处理,我看大家反响还不错,所以作为先行者,我感觉自己多了不少动力,所以今天来说说k8s部署前置条件中docker部分的部署。在此先感谢一下那些点赞和添加收藏的朋友们,你们的支持是我永远的动力!三克油喂给马吃! 之前写过docke…

某开源漫画系统RCE代码审计

免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规&#xff0c;并取得目标系统的明确授权。 对于因不当使用本文信息而造…

Pandas DataFrame 指南

&#x1f4ca; Pandas DataFrame 常用操作代码示例 下面用表格汇总了 DataFrame 的常用操作&#xff0c;方便你快速查阅和实践。 操作类别代码示例说明&#xff08;简要&#xff09;数据读取df pd.read_csv(data.csv)读取 CSV 文件df pd.read_excel(data.xlsx, sheet_nameS…

React学习教程,从入门到精通, React 样式语法知识点与案例详解(13)

React 样式语法知识点与案例详解 作为React初学者&#xff0c;掌握样式语法是构建美观UI的关键。本文将详细介绍React中所有主要的样式方法&#xff0c;并提供详细注释的案例代码。 一、React样式语法知识点总览 1. 行内样式 (Inline Styles) 使用style属性&#xff0c;值为Jav…

Proxychains 配置全解析:从入门到高级应用

引言 在数字时代&#xff0c;网络隐私与安全至关重要。无论是绕过地理限制访问内容&#xff0c;还是在渗透测试中隐藏踪迹&#xff0c;代理工具都不可或缺。Proxychains&#xff08;或称 Proxychains-NG&#xff09;作为一款经典的开源代理链工具&#xff0c;以其高效灵活的特性…

二叉树的前中后序遍历(迭代法)

目录 题目链接&#xff1a; 题目&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 前序遍历&#xff1a; 中序遍历&#xff1a; 后序遍历&#xff1a; 总结&#xff1a; 题目链接&#xff1a; 144. 二叉树的前序遍历 - 力扣&#xff08;LeetCode&#xff09; 94. …

redis的数据类型:string

文章目录String类型介绍redis采用的字符集json类型介绍String类型的命令set key value [EX seconds] [NX|XX]incr keyincr对操作的key对应的value类型有限制吗&#xff1f;incr key操作的返回值是什么&#xff1f;incr操作的key可以不存在吗&#xff1f;多个客户端同时针对同…

传统神经网络实现-----手写数字识别(MNIST)项目

完整代码&#xff1a;# import torch # print(torch.__version__)#1.X 1、验证安装的开发环境是否正确&#xff0c; MNIST包含70,000张手写数字图像: 60,000张用于训练&#xff0c;10,000张用于测试。 图像是灰度的&#xff0c;28x28像素的&#xff0c;并且居中的&#xff…