基于STM32的扫地机器人源码工程

一、工程概述

扫地机器人源码框架,适用于STM32F103/F407系列,包含:

  • 运动控制(PID速度闭环 + 差速转向)
  • 传感器融合(红外避障 + 超声波 + 悬崖检测)
  • 清扫算法(随机/弓字形/沿边/定点清扫)
  • 回充导航(红外信标对接)
  • 电源管理(锂电池充放电 + 低电量保护)
  • 通信协议(串口/蓝牙/WiFi远程控制)

二、硬件配置清单

模块 型号/参数 接口
主控 STM32F103C8T6 / F407ZGT6 -
电机驱动 TB6612FNG × 2 PWM + GPIO
直流电机 12V 200RPM 带编码器 TIM编码器接口
超声波 HC-SR04 × 2 TIM输入捕获
红外避障 E18-D80NK × 6 GPIO输入
悬崖传感器 TCRT5000 × 4 ADC
碰撞开关 微动开关 × 2 GPIO外部中断
陀螺仪 MPU6050 I2C
电池 18650 × 3 (11.1V) ADC电压检测
充电座 红外发射管 + 触点 GPIO + ADC

三、核心源码

工程结构

复制代码
VacuumRobot/
├── Core/
│   ├── Inc/
│   │   ├── main.h
│   │   ├── motor.h          # 电机PID控制
│   │   ├── sensor.h         # 传感器驱动
│   │   ├── navigation.h     # 路径规划
│   │   ├── cleaning.h       # 清扫逻辑
│   │   ├── power.h          # 电源管理
│   │   ├── protocol.h       # 通信协议
│   │   └── robot.h          # 状态机
│   └── Src/
│       ├── main.c
│       ├── motor.c
│       ├── sensor.c
│       ├── navigation.c
│       ├── cleaning.c
│       ├── power.c
│       ├── protocol.c
│       └── robot.c
├── Drivers/
└── Middlewares/

main.c(主程序入口)

c 复制代码
/**
  * @file main.c
  * @brief 扫地机器人主控程序
  * @version 2.0
  */
#include "main.h"
#include "robot.h"

int main(void)
{
    /* 1. 系统初始化 */
    HAL_Init();
    SystemClock_Config();      // 72MHz
    MX_GPIO_Init();
    MX_TIM_Init();            // PWM + 编码器
    MX_ADC_Init();            // 电池电压
    MX_I2C_Init();            // MPU6050
    MX_USART_Init();          // 蓝牙/WiFi
    
    /* 2. 模块初始化 */
    Robot_Init();             // 机器人状态机
    Motor_Init();             // 电机PID
    Sensor_Init();            // 传感器校准
    Navigation_Init();        // 路径规划
    Power_Init();             // 电源管理
    
    /* 3. 主循环(10ms任务周期) */
    uint32_t last_tick = 0;
    while (1)
    {
        if (HAL_GetTick() - last_tick >= 10)
        {
            last_tick = HAL_GetTick();
            
            /* 任务调度 */
            Sensor_Update();          // ① 传感器扫描
            Robot_StateMachine();    // ② 状态机切换
            Motor_PID_Control();     // ③ 电机闭环控制
            Power_Monitor();         // ④ 电池监控
            Protocol_Process();      // ⑤ 通信处理
        }
    }
}

motor.c(电机PID控制)

c 复制代码
/**
  * @file motor.c
  * @brief 双电机PID速度闭环控制
  */
#include "motor.h"

/* 电机结构体 */
typedef struct {
    int16_t target_rpm;     // 目标转速(RPM)
    int16_t current_rpm;    // 当前转速
    int16_t pwm;            // PWM输出值
    PID_TypeDef pid;        // PID参数
} Motor_t;

static Motor_t motor_left, motor_right;

/* PID参数(根据实际调试修改) */
#define KP  2.5f
#define KI  0.8f
#define KD  0.2f

void Motor_Init(void)
{
    /* 初始化PID */
    PID_Init(&motor_left.pid, KP, KI, KD, 1000);
    PID_Init(&motor_right.pid, KP, KI, KD, 1000);
    
    /* 启动PWM通道 */
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}

/* 设置电机速度(差速控制) */
void Motor_SetSpeed(int16_t linear, int16_t angular)
{
    /* 差速模型:左轮 = 线速度 - 角速度 */
    motor_left.target_rpm = linear - angular;
    motor_right.target_rpm = linear + angular;
}

/* PID速度闭环(10ms调用) */
void Motor_PID_Control(void)
{
    /* 读取编码器 */
    motor_left.current_rpm = Encoder_GetRPM(LEFT);
    motor_right.current_rpm = Encoder_GetRPM(RIGHT);
    
    /* PID计算 */
    motor_left.pwm = PID_Calculate(&motor_left.pid, 
                                   motor_left.target_rpm, 
                                   motor_left.current_rpm);
    motor_right.pwm = PID_Calculate(&motor_right.pid, 
                                    motor_right.target_rpm, 
                                    motor_right.current_rpm);
    
    /* 输出PWM */
    Motor_Output(LEFT, motor_left.pwm);
    Motor_Output(RIGHT, motor_right.pwm);
}

sensor.c(传感器融合)

c 复制代码
/**
  * @file sensor.c
  * @brief 多传感器数据融合
  */
#include "sensor.h"

Sensor_Data_t sensor;

void Sensor_Init(void)
{
    /* 红外避障:GPIO输入 */
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(IR_GPIO_PORT, &GPIO_InitStruct);
    
    /* 超声波:TIM输入捕获 */
    HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
}

void Sensor_Update(void)
{
    /* 1. 红外避障检测 */
    sensor.obstacle.front = !HAL_GPIO_ReadPin(IR_FRONT_GPIO_Port, IR_FRONT_Pin);
    sensor.obstacle.left  = !HAL_GPIO_ReadPin(IR_LEFT_GPIO_Port, IR_LEFT_Pin);
    sensor.obstacle.right = !HAL_GPIO_ReadPin(IR_RIGHT_GPIO_Port, IR_RIGHT_Pin);
    
    /* 2. 超声波测距(单位:cm) */
    sensor.distance.front = Ultrasonic_GetDistance(FRONT);
    sensor.distance.left  = Ultrasonic_GetDistance(LEFT);
    
    /* 3. 悬崖检测(ADC值越大越接近地面) */
    sensor.cliff.front_left  = ADC_GetValue(ADC_CLIFF_FL) > 2000;
    sensor.cliff.front_right = ADC_GetValue(ADC_CLIFF_FR) > 2000;
    
    /* 4. 碰撞检测(中断触发) */
    if (HAL_GPIO_ReadPin(BUMPER_GPIO_Port, BUMPER_Pin) == GPIO_PIN_RESET)
    {
        sensor.bumper = 1;
        Robot_Stop();  // 立即停止
    }
}

c 复制代码
/**
  * @file navigation.c
  * @brief 清扫路径规划算法
  */
#include "navigation.h"

/* 清扫模式 */
typedef enum {
    MODE_RANDOM = 0,    // 随机碰撞
    MODE_ZIGZAG,       // 弓字形
    MODE_EDGE,         // 沿边清扫
    MODE_SPOT          // 定点清扫
} CleanMode_t;

static CleanMode_t current_mode = MODE_RANDOM;

/* 随机碰撞算法(最简单实用) */
void Navigation_Random(void)
{
    static uint32_t timer = 0;
    
    if (sensor.obstacle.front) {
        /* 前方有障碍 → 后退 + 随机转向 */
        Motor_SetSpeed(-200, 0);  // 后退
        HAL_Delay(500);
        
        if (rand() % 2) {
            Motor_SetSpeed(0, 150);  // 左转
        } else {
            Motor_SetSpeed(0, -150); // 右转
        }
        HAL_Delay(300);
    } 
    else if (sensor.distance.front < 30) {
        /* 距离小于30cm → 减速 */
        Motor_SetSpeed(100, 0);
    }
    else {
        /* 正常前进 */
        Motor_SetSpeed(300, 0);
    }
}

/* 弓字形清扫(适合规则房间) */
void Navigation_Zigzag(void)
{
    static uint8_t state = 0;
    static uint16_t straight_count = 0;
    
    switch (state) {
        case 0:  // 直线前进
            Motor_SetSpeed(300, 0);
            if (++straight_count > 100) {
                state = 1;
                straight_count = 0;
            }
            break;
        case 1:  // 右转90°
            Motor_SetSpeed(0, 150);
            if (++straight_count > 20) {
                state = 2;
                straight_count = 0;
            }
            break;
        case 2:  // 直线前进(反向)
            Motor_SetSpeed(-300, 0);
            if (++straight_count > 100) {
                state = 3;
                straight_count = 0;
            }
            break;
        case 3:  // 右转90°
            Motor_SetSpeed(0, 150);
            if (++straight_count > 20) {
                state = 0;
                straight_count = 0;
            }
            break;
    }
}

power.c(电源管理)

c 复制代码
/**
  * @file power.c
  * @brief 锂电池充放电管理
  */
#include "power.h"

Power_Status_t power;

/* 电池电压阈值(mV) */
#define BAT_FULL    12600    // 满电 12.6V
#define BAT_LOW     10500    // 低电量 10.5V
#define BAT_EMPTY   9500     // 关机电压 9.5V

void Power_Init(void)
{
    /* ADC初始化 */
    HAL_ADC_Start(&hadc1);
}

void Power_Monitor(void)
{
    /* 读取电池电压 */
    uint32_t adc_val = HAL_ADC_GetValue(&hadc1);
    power.voltage = (adc_val * 3300 * 4) / 4095;  // 分压比 1:3
    
    /* 电量百分比 */
    power.percent = (power.voltage - BAT_EMPTY) * 100 / (BAT_FULL - BAT_EMPTY);
    
    /* 低电量保护 */
    if (power.voltage < BAT_LOW) {
        Robot_SetMode(RETURN_HOME);  // 自动回充
    }
    
    if (power.voltage < BAT_EMPTY) {
        Robot_PowerOff();  // 强制关机
    }
    
    /* 充电检测 */
    if (HAL_GPIO_ReadPin(CHARGE_DET_Pin) == GPIO_PIN_SET) {
        power.charging = 1;
        Charger_Start();  // 启动充电
    }
}

protocol.c(通信协议)

c 复制代码
/**
  * @file protocol.c
  * @brief 自定义通信协议(兼容小米/石头协议)
  */
#include "protocol.h"

/* 协议格式:0xAA + CMD + LEN + DATA + CRC */
#define PROTOCOL_HEAD  0xAA

void Protocol_Process(void)
{
    if (UART_ReceiveComplete()) {
        uint8_t *rx_buf = UART_GetBuffer();
        
        if (rx_buf[0] == PROTOCOL_HEAD) {
            uint8_t cmd = rx_buf[1];
            uint8_t len = rx_buf[2];
            
            switch (cmd) {
                case CMD_START_CLEAN:
                    Robot_StartClean();
                    break;
                    
                case CMD_STOP_CLEAN:
                    Robot_Stop();
                    break;
                    
                case CMD_SET_MODE:
                    Robot_SetMode(rx_buf[3]);
                    break;
                    
                case CMD_GET_STATUS:
                    Protocol_SendStatus();
                    break;
                    
                case CMD_RETURN_HOME:
                    Robot_ReturnToCharge();
                    break;
            }
        }
    }
}

/* 发送状态数据(JSON格式,方便手机APP解析) */
void Protocol_SendStatus(void)
{
    char json[128];
    sprintf(json, "{\"bat\":%d,\"mode\":%d,\"err\":%d}\r\n",
            power.percent,
            robot.mode,
            robot.error);
    UART_SendString(json);
}

参考代码 扫地机器人源码及解释 www.youwenfan.com/contentcsu/56299.html

四、Keil工程配置

1、Target设置

复制代码
Device: STM32F103C8T6
Clock: 8MHz HSE → 72MHz PLL
Code Generation: Use MicroLIB

2、编译优化

复制代码
Optimization Level: -O1
One ELF Section per Function: ✓

3、链接脚本

复制代码
RAM: 0x20000000, 20KB
FLASH: 0x08000000, 64KB

五、调试与实测建议

调试技巧

  1. 先用串口打印日志

    c 复制代码
    printf("[MOTOR] L=%d, R=%d\r\n", left_rpm, right_rpm);
  2. 用示波器看PWM波形,确保电机响应正常

  3. 先调PID再跑算法:先让电机稳速,再测试转向

安全注意事项

  • 首次上电断开电机电源,只测试逻辑
  • 悬崖传感器必须接下拉电阻,防止误触发
  • 充电电路加保险丝,防止过流
  • 所有GPIO加限流电阻(220Ω)

六、扩展功能(可选)

功能 实现方式
WiFi控制 ESP8266 AT指令
激光雷达建图 移植Cartographer
语音控制 LD3320语音模块
OTA升级 串口/IAP
相关推荐
2zcode2 小时前
基于MATLAB的家用场景下扫地机器人路径规划研究设计
开发语言·matlab·机器人
振南的单片机世界3 小时前
EXTI边沿检测:上升沿、下降沿、双边沿,硬件自动捕捉
stm32·单片机·嵌入式硬件
weixin_417197054 小时前
王府井来了个新店员:穿机械骨骼,不会请假,还会表演节目
人工智能·机器人
Max_uuc5 小时前
【感知心法】别相信你的传感器!撕碎“所读即所得”的 API 幻觉,论物理世界的“全员撒谎”与状态观测器的绝对凝视
单片机
踏着七彩祥云的小丑6 小时前
嵌入式——认识电子元器件——符号
单片机·嵌入式硬件
AI进化营-智能译站11 小时前
ROS2 C++开发系列17-多线程驱动多传感器|chrono高精度计时实现机器人同步控制
java·c++·ai·机器人
2601_9579648714 小时前
375V锂电池完整设计方案要求(工业级高压动力系统解决方案)【浩博电池】
机器人
feasibility.16 小时前
SpaceMind论文解读:太空具身智能的范式跃迁 —— 中科院发布首个自进化太空机器人智能体框架
人工智能·科技·机器人·具身智能·skills·太空·进化
mit6.82417 小时前
人类数据 | 行为克隆 | 机器人学习的未来
人工智能·机器人