基于STM32与Qt的自动平衡机器人:从控制到人机交互的的详细设计流程
一、项目概述
目标和用途
本项目旨在开发一款基于 STM32 控制的自动平衡机器人,结合步进电机和陀螺仪传感器,实现对平衡机器人的精确控制。该机器人可以用于教育、科研、娱乐等多个领域,帮助用户了解自动控制、机器人运动学等相关知识。
技术栈关键词
-
STM32 单片机
-
步进电机
-
陀螺仪传感器
-
AD 采集电路
-
Qt 人机界面
-
实时数据监控
二、系统架构
系统架构设计
本项目的系统架构设计包括以下主要组件:
-
控制单元: STM32 单片机
-
传感器模块: 陀螺仪传感器
-
驱动模块: 步进电机驱动器
-
人机交互界面: Qt 桌面应用程序
-
通信协议: UART 或 I2C
系统架构图
三、环境搭建和注意事项
环境搭建
-
硬件环境:
-
STM32 开发板(如 Nucleo 或 Discovery)
-
步进电机及驱动模块
-
陀螺仪传感器(如 MPU6050)
-
面包板及连接线
-
-
软件环境:
-
STM32CubeIDE 或 Keil MDK
-
Qt Creator
-
STM32 HAL 库
-
注意事项
-
确保电源供应稳定,避免电源波动导致的设备损坏。
-
在调试过程中,注意步进电机的工作电流,避免过载。
-
传感器的连接线要正确,防止接反导致数据采集错误。
四、代码实现过程
在本部分中,我们将详细介绍 STM32 自动平衡机器人的各个功能模块的代码实现,包括陀螺仪数据采集、步进电机控制以及 Qt 人机界面控制。每个模块的实现都将包含代码示例、说明和算法的详细介绍,最后将展示系统的时序图。
1. 陀螺仪数据采集模块
功能
该模块的主要功能是通过 I2C 总线读取陀螺仪传感器(如 MPU6050)的数据(角速度和角度),并进行滤波处理以提高数据的准确性。
代码实现
#include "mpu6050.h"
#include "i2c.h"#define MPU6050_ADDR 0x68 // MPU6050 I2C 地址void MPU6050_Init() {// 1. 初始化 I2CHAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR << 1, 0x6B, I2C_MEMADD_SIZE_8BIT, (uint8_t[]){0}, 1, HAL_MAX_DELAY);// 2. 设置陀螺仪为正常工作模式HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR << 1, 0x1B, I2C_MEMADD_SIZE_8BIT, (uint8_t[]){0}, 1, HAL_MAX_DELAY); // 设置为 ±250°/s
}void Read_Gyro_Data(float* gyro_x, float* gyro_y, float* gyro_z) {uint8_t data[6];// 读取陀螺仪数据HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR << 1, 0x43, I2C_MEMADD_SIZE_8BIT, data, 6, HAL_MAX_DELAY);// 数据转换int16_t rawGyroX = (data[0] << 8) | data[1];int16_t rawGyroY = (data[2] << 8) | data[3];int16_t rawGyroZ = (data[4] << 8) | data[5];// 转换为角速度(°/s)*gyro_x = (float)rawGyroX / 131.0;*gyro_y = (float)rawGyroY / 131.0;*gyro_z = (float)rawGyroZ / 131.0;
}
代码说明
-
MPU6050_Init()
函数用于初始化 MPU6050 陀螺仪,包括设置工作模式。 -
Read_Gyro_Data()
函数读取陀螺仪的原始角速度数据,将其转换为实际的角速度(单位为 °/s)。 -
读取的数据通过 I2C 总线传输,使用 HAL 库函数
HAL_I2C_Mem_Read()
和HAL_I2C_Mem_Write()
进行数据的读写。
2. 步进电机控制模块
功能
该模块负责接收来自陀螺仪的数据,计算控制步进电机的速度和方向,从而实现机器人的平衡控制。
代码实现
#include "stepper_motor.h"#define STEPS_PER_ROTATION 200 // 步进电机每转一圈的步数
#define MAX_SPEED 1000 // 最大速度static int current_speed = 0;
static int current_direction = 1; // 1: 正转, -1: 反转void StepperMotor_SetSpeed(int speed) {if (speed > MAX_SPEED) speed = MAX_SPEED;if (speed < 0) speed = 0;current_speed = speed;// 根据 speed 设置定时器的频率__HAL_TIM_SET_PRESCALER(&htim1, (SystemCoreClock / (current_speed * STEPS_PER_ROTATION)) - 1);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}void StepperMotor_SetDirection(int direction) {current_direction = direction;// 方向引脚设置HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, current_direction > 0 ? GPIO_PIN_SET : GPIO_PIN_RESET);
}void StepperMotor_Run() {// 控制步进电机旋转while (1) {if (current_speed > 0) {// 产生脉冲信号控制步进电机HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);HAL_Delay(1); // 脉冲宽度HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);HAL_Delay(1); // 等待下一个脉冲}}
}
代码说明
-
StepperMotor_SetSpeed(int speed)
函数设置步进电机的速度,使用定时器来生成定时脉冲信号来控制电机的转动速度。 -
StepperMotor_SetDirection(int direction)
函数设置步进电机的转动方向,通过控制 GPIO 引脚的高低电平来设置电机的方向。 -
StepperMotor_Run()
函数根据当前速度持续产生脉冲信号,从而使步进电机旋转。
3. Qt 人机界面控制模块
功能
Qt 人机界面模块用于实时显示被测转子的转速、转向和驱动脉冲频率,并提供控制按钮以启动、停止、加速、减速和改变方向。
代码实现
#include <QMainWindow>
#include <QTimer>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void startMotor();void stopMotor();void updateDisplay();private:QLabel *speedLabel;QLabel *directionLabel;QPushButton *startButton;QPushButton *stopButton;QTimer *timer;float currentSpeed;int currentDirection; // 1: 正转, -1: 反转
};MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), currentSpeed(0), currentDirection(1) {speedLabel = new QLabel("转速: 0");directionLabel = new QLabel("方向: 正转");startButton = new QPushButton("启动");stopButton = new QPushButton("停止");QVBoxLayout *layout = new QVBoxLayout();layout->addWidget(speedLabel);layout->addWidget(directionLabel);layout->addWidget(startButton);layout->addWidget(stopButton);QWidget *centralWidget = new QWidget();centralWidget->setLayout(layout);setCentralWidget(centralWidget);connect(startButton, &QPushButton::clicked, this, &MainWindow::startMotor);connect(stopButton, &QPushButton::clicked, this, &MainWindow::stopMotor);timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &MainWindow::updateDisplay);timer->start(100); // 每100毫秒更新一次显示
}MainWindow::~MainWindow() {// 清理
}void MainWindow::startMotor() {currentSpeed = 100; // 启动电机currentDirection = 1; // 正转// 向 STM32 发送启动和速度指令
}void MainWindow::startMotor() {currentSpeed = 100; // 启动电机currentDirection = 1; // 正转// 向 STM32 发送启动和速度指令// 这里可以调用串口通信函数,发送控制命令// 例如: sendCommandToSTM32("START", currentSpeed, currentDirection);
}void MainWindow::stopMotor() {currentSpeed = 0; // 停止电机// 向 STM32 发送停止命令// 例如: sendCommandToSTM32("STOP");
}void MainWindow::updateDisplay() {// 更新转速和方向标签speedLabel->setText(QString("转速: %1").arg(currentSpeed));directionLabel->setText(currentDirection == 1 ? "方向: 正转" : "方向: 反转");// 这里可以读取 STM32 发送过来的实时数据并更新界面// 例如: currentSpeed = readSpeedFromSTM32();// 方向可能需要从 STM32 读取或根据计算结果更新
}
代码说明
-
startMotor()
函数被点击时调用,设置当前速度和方向,并向 STM32 发送启动指令。 -
stopMotor()
函数被点击时调用,停止电机并发送停止指令。 -
updateDisplay()
函数定时更新界面上的转速和方向标签。这一部分可以通过读取 STM32 的串口数据实现实时更新。
4. 数据通信模块
功能
本模块实现 STM32 和 Qt 界面之间的数据通信,使用串口(UART)进行双向数据传输。
代码实现
#include "usart.h"void sendCommandToSTM32(const char* command) {HAL_UART_Transmit(&huart2, (uint8_t*)command, strlen(command), HAL_MAX_DELAY);
}void receiveDataFromSTM32(char* buffer, uint16_t size) {HAL_UART_Receive(&huart2, (uint8_t*)buffer, size, HAL_MAX_DELAY);
}
代码说明
-
sendCommandToSTM32(const char* command)
函数用于向 STM32 发送指令。 -
receiveDataFromSTM32(char* buffer, uint16_t size)
函数用于接收来自 STM32 的数据,存储在指定的缓冲区中。
5. 时序图
以下是系统时序图,展示了用户与 Qt 界面、Qt 界面与 STM32 之间的交互过程。
五、项目总结
主要功能
本项目的主要目标是设计并实现一款基于 STM32 的自动平衡机器人。项目的核心功能包括:
-
实时数据采集:
-
使用陀螺仪传感器(如 MPU6050)获取机器人的角速度和角度数据,实现对机器人的实时姿态监测。
-
通过 I2C 接口与 STM32 进行数据通信,确保数据的准确传输。
-
-
步进电机控制:
-
利用步进电机驱动模块,实现机器人的加速、减速及转向控制。
-
根据陀螺仪反馈的数据,动态调整电机的速度和方向,以保持机器人的平衡状态。
-
-
人机交互界面:
-
使用 Qt 框架设计用户界面,提供启动、停止、加速和减速等操作按钮。
-
实时显示机器人的转速、转向和驱动脉冲频率等信息,增强用户体验。
-
-
数据通信:
-
通过 UART 串口实现 STM32 和 Qt 界面之间的双向通信,支持实时数据传输。
-
确保用户可以通过界面直接控制机器人,并获取其状态信息。
-
相关文章:

基于STM32与Qt的自动平衡机器人:从控制到人机交互的的详细设计流程
一、项目概述 目标和用途 本项目旨在开发一款基于 STM32 控制的自动平衡机器人,结合步进电机和陀螺仪传感器,实现对平衡机器人的精确控制。该机器人可以用于教育、科研、娱乐等多个领域,帮助用户了解自动控制、机器人运动学等相关知识。 技…...

C#使用ZipFile的方法CreateFromDirectory
由于现在数据越来越大,虽然磁盘的大小也在增加,但是数据增加的速度是远超过磁盘的增加速度。 因为数据是一种思想的表现,特别是ChatGPT的AI出现,导致很多数据无限地使用机器化地产生,所以数据压缩还是很常有的事情,毕竟压缩之后可以减少磁盘空间的占用。 在C#里有一个专…...

Redis 哨兵模式的选举算法是什么?
Redis 哨兵模式中的选举算法主要用于在主节点出现故障时,从多个 Sentinel 节点中选出一个领导者(Leader)来执行故障转移操作。 Redis 哨兵的选举算法基于 Raft 算法的简化版本,但不完全等同于标准的 Raft 算法。以下是其主要过程: 一、发现主节点故障 当一个 Sentinel …...

Linux shell编程学习笔记80:gzip命令——让文件瘦身
0 引言 在 Linux shell编程学习笔记76:tar命令——快照 & 备份(上)-CSDN博客 Linux shell编程学习笔记77:tar命令——快照 & 备份(下)_linux 系统快照-CSDN博客 Linux shell编程学习笔记78&am…...

【字幕】恋上数据结构与算法之01为什么要学习数据结构与算法
视频地址:请查看01为什么要学习数据结构与算法_哔哩哔哩_bilibili 同志们好,我是小码哥的mj李明杰。非常欢迎大家来学习链上数据结构与算法,从今天开始呢就由我来带大家一起来学习和掌握这个数据结构与算法啊。在正式学习之前我们先来看一下…...

120页ppt丨集团公司战略规划内容、方法、步骤及战略规划案例研究
响应会员需求,晓零分享一份经典资料《120页ppt集团公司战略规划内容、方法、步骤及战略规划案例研究》,欢迎进入星球下载学习。 以下是对企业战略规划三个阶段八个步骤的详细解析: 一、阶段一:内外分析 项目启动和前期准备&…...

滚雪球学SpringCloud[2.3]:服务发现与负载均衡详解
全文目录: 前言1. Ribbon的使用与配置1.1 Ribbon 概述Ribbon 的核心功能: 1.2 Ribbon 的基本使用1.2.1 引入 Ribbon 依赖1.2.2 配置 RestTemplate 与 Ribbon1.2.3 示例:通过 Ribbon 调用服务 1.3 Ribbon 的配置选项 2. Ribbon的负载均衡策略2…...

商务英语口语之聚会宴饮常用口语柯桥培训到蓝天广场
吃饭一定要掌握的英语口语 邀请他人共进餐: Would you like to join me for dinner? 你愿意和我一起吃饭吗? Lets grab a bite to eat together. 我们一起去吃点东西吧。 How about having lunch with me? 和我一起吃午饭怎么样? 询问…...

【C#】VS插件
翻译 目前推荐较多的 可以单词发言,目前还在开发阶段 TranslateIntoChinese - Visual Studio Marketplace 下载量最高的(推荐) Visual-Studio-Translator - Visual Studio Marketplace 支持翻译的版本较多,在 Visual Studio 代码编辑器中通过 Googl…...

嵌入式C语言自我修养:C语言的面向对象编程思想
⭐关联知识点:C和C的区别 代码复用与分层思想 什么是代码复用呢? (1)函数级代码复用:定义一个函数实现某个功能,所有的程序都可以调用这个函数,不用自己再单独实现一遍,函数级的代…...

行车记录仪格式化了怎么恢复?专业恢复方法分享
行车记录仪作为现代驾驶的必备设备,它忠实记录着行车过程中的点点滴滴,是保障行车安全、处理交通事故的重要依据。然而,有时由于操作失误或其他原因,我们可能会不小心将行车记录仪进行格式化,导致宝贵的录像数据丢失。…...

C++中extern ”c“的理解
c中extern “C“的作用及理解_extern "c-CSDN博客...

红黑树的删除
文章目录 前言一.删除的节点左子树右子树都有二.删除的节点只有左/右子树删除调整操作 三.删除的节点没有孩子1.删除的节点为红色2.删除的节点为黑色1).兄弟节点为黑色(1).兄弟节点至少有一个红色的孩子节点LL型RR型RL型LR型 (2).兄弟节点没有孩子或所有孩子为黑色 2).兄弟节点…...

Vue3+setup实现父子组件单表增删改查写法模板
父组件写法 <el-card><!-- el-card 头部插槽 显示列表名和新增按钮 --><template #header><div class"table-header-container"><i class"fas fa-th" />角色列表(100)<span style"flex-grow…...

jmeter 录制APP脚本
一、手机 1、修改网络 代理选择手动→填写服务器主机名(电脑IP,如:192.1xx.x.xx)→服务器端口(任意未被占用端口,如:8888) 2、安装证书 手机浏览器访问服务器主机名:服务器端口&a…...

C++类与对象深度解析(一):从抽象到实践的全面入门指南
文章目录 C 类与对象——详细入门指南前言1. 类的定义1.1 类定义的基本格式示例代码解释 1.2 访问限定符示例代码解释 1.3 类域示例代码解释 1.4 成员命名规范常见的命名约定:示例:拓展: 1.5 class与struct的默认访问权限示例: 2.…...

docker拉取 jdk 8
docker pull openjdk:8docker run -d -it --name java-8 openjdk:8docker run -d -it --name java-8 openjdk:8 –name java-8 容器名,自定义的 openjdk:8 镜像名:标签名 , 使用 docker images 查看 2、查看已运行的容器实例: doc…...

机器学习VS深度学习
机器学习(Machine Learning, ML)和深度学习(Deep Learning, DL)是人工智能(AI)的两个子领域,它们有许多相似之处,但在技术实现和应用范围上也有显著区别。下面从几个方面对两者进行区…...

基于vue框架的宠物交流平台1n2n3(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
系统程序文件列表 项目功能:会员,宠物信息,宠物类型,团队信息,申请领养,团队申请,领养宠物 开题报告内容 基于Vue框架的宠物交流平台开题报告 一、项目背景 随着现代生活节奏的加快与人们情感需求的日益增长,宠物已成为众多家庭不可或缺的重要成员。…...

Rust 所有权 借用与引用
文章目录 发现宝藏1. 所有权(Ownership)2. 引用(References)2.1 不可变引用2.2 可变引用2.3 引用的规则 3. 悬垂引用(Dangling References)4. 借用(Borrowing)结论 发现宝藏 前些天…...

构建智能电商新生态:深度解析京东商品详情API的力量
在当今数字化浪潮中,智能电商系统已成为推动零售业转型升级的重要引擎。作为电商行业的领军者之一,京东凭借其庞大的商品数据库和先进的技术架构,为开发者与商家提供了丰富的API接口,其中商品详情API无疑是构建智能电商系统的关键…...

Golang | Leetcode Golang题解之第398题随机数索引
题目: 题解: type Solution []intfunc Constructor(nums []int) Solution {return nums }func (nums Solution) Pick(target int) (ans int) {cnt : 0for i, num : range nums {if num target {cnt // 第 cnt 次遇到 targetif rand.Intn(cnt) 0 {ans …...

使用注意力机制可以让你的模型更加灵活,但是需要额外的计算资源。rnn lstm bilstm attension
确实,使用注意力机制可以使模型更加灵活,但也确实需要额外的计算资源。注意力机制允许模型在处理序列数据时,能够动态地关注不同位置的重要性,从而更好地捕捉长依赖关系。下面是一个简单的注意力机制实现示例,可以帮助…...

git命令大全
简介:个人学习分享,如有错误,欢迎批评指正 一、Git操作流程 1、代码提交和同步代码 第零步: 工作区与仓库保持一致第一步: 文件增删改,变为已修改状态第二步: git add ,变为已暂存状态 $ git status $ git add --al…...

【数据仓库】数据仓库常见的数据模型——范式模型
目录 一、范式 1、第一范式 2、第二范式 3、第三范式 4、进一步范式化:BCNF、4NF 和 5NF 简介 (1)Boyce-Codd 范式(BCNF) (2)第四范式(4NF) (5&#x…...

【LeetCode每日一题】——LCR 078.合并 K 个升序链表
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目注意】六【题目示例】七【题目提示】八【解题思路】九【时间频度】十【代码实现】十一【提交结果】 一【题目类别】 优先队列 二【题目难度】 困难 三【题目编号】 LCR 078.合并 K 个升序链表 …...

代码随想录算法训练营第五十九天 | dijkstra(堆优化版)精讲
目录 dijkstra(堆优化版)精讲 思路 堆优化细节 方法一: 最小堆优化 dijkstra(堆优化版)精讲 题目链接:卡码网:47. 参加科学大会 文章讲解:代码随想录 小明是一位科学家&#x…...

go语言后端开发学习(七)——如何在gin框架中集成限流中间件
一.什么是限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数。 我们生活中也会经常遇到限流的场景,比如:某景区限制每日进入景区的游客数量为8万人;沙河地铁站早高峰通过站外排队逐一放行的…...

SpringBoot2:web开发常用功能实现及原理解析-整合EasyExcel实现Excel导入导出功能
1、工程包结构 主要是这5个Java类 2、导入EasyExcel包 这里同时贴出其他相关springboot的基础包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><depend…...

CTFShow-信息搜集
Web1: 题目描述:开发注释未及时删除 。 打开题目后提示web1:where is flag? ctrlu读取源码。 Web2: 题目描述:js前台拦截 无效操作 打开题目后显示:无法查看源代码 右键无法用,…...