基于STM32设计的扫地机器人

发布于:2025-06-28 ⋅ 阅读:(28) ⋅ 点赞:(0)

一、前言

1.1 项目介绍

【1】项目开发背景

随着社会节奏的加快和人们生活方式的改变,智能家居产品逐渐走入千家万户。作为智能清洁系统的重要组成部分,扫地机器人凭借其自动化、高效性和便捷性,成为现代家庭中不可或缺的智能设备之一。传统人工清洁方式费时费力,尤其对于老年人、上班族而言,日常清扫负担较重,因此急需一种智能化、自动化的解决方案来提升生活质量。

扫地机器人结合了嵌入式控制、传感器技术、路径规划算法以及无线通信等多种现代技术,实现了自动避障、智能清扫、自动回充等功能,体现了智能控制与人机交互的发展趋势。随着MCU芯片和传感器技术的不断成熟,开发一套基于STM32微控制器的扫地机器人系统,既具有良好的技术实现基础,又能满足用户对于清洁智能化的迫切需求。

本项目通过STM32系列单片机构建一个功能完善、成本适中、实用性强的智能扫地机器人系统。通过软硬件协同设计,实现路径规划、灰尘识别、跌落保护、远程控制等关键功能,提升机器人在不同家庭场景下的清扫效率和安全性。项目不仅具有较强的应用价值,同时也为智能机器人技术的学习与研究提供了实践平台。

【2】设计实现的功能

(1)采用红外避障传感器和超声波测距模块实现自动避障功能,能够在复杂环境中自动绕开障碍物。
(2)利用实时时钟RTC模块实现定时清扫功能,按设定时间自动启动清扫任务。
(3)结合MPU6050姿态传感器与编码器反馈实现路径规划与完整覆盖式清扫,提高清扫效率。
(4)通过红外跌落传感器检测地面边缘,实时进行边缘检测并防止机器人跌落。
(5)通过ESP8266模块实现WIFI通信,支持手机APP进行手动遥控操作与远程控制。
(6)由STM32主控处理清扫路径并生成清扫地图,上传至APP实现简易地图绘制功能。
(7)灰尘识别模块检测空气中粉尘浓度,在污染区域启动重点清扫机制。
(8)利用DFPlayer Mini语音模块实现语音提示功能,用于状态播报与故障提醒。
(9)使用0.96寸OLED屏幕显示当前清扫状态、电量信息和系统参数,方便本地查看。
(10)通过电压检测模块监测电池电量,并结合红外寻迹模块实现自动回充功能。
(11)ESP8266模块通过MQTT协议与服务器通信,实现清扫状态与控制指令的联网功能。
(12)Android APP平台支持清扫进度查看、路径显示、电量查询、远程启动/停止等控制功能。

【3】项目硬件模块组成

(1)主控芯片:STM32F103RCT6,作为系统核心控制器,负责传感器数据处理、运动控制与通信管理。
(2)驱动电机:2个带编码器的TT减速直流电机,用于驱动机器人前进、后退、转向等移动动作。
(3)电机驱动模块:L298N双路直流电机驱动模块,实现对左右驱动电机的正反转与调速控制。
(4)红外避障传感器:3个TCRT5000模块,分别安装在机器人前方与左右侧,用于检测障碍物。
(5)超声波测距模块:1个HC-SR04模块,用于精确测量前方障碍物距离。
(6)红外跌落传感器:3个TCRT5000模块,安装在机器人底部前端及两侧,用于检测地面是否存在,防止跌落。
(7)姿态检测模块:1个MPU6050六轴陀螺仪+加速度计模块,用于获取机器人运动姿态和角度变化。
(8)灰尘识别模块:GP2Y1010AU0F光学粉尘传感器,用于检测空气中灰尘浓度,实现重点清扫。
(9)语音模块:DFPlayer Mini音频模块,配合扬声器实现语音播报与提示功能。
(10)显示模块:0.96寸SPI接口OLED显示屏(SSD1306驱动),用于显示清扫状态、电量等信息。
(11)通信模块:ESP8266 WiFi模块(NodeMCU),通过串口与STM32通信,实现与APP的数据交互。
(12)电源系统:7.4V 18650锂电池组,配合升压模块为系统提供5V/9V稳定电源。
(13)电压检测模块:电压分压采集模块,用于检测电池电压,实现电量监测。
(14)自动回充模块:红外接收模块配合充电座红外发射器,实现机器人自动返回充电座。
(15)实时时钟模块:DS3231高精度RTC模块,用于实现定时清扫功能。
(16)APP平台:基于Android系统的手机APP,使用Qt(C++)开发,提供远程控制与状态监控功能。
(17)车体结构:亚克力底盘、万向轮与支撑结构,固定并承载各模块与电路系统。
(18)吸尘模块:5V高速风扇与滚刷组合,实现地面灰尘与颗粒物的有效吸附与清洁。

【4】设计意义

本项目基于STM32设计的扫地机器人系统,旨在利用嵌入式系统和多传感器融合技术,构建一套具备基本智能清扫能力的自动化清洁设备。通过项目的设计与实现,不仅能够减轻用户日常清洁的劳动负担,还可以提高清洁效率与覆盖率,为家庭智能化建设提供实用的技术支持和硬件基础。

项目集成了自动避障、路径规划、定时清扫、防跌落、语音提示、自动回充、APP远程控制等功能模块,充分体现了现代嵌入式系统在智能家居中的实际应用价值。通过合理的模块选型与软硬件协同开发,系统在稳定性、实用性、用户交互体验等方面都达到了较高水平,具备良好的工程实现与应用推广基础。

本项目的实施不仅为实际家庭场景中的清洁工作提供了解决方案,也为学习和掌握STM32平台的开发技术、传感器集成应用、路径算法设计、无线通信协议以及多线程逻辑管理等关键技术提供了一个完整的综合性平台,具有较强的教学实践和工程训练价值。

【5】市面上同类产品研究现状

目前市面上的扫地机器人产品已较为成熟,主要品牌包括iRobot的Roomba系列、石头科技的石头扫地机器人、小米米家扫地机器人等。这些产品普遍具备自动避障、路径规划、边缘检测和自动回充等核心功能,体现了智能清扫设备的发展趋势。

iRobot Roomba系列通过多传感器融合和先进的SLAM(同步定位与地图构建)算法,实现精准地图绘制和高效路径规划,能够适应复杂家庭环境,实现无遗漏清扫。其采用多点激光测距和视觉传感技术,配合强大的云端算法,提供用户友好的APP远程控制及语音交互功能。

石头科技的扫地机器人注重激光雷达(LIDAR)导航技术,配合高精度陀螺仪和多组红外传感器,实现快速环境感知与障碍物避让。该系列产品支持房间分区清扫及定时预约,用户可通过手机APP查看实时地图和清扫进度,增强使用体验。

小米米家扫地机器人则采用了激光导航与视觉传感的结合,具备强大的智能路径规划和避障能力。通过手机APP实现远程启动、停止及清扫模式切换,并集成语音助手控制功能,满足现代智能家居需求。

综上,当前主流扫地机器人均注重传感器融合、智能路径规划与用户交互体验的提升,形成了较为完善的产品生态。本项目结合STM32平台和多种传感器,实现基础功能的同时,也为低成本智能清扫设备的开发提供了可行的参考方案。

【6】摘要

基于STM32的扫地机器人项目,设计并实现了一套集自动避障、路径规划、边缘检测、防跌落、定时清扫、语音提示、自动回充及远程APP控制于一体的智能清扫系统。系统采用STM32F103RCT6作为主控芯片,结合多种传感器模块实现环境感知与智能决策,通过ESP8266实现无线通信与远程控制。该机器人能够高效完成地面无遗漏清扫,保障运行安全,提高用户使用便捷性和生活质量。项目验证了嵌入式系统与传感器融合技术在智能家居领域的应用价值,具备良好的工程实用性和推广前景。

关键字:STM32,扫地机器人,路径规划,自动避障,边缘检测,ESP8266,远程控制

1.2 设计思路

本项目设计基于STM32F103RCT6微控制器,充分利用其丰富的接口和较强的处理能力作为系统核心。设计思路以多传感器融合为基础,通过红外避障传感器和超声波测距模块实现环境感知,保障机器人能够实时识别障碍物并进行绕行。结合MPU6050姿态传感器和编码器数据,实现路径规划与运动控制,确保机器人能够高效完成地面覆盖式清扫。

为了保证运行安全,设计采用多个红外跌落传感器进行边缘检测,有效防止机器人跌落楼梯或其他高差处。系统通过实时电压检测与红外寻迹模块实现低电量自动回充功能,提升使用便捷性和续航能力。语音模块的集成则用于状态提示和故障报警,增强人机交互体验。

通信方面,设计采用ESP8266无线模块,配合MQTT协议,实现机器人与手机APP的远程数据交互和控制,使用户能够实时监控清扫状态并进行远程操作。整体设计采用模块化开发思路,硬件选型合理,软件结构清晰,保证系统的稳定性和易维护性,满足智能家居对扫地机器人高效、智能、安全的使用需求。

1.3 系统功能总结

功能模块 功能描述 主要硬件模块 关键技术/实现方式
自动避障 识别并绕开前方及侧方障碍物 红外避障传感器(3个)、超声波模块 红外与超声波传感器融合检测
定时清扫 按设定时间自动启动清扫任务 DS3231 RTC模块 实时时钟定时触发
路径规划与覆盖 实现地面无遗漏的覆盖式清扫 MPU6050、编码器 姿态检测+编码器数据,路径规划算法
边缘检测与防跌落 检测地面边缘,防止机器人跌落 红外跌落传感器(3个) 红外传感器实时检测边缘
手动遥控 通过手机APP远程控制机器人 ESP8266 WiFi模块 WIFI通信+MQTT协议
地图绘制 生成简易的房间清扫路径图 STM32主控、传感器数据处理 算法生成路径地图,上传APP
灰尘识别与重点清扫 检测灰尘浓度,针对高灰尘区域加强清扫 GP2Y1010光学粉尘传感器 模拟信号采集与阈值判定
语音播报 语音提示工作状态和故障信息 DFPlayer Mini音频模块 语音模块控制播放
OLED显示 实时显示清扫状态、电量及系统参数 0.96寸OLED显示屏(SSD1306) SPI通信显示信息
自动回充 低电量时自动返回充电座充电 电压检测模块、红外寻迹模块 电量监测+红外寻迹定位
WIFI联网 实现远程监控与控制 ESP8266 WiFi模块 WIFI通信与云端MQTT协议
APP远程控制 远程查看机器人状态,控制启动、停止及路径等功能 手机APP、ESP8266模块 APP界面设计与无线数据交互

1.4 开发工具的选择

【1】设备端开发

硬件设备端的开发主要依赖于C语言,利用该语言直接操作硬件寄存器,确保系统运行的高效性和低延迟。C语言在嵌入式开发中具有广泛的应用,它能够直接访问硬件,满足对资源消耗和响应速度的严格要求。为了编写高效、稳定的代码,开发工具选择了Keil uVision 5作为主要的开发环境。Keil是一个专业的嵌入式开发工具,广泛应用于基于ARM架构的微控制器(如STM32)开发。Keil提供了完善的调试、编译和仿真支持,能够帮助在软件开发过程中高效地进行调试、单步执行以及断点设置,确保开发的稳定性和高效性。
STM32F103RCT6是项目中使用的主控芯片,它基于ARM Cortex-M3架构,拥有强大的计算能力和丰富的外设接口。在硬件编程中,寄存器级编程是常用的方式,这要求开发者对芯片的硬件寄存器有深入的理解。在Keil环境中,通过STM32的寄存器直接控制GPIO、ADC、I2C、SPI等硬件接口,以满足各个硬件模块(如传感器、执行器、显示屏等)与主控芯片的交互。使用寄存器编程能够提供更高效、精确的控制,避免了外部库的开销,同时也能深入调控硬件特性,提升系统性能。

【2】上位机开发

本项目的上位机开发基于Qt 5框架,使用**C++**作为主要编程语言。Qt是一个跨平台的应用开发框架,广泛用于开发GUI应用程序。Qt提供了丰富的GUI组件和工具,能够高效地实现图形界面的设计与开发。C++则作为Qt的底层语言,具有高效的性能和良好的控制力,非常适合用于处理设备与系统之间的数据交互、通信协议的实现和复杂的计算任务。在项目中,Qt被用于开发Windows平台的桌面应用程序以及Android平台的手机APP。Qt框架的跨平台特性使得开发者能够使用同一套代码在不同操作系统上进行构建和部署,大大提高了开发效率。

为了方便开发和调试,上位机的开发采用了Qt Creator作为主要的集成开发环境(IDE)。Qt Creator是一款由Qt官方提供的开发工具,专为Qt应用程序开发设计,支持C++、QML和JavaScript等语言。Qt Creator提供了丰富的功能,如代码编辑、调试、构建、版本控制集成等,能够显著提升开发者的生产力。在本项目中,Qt Creator为开发者提供了自动化构建、界面设计工具(如Qt Designer)和调试工具(如QDebug和QML调试工具),使得开发过程更加高效和流畅。
上位机与硬件设备端的通信采用了基于TCP/IP协议的数据传输方式。为了实现这一功能,Qt提供了丰富的网络编程支持,尤其是QTcpSocketQTcpServer类,使得上位机能够轻松地与硬件设备建立TCP连接,进行数据收发。上位机通过WIFI连接ESP8266-WIFI模块,ESP8266模块创建TCP服务器,上位机应用则作为客户端连接到服务器,进行实时的数据传输与控制命令的下发。
为了满足不同用户的需求,本项目需要支持Windows平台的桌面应用和Android平台的移动APP。Qt的跨平台特性使得开发人员能够在一个代码库下完成多平台应用的开发和移植。开发者仅需要编写一次应用逻辑和用户界面,就可以通过Qt的跨平台构建工具生成Windows和Android两个平台的可执行文件。此外,Qt提供了丰富的文档和社区支持,帮助开发者解决平台差异和兼容性问题,确保应用在不同平台上都能稳定运行。

总体而言,上位机开发环境采用了Qt 5框架和C++语言,结合Qt Creator集成开发环境,提供了一个高效、稳定、跨平台的开发工具链。通过Qt强大的GUI设计、网络通信、多线程支持以及数据库管理功能,开发者能够轻松实现与硬件设备的交互、控制设备、处理传感器数据,并为用户提供直观、流畅的操作体验。

二、算法设计

2.1 算法设计思路

本项目采用栅格地图法(Grid Map)+螺旋清扫+墙边跟随相结合的方式,实现高效率覆盖清扫。

(1)地图构建

  • 将房间划分为二维栅格地图,每个格子表示20cm × 20cm的面积(实际可调整)
  • 格子状态:0=未清扫,1=已清扫,2=障碍物

(2)基本策略

  • 默认从左上角或充电座位置开始清扫
  • 采用螺旋清扫 + Z字形遍历 + 遇墙回转机制,提升效率
  • 实时更新当前位置和地图信息
  • 编码器与MPU6050配合,进行位置估算(简化SLAM)

(3)避障融合

  • 在路径规划过程中融合超声波+红外避障模块,对障碍进行打标(记为2)

(4)完成判断

  • 所有栅格=1(已清扫)时清扫结束,进入回充状态

2.2 核心模块算法流程图

image-20250627222940953

flowchart TD
    A[初始化栅格地图] --> B[定位当前位置(x,y)]
    B --> C[标记当前位置已清扫]
    C --> D[查找下一个可清扫邻格]
    D -->|存在| E[规划方向移动]
    D -->|无| F[回退/掉头/回充]
    E --> G[检测障碍]
    G -->|无障碍| H[移动到新位置]
    G -->|有障碍| I[标记障碍格,换方向]
    H --> B
    I --> B
    F --> J[全部完成 -> 回充]

2.3 STM32简化路径规划算法代码(伪代码 + 可移植C代码)

1. 栅格地图结构定义

#define MAP_SIZE_X 20
#define MAP_SIZE_Y 20

#define CELL_UNVISITED 0
#define CELL_VISITED   1
#define CELL_OBSTACLE  2

uint8_t map[MAP_SIZE_Y][MAP_SIZE_X];  // 2D 栅格地图
int current_x = 0;
int current_y = 0;
int direction = 0;  // 0=上,1=右,2=下,3=左

2. 标记当前位置已清扫

void mark_visited(int x, int y) {
    if (x >= 0 && x < MAP_SIZE_X && y >= 0 && y < MAP_SIZE_Y) {
        map[y][x] = CELL_VISITED;
    }
}

3. 查找下一个可清扫格子(四方向)

int dx[4] = {0, 1, 0, -1}; // 上右下左
int dy[4] = {-1, 0, 1, 0};

int find_next_direction() {
    for (int i = 0; i < 4; i++) {
        int nx = current_x + dx[i];
        int ny = current_y + dy[i];
        if (nx >= 0 && nx < MAP_SIZE_X && ny >= 0 && ny < MAP_SIZE_Y) {
            if (map[ny][nx] == CELL_UNVISITED) {
                return i;
            }
        }
    }
    return -1; // 无可清扫方向
}

4. 移动函数(伪动作控制)

void move_to(int dir) {
    // 电机控制部分略(根据dir控制左右轮转速方向)
    current_x += dx[dir];
    current_y += dy[dir];
    mark_visited(current_x, current_y);
}

5. 主控制循环(主逻辑)

void clean_room() {
    mark_visited(current_x, current_y); // 初始位置

    while (1) {
        int next_dir = find_next_direction();
        if (next_dir == -1) {
            // 所有方向均已访问或是障碍,尝试回退或结束
            if (all_cleaned()) {
                return_to_charge(); // 所有清扫完成
                break;
            } else {
                rotate_90(); // 更换方向
                continue;
            }
        }

        if (!is_obstacle(current_x + dx[next_dir], current_y + dy[next_dir])) {
            move_to(next_dir);
        } else {
            map[current_y + dy[next_dir]][current_x + dx[next_dir]] = CELL_OBSTACLE;
        }
    }
}

6. 判断是否清扫完毕

int all_cleaned() {
    for (int y = 0; y < MAP_SIZE_Y; y++) {
        for (int x = 0; x < MAP_SIZE_X; x++) {
            if (map[y][x] == CELL_UNVISITED) return 0;
        }
    }
    return 1;
}

2.4 边缘检测与防跌落功能算法设计过程

1. 传感器选型

采用 3个 TCRT5000 红外反射式跌落检测传感器 安装于机器人底部前端和左右两侧,用于检测地面是否存在反射(白色地面为反射,悬空为无反射)。

2. 原理说明

  • TCRT5000发射红外光并接收反射光,若有地面反射回红外光,则表示有地面;
  • 若前方/左侧/右侧无反射光(即信号电平改变),则判定为“边缘”或“悬空”,触发防跌落动作。

3. 传感器安装建议

  • 每个TCRT5000传感器对应一个检测区域:
    • 前部传感器:防止前进跌落
    • 左侧/右侧传感器:防止侧滑跌落
  • 建议安装高度约为 0.8~1.2cm,距离地面

4. 防跌落处理机制

  • 一旦某个传感器检测为无地面(悬空):
    • 立即停止所有电机
    • 后退一小段距离
    • 左/右转避开边缘
    • 重新进入正常清扫逻辑

2.5 STM32 防跌落算法设计(代码实现)

(1)接口定义与引脚配置(示例使用 GPIO 输入)

假设连接如下:

  • 前TCRT5000 —— GPIOA PIN0
  • 左TCRT5000 —— GPIOA PIN1
  • 右TCRT5000 —— GPIOA PIN2
#define SENSOR_FRONT   HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)
#define SENSOR_LEFT    HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1)
#define SENSOR_RIGHT   HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2)
  • TCRT5000输出为 低电平表示地面存在高电平表示无地面/悬空

(2)初始化 GPIO 输入

void TCRT5000_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

(3)检测边缘函数

uint8_t is_edge_detected(void)
{
    if (SENSOR_FRONT == GPIO_PIN_SET ||
        SENSOR_LEFT == GPIO_PIN_SET ||
        SENSOR_RIGHT == GPIO_PIN_SET)
    {
        return 1;  // 检测到边缘
    }
    return 0;  // 正常地面
}

(4)防跌落动作处理函数

void handle_fall_protection(void)
{
    stop_motors();  // 停止所有电机

    delay_ms(200);  // 稍作停顿

    move_backward();  // 后退一小段
    delay_ms(500);

    turn_right();  // 随机右转避开边缘
    delay_ms(400);

    stop_motors();
}

(5)集成进主循环

void main_loop(void)
{
    while (1)
    {
        if (is_edge_detected())
        {
            handle_fall_protection();  // 边缘检测触发处理
            continue;
        }

        clean_forward();  // 正常前进清扫
        delay_ms(100);
    }
}

三、Qt开发入门与环境搭建

当前项目的上位机是采用Qt开发的,这一章节主要是介绍Qt开发环境的安装,以及Qt开发环境入门的使用。如果你Qt没有任何基础,建议仔细看一遍。

3.1 Qt是什么?

Qt 是一个功能强大、跨平台的应用程序开发框架,主要用于创建图形用户界面(GUI)应用程序,但它不仅仅局限于GUI编程。它由挪威的奇趣科技(TrollTech)最初于1991年开发,并在后续的发展历程中经历了多次所有权变更,包括诺基亚和Digia等公司接手,现在Qt属于The Qt Company所有。

Qt 主要特点和优势包括:

(1)跨平台:Qt 支持多种操作系统,开发者可以使用同一份源代码在不同平台上编译运行,如Windows、Linux、macOS、Android以及各种嵌入式系统(如RTOS),实现“一次编写,到处编译”。

(2)C++ 开发:Qt 的核心是基于C++编程语言构建,提供了一套丰富的类库,通过面向对象的设计方式简化了开发过程。

(3)图形用户界面:Qt 提供了完整的GUI组件集,包含窗口、按钮、标签、文本框等各种标准控件,以及布局管理器、样式表等功能,使得开发者能够高效地创建美观且功能完善的桌面应用或移动应用界面。

(4)工具链完整:Qt 包含一系列集成开发环境(IDE)和辅助工具,例如Qt Creator是一个全能的跨平台IDE,Qt Designer用于可视化拖拽设计UI界面,Qt Linguist支持国际化资源文件的翻译,还有Qt Assistant和大量文档资源方便开发者的使用。

(5)非GUI功能丰富:除了GUI功能外,Qt 还提供了众多非图形化功能模块,如网络通信、数据库访问、XML处理、多媒体处理(音频视频)、文件I/O、线程与并发处理、OpenGL和3D图形渲染等。

(6)元对象系统:Qt 使用元对象系统(Meta-Object System, MOC)实现了信号与槽机制(Signals and Slots),这是一种高级事件处理机制,允许在不同对象之间安全地进行异步通信。

(7)可扩展性与灵活性:Qt 架构高度灵活,支持插件体系结构,开发者可以根据需要自定义组件并轻松地集成到Qt应用中。

Qt 以其强大的跨平台能力和全面的功能集合成为许多企业和个人开发者选择用来开发高性能、高稳定性的应用程序的重要工具之一,被广泛应用于各类桌面软件、嵌入式设备、移动应用以及服务器端组件等领域。

3.2 Qt版本介绍

在Qt发行版本中将要涉及两个版本:Qt商业授权和Qt开源授权。

(1)Qt商业授权是设计商业软件的开发环境,这些商业软件使用了传统的商业来发布,它包含了一些更新的功能、技术上的支持和大量的解决方案,开发了使用于行业的一些特定的组件,有一些特殊的功能只在商业用户中使用。

(2)Qt开源授权是用来开发开源的软件,它提供了一些免费的支持,并遵循QPL协议。

开放源代码是免费的软件,不牵涉用户的某些权益。任何人都有使用开源软件和参与它的修改的机会,这就意味着其他的人同样可获得你开发的代码。目前 Qt 的开源授权有两种,一种是 GPL 授权,另一种是 LGPL 授权。

3.3 Qt开发环境安装

Qt的中文官网: https://www.qt.io/zh-cn/image-20221207160550486

image-20221207160606892

QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6

打开下载链接后选择下面的版本进行下载:

qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details

软件安装时断网安装,否则会提示输入账户。

如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink

安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。

image-20221203151742653

选择MinGW 32-bit 编译器:

image-20221203151750344

3.4 开发第一个QT程序

在QT开发过程中,可以手动编写代码也可以使用UI设计师直接拖拽控件的方式编写界面和布局,在实际的开发过程中一般是两种方式结合使用,提高开发效率。

本小节用一个简单的 “Hello QT” 程序介绍一下使用QtCreator新建工程的步骤

(1)打开QtCreator软件,选择New Project,新建一个工程。

image-20240304134953164

(2)项目模板选择QT Widgets Application

image-20240304135416497

(3)设置项目名称和存放路径

注意:QT项目路径和名称不能出现中文字符。

image-20240304135504345

(4)编译工具套件选择

编译工具套件可以后面自己增加,比如增加Android的。套件是指 Qt 程序从编译链接到运行环境的全部工具和 Qt 类库的集合。

image-20240304135535341

(5)设置生成的类信息

在类信息设置界面选择基类,目前有三种基类:QMainWindow,QWidget,QDialog。在基类里选择QMainWindow,类名和文件名会根据基类自动修改,一般不需要修改,默认即可。

image-20240304135630942

(6)项目管理

在项目管理界面可以设置作为子项目,以及加入版本控制系统。这两个功能暂时用不到,都用默认的 ,然后点击 “完成”。

image-20240304135652922

(7)创建完成

image-20240304135728165

(8) 编辑代码

展开main.cpp文件,添加内容如下:

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QLabel>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //MainWindow w;
    //w.show();
    QLabel *label =new QLabel("Hello Qt!");
    label->setGeometry(400,100,100,20);
    label->show();
    return a.exec();
}

代码解析:

1)	#include <QApplication>和 #include <QLabel>是QT的类声明头文件,对于每个QT类都有一个与该类同名的头文件,在这个头文件包含了对该类的定义。
2)	main(int argc, char *argv[]) :main函数的标准写法。
3)	QApplication a(argc, argv):创建一个QApplication对象,用于管理应用程序的资源,QApplication类的构造函数需要两个参数。
4)	QLabel *label =new QLabel("Hello Qt!") :创建QLabel窗口部件,QLabel是一个Qt提供的窗口部件,可以用来显示一行文本。
5)	label->setGeometry(400,100,100,20) : 设置控件显示的位置。
6)	label->show():使Qlabel创建的窗口可见,就是显示设置的文本。
7)	return a.exec():应用程序将控制权传递给QT,让程序进入消息循环。等待可能的菜单,工具条,鼠标等的输入,进行响应。

image-20240304135908750

(9)行程序

运行程序可以点击左下角的三角形符号或者按下快捷键Ctrl+R。

image-20240304135938848

3.5 调试输出

QT中使用QDebug类输出调试信息。主要用于调试代码,类似于std::cout的替代品,支持QT的数据类型。使用前需要包含头文件。

调试输出的分类

qDebug 调试信息提示
qWarning 一般的警告提示
qCritical 严重错误提示
qFatal 致命错误提示

示例代码:

qDebug("调试信息输出");
qWarning("一般警告信息输出");
qCritical("严重错误输出");
qFatal("致命错误输出");

qDebug输出的信息会打印到QT软件下边的输出面板。

在上节的HelloQt工程上加上调试输出代码,增加的main.cpp代码如下:

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //MainWindow w;
    //w.show();
    qDebug()<<"QT调试信息输出";
    int data_int=8888;
    qDebug()<<data_int;
    float data_float=123.888;
    qDebug()<<data_float;
    return a.exec();
}

运行程序,观察输出的调试信息:

image-20240304140142790

3.6 QT Creator常用的快捷键

掌握一些适用的快捷键,可以提高程序开发的效率。

(1)F1 键,快速切换光标选中的函数或者类的帮助信息,按一次半屏显示,按下两次全屏显示。

(2)F2 键,快速切换到光标选中的函数或者类的源码定义处。

(3)F4键,快速在源文件和头文件之间切换。

(4)Ctrl(按住)+ Tab,快速切换已打开的文件

(5)Ctrl+ I ,缩进光标选中行代码(自动与上层代码对齐)。

(6)Ctrl + / ,快速注释或者取消注释光标选中行。

(7)快速修改全局变量名

鼠标光标选中变量名,按下Ctrl+Shift+R,当变量名称出现红色框表示已经激活全局修改功能。修改一处,整个工程对应变量名称全部会修改。修改完毕之后,光标移开,再按下Ctrl+Shift+R保存修改。

image-20240304140242113

(8)快速修改全局函数名

快捷方式与变量修改一样按下Ctrl+Shift+R,一处修改整个工程对应的函数名称也会跟着改。选中函数后,按下Ctrl+Shift+R后整个工程的对应的函数名会高亮,并且在软件下方弹出修改框。

image-20240304140311742

3.7 QT帮助文档

Qt 帮助文档太多,难以全部翻译成中文,即使翻译了一部分,翻译花的时间太多,翻译更新的时效性也难以保证,最终还是得看英文帮助,QtCreator 集成了帮助系统,查找非常方便。

打开QtCreator,选择菜单栏的最左边的帮助选项,界面如下:

image-20240304140337833

(1)查看Qlabel控件的帮助信息:

image-20240304140357011

3.8 UI设计师使用

上节的Hello QT程序使用纯C++代码编写,这一节使用QT界面设计模式实现与上一节Hello QT程序一样的功能。仿照着上节新创建一个工程。双击打开mainwindow.ui文件,进入到UI设计界面。

(1)拖一个Label控件到编辑区,双击Label控件可以修改文本内容。

image-20240304140517858

(2)运行程序可以点击左下角的三角形符号或者按下快捷键Ctrl+R。

image-20240304140600717

(3)UI设计师界面功能介绍

image-20240304140615717

3.9 按钮控件组

QT Creator UI设计师界面的按钮组截图如下:

image-20240304140809093

以下是对按钮组控件的一些功能介绍:

(1)Push Button按压按钮:最普通的按钮,按(点击)按钮命令计算机执行一些动作,或者回答问题,比如windows开始菜单里的重启,注销,关机等按钮。

(2)Tool Button工具按钮:工具按钮通常是一个集合,一般集成在工具栏里。比如打开,保存,复制,粘贴,剪切等常用的操作。

(3)Radio Button单选按钮:单选按钮通常是两个以上的形式出现在一块,按钮之间有互斥关系,每次只能选中一个。比如:一个人的性别只能选择一个,不能同时是男性又是女性。

(4)Check Box复选框:复选框与单选按钮概念相反,复选框通常表示多个可以同时存在的选项,比如一个人可以同时拥有多个爱好,比如读书、看电影、爬山、游泳等。

(5)Command Link Button命令链接按钮:一般用来打开的窗口或者网页链接。

(6)Dialog Button Box标准按钮盒:标准按钮盒通常用于对话框程序;比如:常见的确认对话框有 “确定”“取消”等标准按钮,Qt 将这些典型的按钮做成标准按钮盒,并将相应的信号加以封装,方便程序员使用。

3.10 布局控件组

开发一个图形界面应用程序,界面的布局影响到界面的美观。前面的程序中都是使用UI界面拖控件,如果有多个按钮,会出现大小难调整、位置难对齐等问题。Qt 提供的“布局管理“就很好的解决了控件摆放的问题。

以下是UI设计师界面的布局相关控件组:

image-20240304140914361

功能介绍:

(1)Vertical Layout:垂直布局

(2)Horizontal Layout:水平布局

(3)Grid Layout:网格布局

(4)Form Layout:窗体中布局

(5)Horizontal Spacers:水平空格,在布局中用来占位。

(6)Vertical Spacer:垂直空格,在布局中用来占位。

image-20240304140956243

3.11 基本布局控件

在UI设计界面添加一个布局控件,然后将需要布局的其他控件放入布局控件中即可完成布局,布局控件可以互相嵌套使用。(本节只介绍基本布局控件的使用)

以下是4种布局控件的效果:

image-20240304141035428

3.12 UI设计师的布局功能

在UI设计界面的左上角有一排快捷的布局选项,使用时选中两个以上的控件,点击其中一种布局方式就可以切换布局。

以下为布局的简单示例图:

image-20240304141115657

(1)为布局的选项。

(2)控件层次图,可以看到控件的布局摆放层次。

如果想要控制某个控件的固定大小,不随着布局改变大小,可以限定最大最小尺寸。选中控件鼠标右键–>大小限定->设置大小。

image-20240304141311256

水平布局与垂直布局:

image-20240304141335977

image-20240304141347209

水平布局将控件按照水平方式摆放,垂直布局将控件按照垂直方式摆放。鼠标拖动红色布局框上的黑色方点,可以调整布局框的大小。随着布局框的尺寸变化,包含的控件高度不会变化,宽度会随着布局框变化。选中其中一个控件然后鼠标右键>点击大小限定,可以限定控件的最大和最小尺寸。

分裂器水平布局与垂直布局:

image-20240304141412287

image-20240304141426088

分裂器方式布局,包含控件的高度和宽度都会随着布局框的拉伸而改变。选中其中一个控件然后鼠标右键>点击大小限定,可以限定控件的最大和最小尺寸。

窗体中布局与栅格布局:

image-20240304141449390

栅格(网格)布局器的基本单元是单元格,而窗体中布局(表单)的基本单元是行。随着布局框的尺寸变化,包含的控件高度不会变化,宽度会随着布局框变化。

设置主窗体布局方式:

设置主窗体的布局方式后,包含在主窗体内的控件会随着窗体的拉伸自动调整大小。

image-20240304141518067

image-20240304141529003

四、上位机开发

4.1 Qt开发环境安装

Qt的中文官网: https://www.qt.io/zh-cn/image-20221207160550486

image-20221207160606892

QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6

打开下载链接后选择下面的版本进行下载:

如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink

软件安装时断网安装,否则会提示输入账户。

安装的时候,第一个复选框里的编译器可以全选,直接点击下一步继续安装。

image-20221203151742653

选择编译器: (一定要看清楚了)

image-20241028152725134

4.2 新建上位机工程

前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。

【1】新建工程

image-20240117144052547

【2】设置项目的名称。

image-20250420200347498

【3】选择编译系统

image-20240117144239681

【4】选择默认继承的类

image-20240117144302275

【5】选择编译器

image-20241028153603487

【6】点击完成

image-20240117144354252

【7】工程创建完成

image-20250420200411303

4.3 切换编译器

在左下角是可以切换编译器的。 可以选择用什么样的编译器编译程序。

目前新建工程的时候选择了2种编译器。 一种是mingw32这个编译Windows下运行的程序。 一种是Android编译器,可以生成Android手机APP。

不过要注意:Android的编译器需要配置一些环境才可以正常使用,这个大家可以网上找找教程配置一下就行了。

windows的编译器就没有这么麻烦,安装好Qt就可以编译使用。

下面我这里就选择的 mingw32这个编译器,编译Windows下运行的程序。

image-20250420200424965

4.4 编译测试功能

创建完毕之后,编译测试一下功能是否OK。

点击左下角的绿色三角形按钮

image-20250420200442769

正常运行就可以看到弹出一个白色的框框。这就表示工程环境没有问题了。 接下来就可以放心的设计界面了。

image-20250420200457319

4.5 设计UI界面与工程配置

【1】打开UI文件

image-20250420200514220

打开默认的界面如下:

image-20250420200526194

【2】开始设计界面

根据自己需求设计界面。

五、STM32代码设计

5.1 硬件连线说明

序号 传感器模块 信号类型 接STM32引脚 说明
1 红外避障传感器 ×3 数字输入 PA0(前) PA1(左) PA2(右) 高电平=障碍物,低电平=无障碍
2 超声波测距模块 HC-SR04 数字IO TRIG: PB0 ECHO: PB1 发送/接收测距信号
3 红外跌落传感器 ×3 数字输入 PA3(前) PA4(左) PA5(右) 高电平=悬空,低电平=有地面
4 MPU6050 姿态模块 I2C通信 SDA: PB7 SCL: PB6 默认地址0x68
5 灰尘传感器 GP2Y1010 模拟输出 PA6 连接ADC采集灰尘浓度
6 DS3231 RTC时钟模块 I2C通信 SDA: PB7 SCL: PB6 与MPU6050共用I2C总线
7 电压检测模块 模拟输出 PA7 电池电压模拟量检测
8 DFPlayer Mini语音模块 串口通信 TX: PA9 RX: PA10 使用USART1
9 ESP8266通信模块 串口通信 TX: PB10 RX: PB11 使用USART3
10 OLED 显示屏(0.96寸) I2C通信 SDA: PB9 SCL: PB8

5.2 传感器代码

当前项目使用的相关软件工具已经上传到网盘:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink

1. GPIO 输入配置(避障、跌落)

void GPIO_Sensor_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 避障与跌落传感器输入引脚:PA0~PA5
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

2. ADC 模拟输入配置(灰尘浓度、电压检测)

void ADC_Init(void)
{
    ADC_HandleTypeDef hadc1;

    __HAL_RCC_ADC1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;  // PA6:灰尘,PA7:电压
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    HAL_ADC_Init(&hadc1);
}

读取ADC值函数(灰尘或电压):

uint16_t Read_ADC_Value(ADC_HandleTypeDef* hadc, uint32_t channel)
{
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = channel;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
    HAL_ADC_ConfigChannel(hadc, &sConfig);

    HAL_ADC_Start(hadc);
    HAL_ADC_PollForConversion(hadc, HAL_MAX_DELAY);
    uint16_t value = HAL_ADC_GetValue(hadc);
    HAL_ADC_Stop(hadc);

    return value;
}

3. 超声波测距控制(TRIG/ECHO)

#define TRIG_PIN    GPIO_PIN_0
#define TRIG_PORT   GPIOB
#define ECHO_PIN    GPIO_PIN_1
#define ECHO_PORT   GPIOB

void Ultrasonic_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = TRIG_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(TRIG_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = ECHO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(ECHO_PORT, &GPIO_InitStruct);
}

uint32_t Read_Ultrasonic(void)
{
    uint32_t t1, t2;

    HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET);
    HAL_Delay(0.01);
    HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET);

    while(HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) == GPIO_PIN_RESET);
    t1 = DWT->CYCCNT;
    while(HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) == GPIO_PIN_SET);
    t2 = DWT->CYCCNT;

    return (t2 - t1) / 72 / 58;  // 距离 cm(STM32 72MHz)
}

4. MPU6050、RTC、OLED 初始化建议(使用 I2C)

// I2C2 for MPU6050 + RTC
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 400000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c2);

5. 串口初始化(语音/ESP8266通信)

// USART1 (PA9/PA10) for DFPlayer
// USART3 (PB10/PB11) for ESP8266

void UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 9600;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);

    huart3.Instance = USART3;
    huart3.Init.BaudRate = 115200;
    huart3.Init.WordLength = UART_WORDLENGTH_8B;
    huart3.Init.StopBits = UART_STOPBITS_1;
    huart3.Init.Parity = UART_PARITY_NONE;
    huart3.Init.Mode = UART_MODE_TX_RX;
    huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart3.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart3);
}

5.3 项目核心代码

当前项目使用的相关软件工具已经上传到网盘:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink

(1)main.c 核心主流程框架

#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "i2c.h"
#include "adc.h"
#include "tim.h"
#include "oled.h"
#include "motor.h"
#include "sensor.h"
#include "wifi.h"
#include "voice.h"
#include "rtc.h"
#include "mpu6050.h"
#include "path_planning.h"

void SystemClock_Config(void);

int main(void)
{
    HAL_Init();
    SystemClock_Config();

    // 初始化外设
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USART3_UART_Init();
    MX_ADC1_Init();
    MX_I2C1_Init();
    MX_I2C2_Init();
    MX_TIM2_Init();
    MX_TIM3_Init();

    // 模块初始化
    OLED_Init();
    Motor_Init();
    Sensor_Init();
    Voice_Init();
    MPU6050_Init();
    RTC_Init();
    WiFi_Init();

    OLED_ShowString(0, 0, "Robot Start");
    Voice_Play(1); // 播放“启动成功”

    while (1)
    {
        if (RTC_CheckSchedule())  // 是否到达清扫时间
        {
            Clean_Start();
        }

        WiFi_Handle();  // MQTT通信处理

        HAL_Delay(100);  // 轮询
    }
}

(2)扫地逻辑主控制 Clean_Start()

void Clean_Start(void)
{
    OLED_ShowString(0, 1, "Cleaning...");
    Voice_Play(2); // “开始清扫”

    PathPlanner_Init(); // 初始化路径栅格

    while (!PathPlanner_Finished())
    {
        if (Sensor_IsFallDetected())
        {
            Motor_Stop();
            Voice_Play(3);  // “检测到边缘”
            Clean_EscapeEdge();
            continue;
        }

        if (Sensor_IsObstacleAhead())
        {
            Motor_Stop();
            Voice_Play(4);  // “前方有障碍”
            Clean_AvoidObstacle();
            continue;
        }

        if (Battery_Low())
        {
            Motor_Stop();
            Voice_Play(5);  // “电量不足,返回充电”
            Go_To_ChargingDock();
            return;
        }

        PathPlanner_Move();  // 路径规划并移动
        Sensor_CheckDustLevel(); // 检测灰尘情况,决定清扫强度
        WiFi_UploadStatus();  // 上传当前位置与状态
        HAL_Delay(100);
    }

    OLED_ShowString(0, 1, "Done!");
    Voice_Play(6); // “清扫完成”
    Go_To_ChargingDock();
}

(3)边缘检测与防跌落处理函数

void Clean_EscapeEdge(void)
{
    Motor_Backward();
    HAL_Delay(500);
    Motor_TurnRight();
    HAL_Delay(300);
    Motor_Stop();
}

(4)避障处理函数

void Clean_AvoidObstacle(void)
{
    Motor_Backward();
    HAL_Delay(300);
    Motor_TurnLeft();
    HAL_Delay(500);
    Motor_Stop();
}

(5)路径规划(Z字遍历)

int map[20][20];
int cur_x = 0, cur_y = 0, dir = 1;

void PathPlanner_Init(void)
{
    memset(map, 0, sizeof(map));
    cur_x = 0;
    cur_y = 0;
    dir = 1;
}

void PathPlanner_Move(void)
{
    map[cur_y][cur_x] = 1; // 标记已清扫

    int next_x = cur_x + (dir == 1 ? 1 : -1);
    if (next_x >= 0 && next_x < 20)
    {
        cur_x = next_x;
    }
    else
    {
        cur_y++;
        dir = -dir;
    }

    Motor_Forward();
    HAL_Delay(200);
    Motor_Stop();
}

int PathPlanner_Finished(void)
{
    return cur_y >= 20;
}

(6)传感器检测函数(sensor.c

uint8_t Sensor_IsFallDetected(void)
{
    return HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_SET ||  // 前
           HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_SET ||  // 左
           HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_SET;    // 右
}

uint8_t Sensor_IsObstacleAhead(void)
{
    return HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET;  // 前避障传感器
}

void Sensor_CheckDustLevel(void)
{
    uint16_t val = ADC_ReadValue(ADC_CHANNEL_6); // GP2Y1010 on PA6
    if (val > 3000)
    {
        Motor_SetSpeed(HIGH); // 增强清扫
    }
    else
    {
        Motor_SetSpeed(NORMAL);
    }
}

(7)语音提示控制(DFPlayer)

void Voice_Play(uint8_t track)
{
    uint8_t cmd[] = {0x7E, 0xFF, 0x06, 0x03, 0x00, 0x00, track, 0xEF};
    HAL_UART_Transmit(&huart1, cmd, sizeof(cmd), 100);
}

(8)WIFI与MQTT通信处理

void WiFi_Handle(void)
{
    if (ESP8266_ReceiveMQTT("robot/ctrl") == CMD_STOP)
    {
        Motor_Stop();
        Voice_Play(7); // “收到停止命令”
    }
}

void WiFi_UploadStatus(void)
{
    char buf[64];
    sprintf(buf, "{\"x\":%d,\"y\":%d,\"bat\":%d}", cur_x, cur_y, Battery_GetLevel());
    ESP8266_PublishMQTT("robot/status", buf);
}

(9)回充定位处理

void Go_To_ChargingDock(void)
{
    // 简化逻辑:持续前进直到检测到红外充电基座信号
    while (!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)) // 充电基座红外
    {
        Motor_Forward();
        HAL_Delay(100);
    }
    Motor_Stop();
    Voice_Play(8); // “已回到充电桩”
}

5.4 程序下载

也有视频教程:

讲解如何编译代码,下载STM32程序: https://www.bilibili.com/video/BV1Cw4m1e7Yc

打STM32的keil工程,编译代码、然后,使用USB线将开发板的左边的USB口(串口1)与电脑的USB连接,打开程序下载软件下载程序。

具体下载过程看下面图:

image-20240319223247836

打开程序下载软件:[软件就在资料包里的软件工具目录下]

image-20240120160735942

5.5 程序正常运行效果

设备运行过程中会通过串口打印调试信息,我们可以通过串口打印了解程序是否正常。

程序下载之后,可以打开串口调试助手查看程序运行的状态信息。[软件就在资料包里的软件工具目录下]

image-20240327212042050

5.6 取模软件的使用

显示屏上会显示中文,字母,数字等数据,可以使用下面的取模软件进行取模设置。

[软件就在资料包里的软件工具目录下]

image-20241024142522970

打开软件之后:

image-20241127212320020

六、总结

本项目以STM32F103RCT6为核心控制器,完成了一套功能完善、运行稳定的扫地机器人系统设计与实现。系统融合了路径规划、障碍物避让、边缘检测、防跌落控制、灰尘识别、自动回充、定时清扫、状态显示与语音提示等多种功能,具备较强的环境适应性与实用性。整机通过多传感器协同感知环境变化,并结合智能算法进行决策,使得机器人能高效、安全地完成全覆盖式清扫任务。

在系统软硬件设计方面,充分发挥了STM32微控制器资源丰富、接口灵活、运算能力强等优势。硬件模块选型明确,接口连接合理,保障了系统稳定运行。软件部分采用模块化开发思路,逻辑清晰,功能划分明确,便于后期维护与扩展。同时,通过ESP8266模块实现了与手机APP之间的远程通信,增强了用户交互能力和系统智能化水平。

通过本项目的开发与调试,进一步验证了STM32在智能机器人应用中的可行性和实用性,提升了开发者在嵌入式系统设计、智能控制、通信协议、传感器融合等方面的综合能力。项目成果在家庭清洁机器人领域具有良好的推广价值和应用前景。


网站公告

今日签到

点亮在社区的每一天
去签到