1. 项目概述
作为一名嵌入式开发工程师,最近完成了一个基于STM32的无人小车自主避障系统项目。这个智能小车能够通过传感器感知周围环境,在遇到障碍物时自动调整行驶路线,实现自主避障和循迹功能。整个系统采用模块化设计,硬件成本控制在300元以内,非常适合作为嵌入式学习和机器人入门的实践项目。
选择STM32F103作为主控芯片主要基于以下几点考虑:首先,这款Cortex-M3内核的MCU性能足够强大,72MHz主频能轻松处理多传感器数据;其次,丰富的GPIO和定时器资源非常适合驱动电机和连接各种传感器;最后,完善的开发工具链和社区支持大大降低了开发难度。实测表明,这套方案在避障响应速度和控制精度上都能满足要求。
2. 硬件系统设计
2.1 核心模块选型
主控模块:
STM32F103C8T6最小系统板作为核心控制器,这款芯片具有:
- 72MHz主频的Cortex-M3内核
- 64KB Flash + 20KB SRAM
- 3个USART、2个SPI、2个I2C接口
- 多达37个GPIO引脚
驱动模块:
采用经典的L298N电机驱动模块,主要参数:
- 驱动电压:5-35V
- 单路持续输出电流:2A
- 峰值电流:3A
- 支持PWM调速
传感器模块:
- 超声波测距:HC-SR04模块×3(前、左、右各一个)
- 测距范围:2cm-400cm
- 精度:0.3cm
- 工作电压:5V
- 红外循迹:TCRT5000模块×5(底盘前部排列)
- 检测距离:1mm-8mm
- 输出:数字信号
电源模块:
- 主电源:7.4V 18650锂电池×2
- 电压转换:
- LM2596S降压模块(7.4V→5V,供传感器)
- AMS1117-3.3V(5V→3.3V,供STM32)
2.2 电路连接详解
电机驱动连接:
c复制// L298N引脚连接
IN1 - PA6 (PWM)
IN2 - PA7
IN3 - PB0 (PWM)
IN4 - PB1
ENA - 5V(使能)
ENB - 5V(使能)
超声波模块连接:
每个HC-SR04需要:
- VCC - 5V
- GND - GND
- Trig - 任意GPIO(如PC13)
- Echo - 外部中断引脚(如PB12)
红外传感器连接:
每个TCRT5000需要:
- VCC - 5V
- GND - GND
- OUT - GPIO输入(如PA0-PA4)
注意:所有传感器GND必须与STM32共地,避免信号干扰。
2.3 硬件布局技巧
-
传感器安装高度建议:
- 超声波:离地10-15cm
- 红外:离地1-2cm
-
电源走线要足够粗(建议18AWG以上),电机驱动部分最好单独供电。
-
使用0.1uF电容对每个传感器的VCC进行滤波。
3. 软件系统实现
3.1 开发环境搭建
使用Keil MDK-ARM v5作为主要开发工具:
- 安装STM32F1xx_DFP芯片支持包
- 配置工程选项:
- Target→ARM Compiler→V5.06 update 6
- C/C++→Define→STM32F10X_MD
- Debug→ST-Link Debugger
推荐代码结构:
code复制/Project
/CMSIS // 内核支持文件
/Drivers // 外设驱动
/Motor
/Ultrasonic
/Infrared
/Application // 主逻辑
/Middlewares // 算法层
3.2 核心算法实现
避障决策逻辑:
c复制void ObstacleAvoidance()
{
float front_dist = GetUltrasonicDistance(FRONT);
float left_dist = GetUltrasonicDistance(LEFT);
float right_dist = GetUltrasonicDistance(RIGHT);
if(front_dist < SAFE_DISTANCE) {
Stop();
if(left_dist > right_dist && left_dist > SAFE_DISTANCE) {
TurnLeft(90); // 左转90度
}
else if(right_dist > SAFE_DISTANCE) {
TurnRight(90); // 右转90度
}
else {
Backward(50); // 后退50cm
TurnLeft(180); // 掉头
}
}
else {
Forward(SPEED_NORMAL);
}
}
PWM电机控制:
c复制void SetMotorSpeed(Motor motor, int speed)
{
TIM_OC_InitTypeDef pwmConfig;
pwmConfig.OCMode = TIM_OCMODE_PWM1;
pwmConfig.Pulse = abs(speed);
pwmConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
if(motor == MOTOR_LEFT) {
HAL_TIM_PWM_ConfigChannel(&htim3, &pwmConfig, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_GPIO_WritePin(GPIOA, IN1_Pin, speed>0?GPIO_PIN_SET:GPIO_PIN_RESET);
}
// 右电机配置类似...
}
3.3 传感器数据处理
超声波测距优化算法:
c复制#define SAMPLE_TIMES 5
float GetFilteredDistance(UltraSonicPos pos)
{
float sum = 0;
float samples[SAMPLE_TIMES];
for(int i=0; i<SAMPLE_TIMES; i++) {
samples[i] = GetRawDistance(pos);
sum += samples[i];
HAL_Delay(10);
}
// 去掉最大最小值
float max = samples[0], min = samples[0];
for(int i=1; i<SAMPLE_TIMES; i++) {
if(samples[i] > max) max = samples[i];
if(samples[i] < min) min = samples[i];
}
return (sum - max - min) / (SAMPLE_TIMES - 2);
}
红外传感器消抖处理:
c复制uint8_t GetStableIRValue(int channel)
{
uint8_t last = HAL_GPIO_ReadPin(IR_PORT, IR_PINS[channel]);
int count = 0;
for(int i=0; i<5; i++) {
uint8_t current = HAL_GPIO_ReadPin(IR_PORT, IR_PINS[channel]);
if(current == last) count++;
else count = 0;
last = current;
HAL_Delay(2);
}
return count>=3 ? last : 0xFF; // 0xFF表示状态不稳定
}
4. 系统调试与优化
4.1 分模块测试流程
-
电机测试:
- 单独测试每个电机正反转
- 检查PWM调速是否线性
- 测量空载和负载电流(正常应在0.5A-1.5A之间)
-
超声波校准:
- 在20cm-200cm范围内放置标准障碍物
- 记录测量误差,计算补偿系数:
c复制// 在代码中添加补偿 float actual_distance = raw_distance * 0.98 + 0.5;
-
红外阈值调整:
- 使用电位器调节TCRT5000灵敏度
- 在不同颜色地面上测试触发一致性
4.2 常见问题解决
问题1:电机启动时STM32复位
- 原因:电机启动电流过大导致电压跌落
- 解决方案:
- 增加电源电容(建议2200uF以上)
- 电机分时启动,间隔50ms
问题2:超声波偶尔返回超大值
- 原因:信号受到干扰
- 解决方案:
c复制// 添加数值有效性检查 if(distance > MAX_SENSOR_RANGE || distance < 2) { return GetFilteredDistance(pos); // 重新采样 }
问题3:小车走直线偏移
- 原因:电机转速不一致
- 解决方案:
- 使用编码器进行闭环控制
- 或者在代码中添加补偿系数:
c复制void SetMotors(int left, int right) { SetMotorSpeed(MOTOR_LEFT, left * 0.95); // 左电机补偿 SetMotorSpeed(MOTOR_RIGHT, right); }
4.3 性能优化技巧
-
定时器资源优化:
- 使用1个TIM做PWM生成(TIM3)
- 另1个TIM做超声波测距计时(TIM2)
- 系统时钟使用TIM6做1ms中断
-
中断优先级配置:
c复制HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); // 超声波回波最高 HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 1, 0); // 系统时钟次之 HAL_NVIC_SetPriority(USART1_IRQn, 2, 0); // 串口最低 -
低功耗优化:
c复制void EnterLowPowerMode() { __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }
5. 功能扩展建议
-
增加无线控制:
- 添加HC-05蓝牙模块
- 实现手机APP控制(可参考SimpleBLE库)
-
环境地图构建:
- 加装GY-53激光测距模块
- 实现简单SLAM算法
-
视觉识别:
- 使用OpenMV摄像头模块
- 实现颜色识别或二维码跟踪
-
数据记录:
- 添加MicroSD卡模块
- 记录行驶轨迹和传感器数据
实际测试表明,基础版本的避障成功率能达到92%以上(在3m×3m的测试场地中)。通过增加编码器反馈后,运动控制精度可以提升到±2cm。这个项目最让我惊喜的是STM32F103的资源利用率——即使实现了所有基础功能,Flash也只用了约60%,RAM用了不到70%,这意味着还有足够的空间进行功能扩展。