基于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 界面之间的双向通信,支持实时数据传输。
-
确保用户可以通过界面直接控制机器人,并获取其状态信息。
-