基于STM32F103+FreeRTOS的扫地机器人工程框架(简化版)

基于STM32F103+FreeRTOS的扫地机器人工程框架

一、项目说明

重要声明:本工程为简化版扫地机器人框架,基于STM32F103C8T6和FreeRTOS实现核心功能(电机控制、传感器采集、避障逻辑),非小米扫地机器人真实源码(商业源码受知识产权保护,无法公开)。框架模拟了扫地机器人的基本架构,可用于学习嵌入式实时系统设计、FreeRTOS任务调度、电机控制及传感器融合等核心技术。

二、系统架构

graph TD
    A[STM32F103主控] -->|FreeRTOS| B[任务调度]
    B --> C[主控制任务]
    B --> D[电机控制任务]
    B --> E[传感器处理任务]
    B --> F[路径规划任务]
    B --> G[UI交互任务]
    C -->|协调| D & E & F & G
    D -->|PWM| H[电机驱动]
    E -->|I2C/SPI| I[传感器组]
    F -->|避障/路径| D
    G -->|按键/LED| J[用户接口]
    I -->|数据| E
    H -->|动力| K[扫地机器人本体]
    J -->|控制| C

三、核心模块设计

1. 硬件配置

模块 型号/接口 功能说明
主控 STM32F103C8T6 Cortex-M3@72MHz,64KB Flash
电机驱动 L298N 控制左右轮、边刷、风机(PWM)
传感器 红外避障(3路)、碰撞开关、MPU6050(陀螺仪) 环境感知、姿态检测
通信 UART1(调试)、UART2(Wi-Fi模块) 日志输出、远程控制
电源 7.4V锂电池+LM2596降压 系统供电(3.3V/5V)
显示 OLED(SSD1306, I2C) 状态显示(电量、模式)

2. FreeRTOS任务划分

任务名称 优先级 功能描述 通信方式
Task_Main 4 主控制逻辑(模式切换、状态机) 队列、信号量
Task_Motor 3 电机PWM控制(速度/方向) 队列(接收路径规划指令)
Task_Sensor 2 传感器数据采集与预处理 队列(发送数据给路径规划)
Task_PathPlan 3 避障算法(红外+碰撞) 队列(发送控制指令给电机)
Task_UI 1 OLED显示+按键处理 信号量(通知主任务)
Task_Comm 2 串口通信(调试/远程控制) 队列(接收控制命令)

四、核心代码实现

1. 工程结构

SweepRobot_FreeRTOS/
├── Core/
│   ├── Src/
│   │   ├── main.c          // 主函数、FreeRTOS初始化
│   │   ├── tasks.c         // 任务实现
│   │   ├── freertos.c      // FreeRTOS配置(heap、调度器)
│   │   ├── stm32f1xx_it.c   // 中断服务函数
│   │   └── drivers/        // 外设驱动(PWM、UART、I2C、ADC)
│   └── Inc/
│       ├── FreeRTOSConfig.h // FreeRTOS配置
│       └── task_def.h      // 任务定义与宏
├── Drivers/
│   └── STM32F1xx_HAL_Driver/ // HAL库
└── MDK-ARM/                 // Keil工程文件

2. FreeRTOS初始化与任务创建

// main.c
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "task_def.h"

int main(void) {
  HAL_Init();
  SystemClock_Config();  // 72MHz
  MX_GPIO_Init();
  MX_TIM_PWM_Init();     // PWM初始化(电机驱动)
  MX_USART1_UART_Init();  // 调试串口
  MX_I2C1_Init();        // OLED/MPU6050
  MX_ADC1_Init();        // 电池电压采集

  // 创建任务
  xTaskCreate(Task_Main, "Main", 128, NULL, 4, NULL);
  xTaskCreate(Task_Motor, "Motor", 128, NULL, 3, NULL);
  xTaskCreate(Task_Sensor, "Sensor", 128, NULL, 2, NULL);
  xTaskCreate(Task_PathPlan, "PathPlan", 128, NULL, 3, NULL);
  xTaskCreate(Task_UI, "UI", 128, NULL, 1, NULL);
  xTaskCreate(Task_Comm, "Comm", 128, NULL, 2, NULL);

  // 创建队列(传感器数据队列: 存储10个样本)
  sensor_queue = xQueueCreate(10, sizeof(SensorData_t));
  // 创建信号量(UI更新信号)
  ui_semphr = xSemaphoreCreateBinary();

  vTaskStartScheduler();  // 启动调度器
  while (1);
}

3. 核心任务实现

(1)电机控制任务 (Task_Motor)

// tasks.c
#include "motor.h"

// 电机控制数据结构
typedef struct {
  int16_t left_speed;   // 左轮速度(-100~100)
  int16_t right_speed;  // 右轮速度(-100~100)
  uint8_t mode;         // 0:停止, 1:前进, 2:后退, 3:左转, 4:右转
} MotorCmd_t;

void Task_Motor(void *pvParameters) {
  MotorCmd_t cmd;
  TickType_t xLastWakeTime = xTaskGetTickCount();
  
  while (1) {
    // 从队列接收控制指令(阻塞等待)
    if (xQueueReceive(motor_queue, &cmd, portMAX_DELAY) == pdPASS) {
      // 设置PWM占空比(STM32 TIM3 CH1/CH2控制左右轮)
      __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, abs(cmd.left_speed) * 10);
      __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, abs(cmd.right_speed) * 10);
      
      // 设置方向(通过GPIO控制L298N IN1~IN4)
      if (cmd.left_speed > 0) { /* 左轮正转 */ } 
      else { /* 左轮反转 */ }
      if (cmd.right_speed > 0) { /* 右轮正转 */ } 
      else { /* 右轮反转 */ }
    }
    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10));  // 10ms周期
  }
}

(2)传感器处理任务 (Task_Sensor)

// tasks.c
#include "sensor.h"

// 传感器数据结构
typedef struct {
  uint8_t ir_left;    // 左红外(0:有障碍, 1:无障碍)
  uint8_t ir_right;   // 右红外
  uint8_t ir_front;   // 前红外
  uint8_t collision;  // 碰撞开关(0:碰撞, 1:未碰撞)
  int16_t gyro_z;     // 陀螺仪Z轴角速度(°/s)
} SensorData_t;

void Task_Sensor(void *pvParameters) {
  SensorData_t data;
  TickType_t xLastWakeTime = xTaskGetTickCount();
  
  while (1) {
    // 读取传感器(模拟)
    data.ir_left = HAL_GPIO_ReadPin(IR_LEFT_GPIO_Port, IR_LEFT_Pin);
    data.ir_right = HAL_GPIO_ReadPin(IR_RIGHT_GPIO_Port, IR_RIGHT_Pin);
    data.ir_front = HAL_GPIO_ReadPin(IR_FRONT_GPIO_Port, IR_FRONT_Pin);
    data.collision = HAL_GPIO_ReadPin(COLLISION_GPIO_Port, COLLISION_Pin);
    data.gyro_z = MPU6050_ReadGyroZ();  // 读取MPU6050陀螺仪
    
    // 发送数据到路径规划队列
    xQueueSend(sensor_queue, &data, 0);
    
    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(50));  // 50ms采样周期
  }
}

(3)路径规划任务 (Task_PathPlan)

// tasks.c
#include "path_plan.h"

void Task_PathPlan(void *pvParameters) {
  SensorData_t sensor_data;
  MotorCmd_t motor_cmd = {0};
  
  while (1) {
    // 从传感器队列接收数据(阻塞等待)
    if (xQueueReceive(sensor_queue, &sensor_data, portMAX_DELAY) == pdPASS) {
      // 简单避障逻辑(红外+碰撞)
      if (sensor_data.collision == 0) {  // 碰撞: 后退+转向
        motor_cmd.mode = 2;  // 后退
        motor_cmd.left_speed = -30;
        motor_cmd.right_speed = -30;
        vTaskDelay(pdMS_TO_TICKS(500));
        motor_cmd.mode = 3;  // 左转
        motor_cmd.left_speed = -20;
        motor_cmd.right_speed = 20;
        vTaskDelay(pdMS_TO_TICKS(300));
      } 
      else if (sensor_data.ir_front == 0) {  // 前方有障碍
        motor_cmd.mode = 3;  // 左转
        motor_cmd.left_speed = -20;
        motor_cmd.right_speed = 20;
      } 
      else if (sensor_data.ir_left == 0) {  // 左侧有障碍
        motor_cmd.mode = 4;  // 右转
        motor_cmd.left_speed = 20;
        motor_cmd.right_speed = -20;
      } 
      else {  // 无障碍: 前进
        motor_cmd.mode = 1;
        motor_cmd.left_speed = 40;
        motor_cmd.right_speed = 40;
      }
      
      // 发送控制指令到电机队列
      xQueueSend(motor_queue, &motor_cmd, 0);
    }
  }
}

(4)主控制任务 (Task_Main)

// tasks.c
void Task_Main(void *pvParameters) {
  uint8_t system_mode = 0;  // 0:待机, 1:自动清扫, 2:定点清扫
  
  while (1) {
    // 模式切换(通过UI任务通知)
    if (xSemaphoreTake(ui_semphr, 0) == pdTRUE) {
      system_mode = (system_mode + 1) % 3;
    }
    
    // 根据模式执行逻辑
    switch (system_mode) {
      case 0:  // 待机: 停止电机
        Motor_Stop();
        break;
      case 1:  // 自动清扫: 启动路径规划
        xTaskNotifyGive(Task_PathPlan_Handle);  // 通知路径规划任务
        break;
      case 2:  // 定点清扫: 待实现
        break;
    }
    
    vTaskDelay(pdMS_TO_TICKS(100));
  }
}

4. 关键外设驱动

(1)PWM电机控制 (motor.c)

// drivers/motor.c
#include "motor.h"

TIM_HandleTypeDef htim3;  // TIM3用于PWM输出(PA6/PA7)

void MX_TIM_PWM_Init(void) {
  TIM_OC_InitTypeDef sConfigOC = {0};
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 72-1;  // 72MHz/72=1MHz
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 100-1;     // 1MHz/100=10kHz PWM频率
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_PWM_Init(&htim3);
  
  // 配置CH1(左轮)和CH2(右轮)
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
}

// 设置电机速度(-100~100)
void Motor_SetSpeed(int16_t left, int16_t right) {
  // 限制范围
  left = (left > 100) ? 100 : (left < -100) ? -100 : left;
  right = (right > 100) ? 100 : (right < -100) ? -100 : right;
  
  // 设置PWM占空比(0~100对应0~100%占空比)
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, abs(left));
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, abs(right));
  
  // 设置方向(通过GPIO控制L298N)
  HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, (left > 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, (left < 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(IN3_GPIO_Port, IN3_Pin, (right > 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(IN4_GPIO_Port, IN4_Pin, (right < 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

(2)陀螺仪驱动 (sensor.c)

// drivers/sensor.c
#include "mpu6050.h"

// MPU6050读取陀螺仪Z轴数据
int16_t MPU6050_ReadGyroZ(void) {
  uint8_t buf[2];
  I2C_ReadBytes(MPU6050_ADDR, GYRO_ZOUT_H, buf, 2);  // 读取高8位和低8位
  return (int16_t)((buf[0] << 8) | buf[1]);  // 合成16位数据
}

参考代码 xiao米扫地机器人工程源码程序STM32103+freeRTOS www.youwenfan.com/contentcns/182569.html

五、FreeRTOS配置要点

1. FreeRTOSConfig.h关键参数

#define configUSE_PREEMPTION        1       // 抢占式调度
#define configUSE_IDLE_HOOK          0
#define configUSE_TICK_HOOK          0
#define configCPU_CLOCK_HZ           (SystemCoreClock)  // 72000000Hz
#define configTICK_RATE_HZ           ((TickType_t)1000)  // 1ms tick
#define configMAX_PRIORITIES         (5)     // 最大优先级5
#define configMINIMAL_STACK_SIZE     ((uint16_t)128)  // 最小栈大小128字
#define configTOTAL_HEAP_SIZE        ((size_t)(10 * 1024))  // 堆大小10KB
#define configUSE_16_BIT_TICKS       0       // 32位tick计数

2. 任务间通信

六、扩展方向

  1. 真实传感器集成:添加激光雷达(RPLIDAR A1)、悬崖传感器(红外测距)、里程计(编码器)。
  2. 路径规划算法:实现SLAM(如Gmapping)、A*算法、DWA动态窗口法。
  3. 电源管理:添加电池电量检测(ADC)、低功耗模式(STOP模式)。
  4. 通信协议:集成Wi-Fi模块(ESP8266)实现手机APP控制(MQTT协议)。
  5. 文件系统:添加SPI Flash存储地图数据、清扫记录。

七、注意事项

  1. 实时性:电机控制任务优先级高于路径规划,确保响应速度。
  2. 资源竞争:I2C/SPI总线访问需通过互斥量保护(如xSemaphoreTake(i2c_mutex, portMAX_DELAY))。
  3. 调试:通过串口打印任务状态(vTaskList())、队列使用情况(uxQueueMessagesWaiting())。
  4. 功耗:空闲任务中调用__WFI()进入低功耗模式。

八、总结

本框架基于STM32F103和FreeRTOS实现了扫地机器人的核心功能,包括任务调度、电机控制、传感器采集和简单避障逻辑。代码结构清晰,模块化设计便于扩展,可作为学习嵌入式实时系统开发的参考。

专注于matlab/simulink,电子电路,编程