基于STM32的智能小车(寻迹、避障)技术深度解析

在电子设计竞赛和高校创新项目中,你是否曾见过那些沿着黑线自动行驶、遇到障碍物还能灵活绕行的小车?它们看似简单,背后却融合了嵌入式控制、传感器感知与运动规划的完整闭环。这类系统最常见的核心就是 STM32微控制器 ——它不仅是“大脑”,更是连接物理世界与数字逻辑的关键枢纽。

以一块几十元的“蓝丸”开发板为基础,搭配几块钱的红外传感器和超声波模块,就能构建出具备自主决策能力的移动机器人。这种低成本、高可玩性的平台,正成为学习嵌入式开发的最佳实践载体。而其中最具代表性的应用之一,便是集 寻迹 避障 于一体的双模智能小车。


要让一个小车真正“聪明”起来,首先得让它能“看路”和“识险”。寻迹功能依赖地面预设的黑白对比线,通常由一组红外对管完成检测;避障则依靠超声波或红外测距模块判断前方是否有障碍物。这两类信息被STM32实时采集后,经过简单的逻辑判断或算法处理,驱动电机做出前进、转向或后退的动作。

整个系统的灵魂在于 感知—决策—执行 的快速循环。比如当小车偏离轨迹时,必须在几十毫秒内识别偏差并纠正方向;而在接近墙壁时,又需要果断停止并选择新的路径。这一切都要求主控芯片具备足够的处理速度、丰富的外设资源以及可靠的实时响应能力。

为什么STM32能胜任这一角色?

以广泛使用的 STM32F103C8T6 为例,这款基于ARM Cortex-M3内核的32位MCU,主频高达72MHz,远超传统8位单片机。它内置12位ADC可用于模拟信号采集,多个通用定时器支持PWM输出和输入捕获,GPIO数量充足且可配置为中断触发模式。更重要的是,其成熟的开发生态(如Keil、STM32CubeIDE、HAL/LL库)大大降低了上手门槛。

相比老式的51单片机,STM32不仅在性能上有数量级提升,在外设集成度和编程灵活性上也实现了质的飞跃。你可以用一个定时器同时生成两路独立PWM控制左右轮转速,也可以通过DMA自动搬运ADC采样数据,避免CPU频繁轮询。这些特性使得复杂任务调度变得轻而易举。


实现寻迹的核心元件是 TCRT5000红外传感器模块 ,结构简单但原理巧妙:内部包含一个红外发射二极管和一个光电三极管。当光线照射到地面时,白色区域反射强烈,接收端导通,输出低电平;黑色区域吸收大部分光,接收信号弱,输出高电平。利用这一差异,就能判断车体是否压在线上。

实际应用中往往采用多路阵列布置,例如3个或5个传感器横向排列,形成“视觉”窗口。假设中间传感器在线上,说明车辆居中直行;若左侧传感器感应到黑线,则应右转修正。代码层面只需读取几个GPIO状态,结合条件判断即可完成基本循迹逻辑:

#define LEFT_SENSOR    GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_0)
#define MID_SENSOR     GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1)
#define RIGHT_SENSOR   GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_2)

void Track_Scan(void) {
    uint8_t left = LEFT_SENSOR;
    uint8_t mid  = MID_SENSOR;
    uint8_t right= RIGHT_SENSOR;

    if (mid == 0) {
        Motor_Forward();
    } else if (left == 0) {
        Motor_TurnLeft();
    } else if (right == 0) {
        Motor_TurnRight();
    } else {
        Motor_SpinLeft(); // 失去轨迹,原地旋转寻找
    }
}

虽然这段逻辑简洁,但在真实环境中容易因地面反光不均或震动导致误判。因此建议加入软件滤波机制,例如连续采样3~5次取多数结果,或引入延时回检策略,提升稳定性。


相比之下,避障功能更关注空间感知能力。这里常用的是 HC-SR04超声波模块 ,工作方式类似蝙蝠回声定位:通过Trig引脚发送一个至少10μs的高电平脉冲,模块便会发射8组40kHz超声波。若前方存在障碍物,声波反射回来被接收器捕捉,Echo引脚将输出一段高电平,其持续时间即为声波往返时间。

距离计算公式为:

距离(cm) = 高电平宽度(us) × 0.034 / 2

由于STM32主频较高(如72MHz),每个时钟周期仅约13.9ns,因此非常适合精确计时。最直接的方法是使用定时器测量Echo上升沿到下降沿的时间差。下面是一个基于TIM2的实现示例:

uint32_t Get_Distance(void) {
    uint32_t time_us = 0;

    // 发送触发信号
    GPIO_SetBits(GPIOB, GPIO_Pin_1);
    Delay_us(10);
    GPIO_ResetBits(GPIOB, GPIO_Pin_1);

    // 等待上升沿
    while (!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0));

    TIM2->CNT = 0;  // 清零计数器
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)) {
        if (TIM2->CNT > 50000) break; // 超时保护
    }
    time_us = TIM2->CNT;

    return (time_us * 0.034 / 2);
}

尽管这种方法有效,但占用CPU资源较多。更优方案是启用 输入捕获功能 ,利用硬件自动记录边沿时间戳,配合中断处理,既提高精度又释放主程序负担。

需要注意的是,HC-SR04并非万能:对于柔软吸音材料(如布料)、倾斜表面或过窄物体,可能无法返回有效回波。此外,其最小测量距离约为2cm,低于此值属于盲区。因此在程序中应设置合理阈值(如<20cm视为危险),并增加多次测量取平均的操作来抑制偶然误差。


驱动电机才是最终体现控制效果的环节。这里普遍采用 L298N双H桥驱动模块 ,能够同时控制两个直流电机的正反转与调速。每个H桥由四个MOSFET组成,通过不同开关组合改变电流方向,从而实现电机换向。

具体连接上,IN1/IN2接STM32的GPIO用于方向控制,ENA引脚接入PWM信号调节速度。例如:

  • IN1=1, IN2=0 → 正转
  • IN1=0, IN2=1 → 反转
  • ENA=占空比50% → 半速运行

初始化PWM时,常选用TIM3等通用定时器配置为PWM模式:

void Motor_PWM_Init(void) {
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    TIM_TimeBaseInitTypeDef  tim;
    TIM_OCInitTypeDef        oc;

    TIM_TimeBaseStructInit(&tim);
    tim.TIM_Prescaler = 72 - 1;        // 分频至1MHz
    tim.TIM_Period = 1000 - 1;         // 周期1ms → 1kHz PWM
    TIM_TimeBaseInit(TIM3, &tim);

    oc.TIM_OCMode = TIM_OCMode_PWM1;
    oc.TIM_OutputState = TIM_OutputState_Enable;
    oc.TIM_Pulse = 500;                // 初始50%占空比
    oc.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC1Init(TIM3, &oc);            // 左轮PWM
    TIM_OC2Init(TIM3, &oc);            // 右轮PWM
    TIM_Cmd(TIM3, ENABLE);
}

随后通过修改CCR寄存器动态调整占空比,实现无级调速。进一步地,若加入编码器反馈,还可构建PID闭环控制系统,显著提升速度稳定性和响应一致性。

不过L298N也有局限:发热严重,长时间大电流运行需加装散热片;逻辑电平虽标称兼容3.3V,但仍建议加电平转换缓冲;其自带的5V稳压输出虽可为MCU供电,但负载突变时易造成电压波动,最好外接LDO单独供电。


整个系统的架构可以简化为如下拓扑:

[锂电池 7.4V]
     ↓
[L298N] ←→ [左电机][右电机]
     ↑ENA/ENB(PWM)
[STM32F103]
   ├─ PC0~PC2 → [红外传感器阵列]
   ├─ PB0 ← [HC-SR04 Echo]
   ├─ PB1 → [HC-SR04 Trig]
   ├─ PA0~PA3 → [L298N IN1~IN4]
   └─ TIM3_CH1/CH2 → [ENA/ENB](PWM输出)

运行流程上,主循环定期扫描传感器状态。优先级设计尤为关键: 避障应高于寻迹 。也就是说,即使正在跟踪路线,一旦检测到前方障碍物小于安全距离,立即暂停循迹逻辑,执行后退+转向动作,待清除威胁后再恢复原任务。

这种模式切换可通过状态机清晰表达:

typedef enum {
    STATE_TRACKING,
    STATE_AVOIDING,
    STATE_STOPPED
} RobotState;

RobotState state = STATE_TRACKING;

while (1) {
    uint32_t dist = Get_Distance();

    if (dist < 20) {
        state = STATE_AVOIDING;
    } else {
        state = STATE_TRACKING;
    }

    switch (state) {
        case STATE_TRACKING:
            Track_Scan();
            break;
        case STATE_AVOIDING:
            Avoid_Obstacle();
            break;
        default:
            Motor_Stop();
    }
}

此外,机械布局同样影响性能表现:红外传感器距地高度宜控制在1cm左右,过高会降低灵敏度,过低则易受颠簸干扰;超声波探头应居中安装,避免偏斜造成测距偏差;两轮差速转弯时还需考虑最小转弯半径,防止卡死。


在实际调试过程中,常见问题包括:

  • 寻迹抖动 :可能是地面反光不均或传感器响应不稳定所致。解决方案是增加软件滤波,如滑动平均或多点投票机制。
  • 超声波误检 :回波散射或环境噪声可能导致虚假读数。可设定最小有效距离(如10cm以上),并连续测量3次取中值。
  • 电机启动冲击 :直接全速启动易打滑甚至烧毁驱动芯片。推荐缓启策略——从低占空比逐步增加至目标值。
  • 电源波动 :电机启停瞬间会引起电压跌落,可能导致MCU复位。建议在电源端并联1000μF以上电解电容,并使用独立稳压电路为控制系统供电。

为了便于调试,还可以启用串口通信,将传感器原始值、当前状态、PWM输出等信息实时打印出来,帮助定位异常行为。如果未来想扩展功能,比如加入OLED显示、蓝牙遥控或WiFi上传数据,这个基础框架也能轻松对接。


这种基于STM32的智能小车,本质上是一个微型机器人控制系统。它虽未使用复杂的AI模型或SLAM算法,但却完整体现了嵌入式工程的核心思想: 用有限资源解决实际问题 。从模拟信号采集到数字逻辑判断,从PWM生成到电机控制,每一个环节都需要软硬件协同优化。

更重要的是,它的模块化结构极具延展性。下一步完全可以引入编码器实现里程估算,结合PID算法做到匀速巡航;也可以添加MPU6050陀螺仪进行姿态校正;甚至移植FreeRTOS,将传感器采集、电机控制、通信任务拆分为独立线程,提升系统响应效率。

无论是作为课程设计、竞赛项目还是自学练手,这套方案都提供了扎实的技术起点。它教会我们的不只是如何让一个小车跑起来,而是如何构建一个可靠、可控、可演进的嵌入式系统。而这,正是通往更高级机器人开发的必经之路。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐