一、项目概述

目标和用途

本项目旨在开发一款基于 STM32 控制的自动平衡机器人,结合步进电机和陀螺仪传感器,实现对平衡机器人的精确控制。该机器人可以用于教育、科研、娱乐等多个领域,帮助用户了解自动控制、机器人运动学等相关知识。

技术栈关键词

  • STM32 单片机

  • 步进电机

  • 陀螺仪传感器

  • AD 采集电路

  • Qt 人机界面

  • 实时数据监控

二、系统架构

系统架构设计

本项目的系统架构设计包括以下主要组件:

  1. 控制单元: STM32 单片机

  2. 传感器模块: 陀螺仪传感器

  3. 驱动模块: 步进电机驱动器

  4. 人机交互界面: Qt 桌面应用程序

  5. 通信协议: UART 或 I2C

系统架构图

控制
数据采集
通信
实时数据
STM32 单片机
步进电机驱动器
陀螺仪传感器
Qt 人机界面

三、环境搭建和注意事项

环境搭建

  1. 硬件环境:

    • STM32 开发板(如 Nucleo 或 Discovery)

    • 步进电机及驱动模块

    • 陀螺仪传感器(如 MPU6050)

    • 面包板及连接线

  2. 软件环境:

    • 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. 初始化 I2C
    HAL_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_OBJECT

public:
    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 之间的交互过程。

UserQtUISTM32GyroSensorStepperMotor点击启动按钮发送启动命令读取陀螺仪数据返回陀螺仪数据设置速度和方向确认启动返回实时转速和方向更新转速和方向显示点击停止按钮发送停止命令停止电机确认停止UserQtUISTM32GyroSensorStepperMotor

五、项目总结

主要功能

本项目的主要目标是设计并实现一款基于 STM32 的自动平衡机器人。项目的核心功能包括:

  1. 实时数据采集:

    • 使用陀螺仪传感器(如 MPU6050)获取机器人的角速度和角度数据,实现对机器人的实时姿态监测。

    • 通过 I2C 接口与 STM32 进行数据通信,确保数据的准确传输。

  2. 步进电机控制:

    • 利用步进电机驱动模块,实现机器人的加速、减速及转向控制。

    • 根据陀螺仪反馈的数据,动态调整电机的速度和方向,以保持机器人的平衡状态。

  3. 人机交互界面:

    • 使用 Qt 框架设计用户界面,提供启动、停止、加速和减速等操作按钮。

    • 实时显示机器人的转速、转向和驱动脉冲频率等信息,增强用户体验。

  4. 数据通信:

    • 通过 UART 串口实现 STM32 和 Qt 界面之间的双向通信,支持实时数据传输。

    • 确保用户可以通过界面直接控制机器人,并获取其状态信息。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐