基于STM32的避障寻迹小车设计
一、系统概述与核心功能
1. 系统定位
基于STM32的避障寻迹小车以“环境感知-路径规划-运动控制-状态反馈”为核心,融合红外寻迹(沿黑线行驶)与超声波避障(自动绕开障碍物)功能,支持手动/自动模式切换、实时状态显示及低功耗续航,适用于教育实训、智能仓储、家庭服务等场景。
2. 核心功能模块
| 模块 | 功能描述 |
|---|---|
| 环境感知 | 红外寻迹(5路TCRT5000检测黑线)、超声波避障(HC-SR04检测前方障碍物,测距2-400cm) |
| 运动控制 | 双直流电机驱动(L298N/TB6612FNG),PWM调速(0-100%占空比),支持前进/后退/转向 |
| 路径规划 | 寻迹:PID算法调整电机差速(直线/弯道跟踪);避障:遇障时“停止-转向-绕行-回归轨迹” |
| 状态反馈 | OLED显示(传感器数据、模式、电池电压),LED指示(电源/故障),蜂鸣器报警(避障触发) |
| 人机交互 | 按键切换模式(寻迹/避障/手动),蓝牙模块(HC-05)手机APP控制,预留扩展接口(摄像头/陀螺仪) |
| 低功耗设计 | 待机时关闭非必要模块(传感器/显示),STM32进入STOP模式,续航≥2小时(7.4V/2000mAh电池) |
二、硬件设计方案
1. 核心硬件选型
| 模块 | 型号 | 关键参数 | 接口方式 |
|---|---|---|---|
| 主控MCU | STM32F103C8T6 | 72MHz Cortex-M3,64KB Flash,20KB RAM,3个定时器(PWM),2个UART,2个I2C | 核心控制器 |
| 寻迹传感器 | TCRT5000×5 | 红外反射式,检测距离0-3cm,输出数字信号(黑线低电平,白底高电平) | GPIO(PB0-PB4,数字输入) |
| 避障传感器 | HC-SR04 | 超声波测距,Trig(输出)、Echo(输入),测距精度±3mm,探测角度15° | Trig=PA0,Echo=PA1(定时器输入捕获) |
| 电机驱动 | L298N | 双H桥驱动,支持2路直流电机(5-35V,2A/路),内置续流二极管 | IN1=PA2,IN2=PA3(左电机);IN3=PA4,IN4=PA5(右电机);ENA=PA6(PWM),ENB=PA7(PWM) |
| 直流电机 | 37GB520直流减速电机 | 减速比1:30,额定电压6V,空载转速120rpm,扭矩0.5N·m | 配橡胶轮(直径65mm) |
| 电源模块 | 7.4V锂电池+LM2596+AMS1117 | 7.4V/2000mAh锂电池→LM2596降压至5V(驱动模块)→AMS1117-3.3V(STM32/传感器) | 供电一体化(带过充保护) |
| 显示模块 | OLED 12864(I2C) | 0.96寸,128×64像素,低功耗(<10mA),显示传感器数据、模式、电压 | I2C(PB6=SCL,PB7=SDA) |
| 通信模块 | HC-05蓝牙模块 | 蓝牙2.0+EDR,UART接口,10m距离,支持AT指令配置 | UART1(PA9=TX,PA10=RX) |
| 辅助模块 | 按键×3+LED×2+蜂鸣器 | 按键(模式切换/启停),LED(电源/故障),有源蜂鸣器(5V,避障报警) | GPIO(PC0-PC2按键,PC3-PC4 LED,PC5蜂鸣器) |
2. 硬件电路设计要点
2.1 核心电路连接
-
STM32最小系统:8MHz外部晶振+32.768kHz RTC晶振,SWD调试接口(PA13/PA14),复位电路(10kΩ上拉+0.1μF电容)。
-
寻迹传感器(TCRT5000×5):VCC=5V,GND共地,OUT引脚接PB0-PB4(数字输入,内部上拉),检测黑线时输出低电平。
-
超声波模块(HC-SR04):VCC=5V,Trig=PA0(推挽输出),Echo=PA1(浮空输入,定时器TIM2_CH2输入捕获)。
-
电机驱动(L298N):
- 左电机:IN1=PA2(正转),IN2=PA3(反转),ENA=PA6(TIM3_CH1 PWM,20kHz);
- 右电机:IN3=PA4(正转),IN4=PA5(反转),ENB=PA7(TIM3_CH2 PWM);
- 电机电源:7.4V锂电池直接接入L298N VCC,GND与STM32共地。
2.2 抗干扰设计
- 电源隔离:电机电源(7.4V)与逻辑电源(5V/3.3V)通过磁珠(600Ω@100MHz)隔离,避免电机启动干扰。
- 信号滤波:超声波Echo引脚并联10kΩ上拉电阻+0.1μF电容,滤除高频噪声;红外传感器OUT引脚加10kΩ下拉电阻,增强抗干扰。
- PCB布局:传感器信号走线短且远离开关电源,模拟地(AGND)与数字地(DGND)单点连接(通过0Ω电阻)。
三、软件设计与核心代码
1. 系统架构(FreeRTOS多任务调度)
采用FreeRTOS实时操作系统,划分5个核心任务(优先级从高到低):
- 传感器采集任务(优先级4):周期性读取红外寻迹(5路)和超声波(测距)数据,滤波后发送至消息队列。
- 寻迹控制任务(优先级3):解析寻迹数据,通过PID算法计算电机差速,生成电机控制指令。
- 避障控制任务(优先级3):判断超声波距离,触发避障逻辑(转向/绕行),发送临时控制指令。
- 电机驱动任务(优先级2):解析控制指令,通过PWM驱动电机(正转/反转/调速)。
- 人机交互任务(优先级1):更新OLED显示(传感器数据、模式),处理按键/蓝牙指令(模式切换、启停)。
2. 核心代码实现(基于HAL库)
2.1 主程序框架(FreeRTOS初始化)
#include "stm32f1xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"
#include "motor.h"
#include "sensor.h"
#include "oled.h"
#include "bluetooth.h"
// 全局变量定义
uint8_t system_mode = 0; // 0-待机,1-寻迹,2-避障,3-手动
uint16_t trace_data[5]; // 5路红外寻迹数据(0=白底,1=黑线)
uint16_t distance = 0; // 超声波测距结果(cm)
int main(void) {
HAL_Init();
SystemClock_Config(); // 72MHz
MX_GPIO_Init(); // GPIO初始化(传感器、电机、按键)
MX_TIM3_Init(); // TIM3初始化(PWM输出,控制电机)
MX_TIM2_Init(); // TIM2初始化(超声波Echo输入捕获)
MX_I2C1_Init(); // I2C1初始化(OLED)
MX_USART1_Init(); // USART1初始化(蓝牙)
OLED_Init(); // OLED显示初始化
Motor_Init(); // 电机驱动初始化
Sensor_Init(); // 传感器初始化(红外、超声波)
Bluetooth_Init(); // 蓝牙模块初始化
// FreeRTOS任务创建
xTaskCreate(Sensor_Task, "Sensor", 256, NULL, 4, NULL); // 传感器采集
xTaskCreate(Trace_Task, "Trace", 256, NULL, 3, NULL); // 寻迹控制
xTaskCreate(Avoid_Task, "Avoid", 256, NULL, 3, NULL); // 避障控制
xTaskCreate(Motor_Task, "Motor", 256, NULL, 2, NULL); // 电机驱动
xTaskCreate(UI_Task, "UI", 128, NULL, 1, NULL); // 人机交互
vTaskStartScheduler(); // 启动调度器
while (1);
}
2.2 传感器采集任务(红外寻迹+超声波)
// 传感器数据结构体
typedef struct {
uint16_t trace[5]; // 5路红外数据(0/1)
uint16_t distance; // 超声波距离(cm)
} SensorData_t;
SensorData_t sensor_data;
void Sensor_Task(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = pdMS_TO_TICKS(20); // 20ms采集一次(50Hz)
while (1) {
// 1. 读取红外寻迹数据(5路TCRT5000,PB0-PB4)
for (uint8_t i = 0; i < 5; i++) {
sensor_data.trace[i] = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0 + i); // 0=白底,1=黑线
}
// 2. 读取超声波距离(HC-SR04,TIM2输入捕获)
distance = HCSR04_ReadDistance(); // 返回cm(简化函数,实际需定时器测脉宽)
// 3. 发送数据至消息队列
xQueueSend(sensor_queue, &sensor_data, 0);
xQueueSend(distance_queue, &distance, 0);
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
2.3 寻迹控制任务(PID算法)
// PID参数(需调试优化)
#define KP 2.5f // 比例系数
#define KI 0.1f // 积分系数
#define KD 0.5f // 微分系数
// 寻迹控制逻辑
void Trace_Task(void *pvParameters) {
SensorData_t data;
int16_t error = 0, last_error = 0, integral = 0, derivative = 0;
int16_t motor_left = 0, motor_right = 0; // 电机速度(-100~100,负=反转)
while (1) {
if (xQueueReceive(sensor_queue, &data, portMAX_DELAY) == pdPASS) {
if (system_mode == 1) { // 寻迹模式
// 1. 计算偏差(黑线位置:0=左,1=中左,2=中,3=中右,4=右)
error = 0;
uint8_t active_count = 0; // 检测到黑线的传感器数量
for (uint8_t i = 0; i < 5; i++) {
if (data.trace[i]) { // 黑线(低电平,此处假设1=黑线,需根据实际调整)
error += (i - 2); // 以中间传感器(2号)为基准,偏差范围-2~+2
active_count++;
}
}
if (active_count == 0) error = last_error; // 无黑线时保持上次偏差
else error /= active_count; // 平均偏差
// 2. PID计算
integral += error;
if (integral > 100) integral = 100; // 积分限幅
if (integral < -100) integral = -100;
derivative = error - last_error;
int16_t pid_output = KP*error + KI*integral + KD*derivative;
last_error = error;
// 3. 计算电机速度(基础速度50,差速由PID输出调整)
motor_left = 50 - pid_output;
motor_right = 50 + pid_output;
// 4. 限幅(-100~100)
motor_left = (motor_left > 100) ? 100 : (motor_left < -100) ? -100 : motor_left;
motor_right = (motor_right > 100) ? 100 : (motor_right < -100) ? -100 : motor_right;
// 5. 发送控制指令至电机任务
xQueueSend(motor_queue, &motor_left, 0);
xQueueSend(motor_queue, &motor_right, 0);
}
}
}
}
2.4 避障控制任务(遇障转向)
void Avoid_Task(void *pvParameters) {
uint16_t dist;
while (1) {
if (xQueueReceive(distance_queue, &dist, portMAX_DELAY) == pdPASS) {
if (system_mode == 2 && dist < 20) { // 避障模式,距离<20cm触发
// 1. 停止电机
Motor_Control(0, 0);
HAL_Delay(200);
// 2. 左转90°(假设左转时间500ms)
Motor_Control(-30, 30); // 左轮反转,右轮正转
HAL_Delay(500);
// 3. 前进绕行(200ms)
Motor_Control(50, 50);
HAL_Delay(200);
// 4. 右转90°回归原方向
Motor_Control(30, -30);
HAL_Delay(500);
// 5. 恢复前进
Motor_Control(50, 50);
// 6. 蜂鸣器报警
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET);
}
}
}
}
2.5 电机驱动任务(PWM控制)
// 电机控制函数(速度-100~100,负=反转)
void Motor_Control(int16_t left, int16_t right) {
// 左电机方向(IN1/IN2)
if (left > 0) { // 正转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
} else if (left < 0) { // 反转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
} else { // 停止
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
}
// 右电机方向(IN3/IN4)
if (right > 0) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
} else if (right < 0) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
// PWM调速(占空比0-100%对应速度-100~100,实际需映射)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, abs(left) * 10); // PA6,左电机PWM
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, abs(right) * 10); // PA7,右电机PWM
}
四、关键技术与优化
1. 寻迹算法优化
- 多传感器融合:5路红外对管(左/中左/中/中右/右)提高黑线检测精度,避免单传感器误判。
- PID参数整定:通过Ziegler-Nichols法整定KP/KI/KD,结合实际测试调整(如弯道时增大KD抑制超调)。
- 丢线处理:当所有传感器未检测到黑线时,小车按最后有效偏差继续行驶(或原地旋转搜索)。
2. 避障逻辑优化
- 动态避障:根据障碍物距离调整转向角度(近障大角度转向,远障小角度微调)。
- 路径记忆:避障过程中记录转向方向,绕行后优先回归原路径(如“左转绕行则右转回归”)。
3. 低功耗设计
- 休眠模式:待机时关闭OLED、蓝牙模块,STM32进入STOP模式(仅保留按键中断唤醒)。
- 电机休眠:手动模式下无操作时,电机停止转动,仅保留霍尔传感器供电(若有)。
参考代码 基于STM32设计避障寻迹小车 www.youwenfan.com/contentcst/133708.html
五、系统调试与扩展
1. 调试步骤
| 阶段 | 操作 | 工具 |
|---|---|---|
| 硬件调试 | 测量电源电压(7.4V/5V/3.3V),示波器检查PWM波形 | 万用表、示波器(TIM3_CH1/CH2) |
| 传感器校准 | 红外对管对准黑线/白底,验证输出电平;超声波测已知距离(如20cm) | 串口打印原始数据 |
| 电机测试 | 单独控制左右电机正反转、调速,验证L298N驱动逻辑 | 逻辑分析仪(GPIO输出) |
| 联调 | 铺设黑线轨迹,测试寻迹流畅度;放置障碍物测试避障成功率 | 高速摄像机(拍摄小车轨迹) |
2. 扩展功能
- 摄像头寻迹:替换红外对管为OV7670摄像头,通过OpenMV识别复杂轨迹(如箭头、二维码)。
- 陀螺仪姿态控制:添加MPU6050陀螺仪,检测小车倾角,防止侧翻(尤其在高速转向时)。
- SLAM建图导航:结合激光雷达(如RPLIDAR A1),实现自主建图与路径规划(需上位机支持)。