1. 项目概述
这个基于STM32单片机的智能小车项目,是我去年带领学生团队完成的一个嵌入式系统综合实践案例。它实现了模拟真实场景下的倒车入库和侧方停车功能,同时具备超声波与红外双重避障能力。相比市面上常见的循迹或遥控小车,这个项目最大的特点是将自动控制算法与实际驾驶场景相结合,对嵌入式开发者和电子爱好者来说是个不错的进阶练手项目。
从技术实现来看,整套系统以STM32F103C8T6最小系统板为核心控制器,通过HC-SR04超声波模块和红外对管实现环境感知,L298N电机驱动模块控制直流减速电机,配合编码器实现闭环速度控制。软件层面采用模块化编程思想,将运动控制、传感器数据处理、状态机逻辑等分离处理,代码结构清晰且易于二次开发。
2. 硬件系统设计
2.1 核心控制器选型
我们选择STM32F103C8T6作为主控芯片主要基于三点考虑:
- 性价比优势:这款Cortex-M3内核的MCU价格约10-15元,却拥有72MHz主频、64KB Flash和20KB RAM,完全满足实时控制需求
- 丰富外设:内置3个USART、2个SPI、2个I2C接口,PWM输出通道多达15个
- 生态支持:STM32CubeMX工具可快速生成初始化代码,降低开发门槛
实际开发中发现:虽然STM32F103系列已属经典,但当前市场存在大量翻新芯片。建议通过正规渠道采购,我们最初在某宝购买的批次就有约30%的芯片存在异常复位问题。
2.2 传感器系统配置
2.2.1 超声波测距模块
采用常见的HC-SR04模块,其工作原理是:
- 触发引脚输入10μs以上高电平
- 模块自动发送8个40kHz超声波脉冲
- 回声引脚输出高电平,持续时间与距离成正比
测量代码示例:
c复制void HC_SR04_Measure(void)
{
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
delay_us(20);
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_RESET);
uint32_t start = TIM2->CNT;
while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_SET);
uint32_t end = TIM2->CNT;
distance_cm = (end - start) * 0.034 / 2; // 声速340m/s
}
2.2.2 红外避障模块
选用TCRT5000红外反射传感器,其特点是:
- 检测距离2-30cm可调
- 数字量输出,无需额外AD转换
- 抗环境光干扰能力强
布局技巧:
- 前部安装3个(左、中、右)用于障碍检测
- 侧面各安装2个用于车位识别
- 底部安装4个用于边界检测
2.3 运动控制系统
2.3.1 电机驱动方案
使用L298N双H桥驱动模块,关键参数:
- 驱动电压:5-35V
- 单通道持续电流:2A
- 峰值电流:3A
- 内置续流二极管
接线示意图:
code复制L298N STM32
IN1 ---- PA6(PWM)
IN2 ---- PA7(PWM)
IN3 ---- PB0(PWM)
IN4 ---- PB1(PWM)
ENA ---- 5V
ENB ---- 5V
2.3.2 编码器接口
采用AB相增量式编码器(600P/R),通过TIMx的编码器模式实现四倍频:
c复制void Encoder_Init(void)
{
TIM_Encoder_InitTypeDef encoder = {0};
encoder.EncoderMode = TIM_ENCODERMODE_TI12;
encoder.IC1Polarity = TIM_ICPOLARITY_RISING;
encoder.IC1Selection = TIM_ICSELECTION_DIRECTTI;
encoder.IC1Prescaler = TIM_ICPSC_DIV1;
encoder.IC1Filter = 0;
// 相同配置IC2...
HAL_TIM_Encoder_Init(&htim3, &encoder);
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
}
3. 软件架构设计
3.1 系统状态机设计
定义5种主要工作状态:
- IDLE:待机状态
- OBSTACLE_AVOID:避障模式
- BACK_IN:倒车入库
- PARALLEL_PARK:侧方停车
- ERROR:异常状态
状态转换逻辑:
mermaid复制stateDiagram-v2
[*] --> IDLE
IDLE --> OBSTACLE_AVOID: 检测到障碍
OBSTACLE_AVOID --> BACK_IN: 后方空间足够
OBSTACLE_AVOID --> PARALLEL_PARK: 侧方空间足够
BACK_IN --> IDLE: 完成入库
PARALLEL_PARK --> IDLE: 完成停车
any --> ERROR: 传感器异常
3.2 关键算法实现
3.2.1 倒车入库算法
- 初始位置检测(距离后方障碍物1m)
- 直线后退至指定位置(约0.5m)
- 计算转向角度:
c复制float calc_steering_angle(float car_width, float space_width) { float min_radius = car_width / (2 * sin(MIN_ANGLE)); float available_space = space_width - car_width; return asin(car_width / (2 * (min_radius + available_space))); } - 执行转向+后退复合动作
- 回正方向盘并微调位置
3.2.2 侧方停车算法
采用五步法:
- 平行驶过车位,记录起始位置
- 倒车至45度角(通过编码器脉冲计数控制)
- 反向打满方向继续倒车
- 检测到与后方车辆距离<30cm时回正
- 前移调整最终位置
3.3 PID速度控制
位置式PID实现:
c复制typedef struct {
float Kp, Ki, Kd;
float integral;
float prev_error;
} PID_Controller;
float PID_Update(PID_Controller *pid, float setpoint, float measurement)
{
float error = setpoint - measurement;
pid->integral += error;
float derivative = error - pid->prev_error;
pid->prev_error = error;
return pid->Kp * error +
pid->Ki * pid->integral +
pid->Kd * derivative;
}
参数整定经验:
- 先调Kp至出现小幅振荡
- 然后加入Kd抑制振荡
- 最后加Ki消除静差
- 典型值:Kp=0.5, Ki=0.01, Kd=0.2
4. 制作与调试要点
4.1 硬件组装注意事项
-
电源布局:
- 电机驱动与MCU使用独立电源
- 添加1000μF以上电解电容滤波
- 稳压芯片建议选用AMS1117-3.3
-
传感器安装:
- 超声波模块避免与电机同平面
- 红外传感器安装高度距地面5-8cm
- 所有线缆使用扎带固定
-
机械结构:
- 车轮轴与电机轴需严格同心
- 建议使用3D打印支架固定传感器
- 整车重心尽量降低
4.2 软件调试技巧
-
传感器校准:
c复制void calibrate_ir_sensors(void) { for(int i=0; i<10; i++) { black_level[i] += read_ir_sensor(i); } // 相同方法校准白电平... } -
运动调试步骤:
- 先单独测试电机正反转
- 再验证编码器计数方向
- 最后闭环测试PID响应
-
常见问题处理:
- 电机抖动:检查PWM频率(建议10-20kHz)
- 测量跳变:添加滑动平均滤波
- 控制不稳:降低采样频率(50-100Hz足够)
5. 性能优化方向
-
传感器融合:
- 结合IMU数据补偿车轮打滑
- 卡尔曼滤波处理超声波数据
-
路径规划改进:
- 引入RRT算法生成最优路径
- 增加中途调整机制
-
能耗优化:
- 动态调整PWM占空比
- 增加休眠模式
这个项目从设计到调试完成大约耗时3个月,期间最大的收获是认识到嵌入式开发中硬件可靠性的重要性。我们前后更换了3批超声波模块才找到性能稳定的型号,建议大家在选购传感器时不要一味追求低价。现在回头来看,如果改用TOF激光传感器可能会获得更稳定的测距性能,当然成本也会相应提高。