ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

STM32循迹避障小车从零搭建:硬件选型与算法调试全解析

2026/8/30 7:23:34 拓冰建站 浏览量
STM32循迹避障小车从零搭建:硬件选型与算法调试全解析 简介本资源是一套面向嵌入式初学者与课程设计者的STM32循迹避障小车完整开发资料覆盖硬件设计、Proteus仿真验证与ARM Cortex-M内核编程全流程适用于电子工程、自动化及物联网方向的实践教学与项目实训。压缩包含332个文件总大小3.66MB其中120个.h头文件与113个.c源码构成完整的STM32固件工程含PID循迹控制、超声波/红外AD采集、电机驱动及避障决策逻辑24个.s启动文件与多个.uvprojx/.uvoptx工程配置支持Keil MDK直接编译5份.SchDoc原理图明确标注ADC传感器接口与电机驱动电路配合Proteus仿真模型可实现软硬协同调试。已有7945人学习下载资料结构清晰、模块解耦度高包含可运行Hex固件、调试配置文件.dbgconf、日志记录及备份版本便于理解底层寄存器操作、外设初始化流程与实时控制算法实现细节。 做小车这件事说难不难说简单也真不简单。尤其是到了STM32这一步从点亮一颗LED到让车真正“跑起来还会躲”中间隔着一整条硬件和软件交织的流水线。这篇内容我基于自己做过的STM32循迹避障小车把从方案选型到硬件搭建、再到软件逻辑和实际调试的完整过程整理出来该踩的坑都帮你标好了。如果你正准备做一辆能循线走、又能自动避开障碍的STM32小车或者手里已经有一堆模块但不知道怎么整合这篇文章应该能给你省下不少瞎折腾的时间。1. 项目定位与整体方案选型1.1 功能需求拆分先别急着焊板子做小车第一步一定是想清楚“我要它干什么”。循迹避障小车本质上是一个自主移动机器人平台核心功能可以拆成三个大块循迹功能小车能沿着地面上预设的黑色或白色引导线自动行驶避障功能行驶过程中检测到前方障碍物时能自动停车、转向或绕行运动控制两个电机分别驱动左右轮通过差速实现直行、转弯、掉头这三个功能听起来各自独立但实际是相互耦合的。比如循迹时要保持直线速度稳定避障时又要立即打破循迹状态去执行转向这两个逻辑怎么切换是软件设计的核心问题。另外功能拆分还要考虑边界是室内地面还是室外粗糙路面速度要求多快要不要无线遥控切换模式这些都会影响选型和架构设计。我自己做的这版定位是室内教学演示级平台最高速度控制在0.5m/s左右循迹线与障碍物都是标准场景。这个定位决定了我不需要上太高端的传感器重点放在逻辑完整性和稳定性上。1.2 主控选型为什么选择STM32小车主控选型STM32几乎是绕不开的选项。我选用的是STM32F103C8T6也就是大家常说的“蓝板”最小系统板。这颗芯片是Cortex-M3内核主频72MHzFlash 64KBRAM 20KB放到今天怎么看都算“落后”但对循迹避障小车来说性能完全够用而且它有个巨大的隐性优势——相关资料多到溢出来。从技术角度分析STM32F103C8T6有几个特性恰好贴合小车项目定时器资源丰富4个16位定时器可以同时输出多路PWM。左右轮电机各需要1路PWM控制速度加上舵机扫描避障又占1路定时器完全够分配ADC通道数量充足如果循迹传感器选模拟量输出的灰度传感器需要同时采集多路信号STM32的多通道ADC配合扫描模式很合适串口数量多调试时用串口打印传感器数值、状态切换信息这个刚需必须满足生态成熟不管是标准库还是HAL库例程代码一抓一大把遇到问题搜一下基本都有答案对比过其他主控Arduino确实上手快但PWM通道和定时器控制精度有限而且学到的东西偏应用层面不利于后续往嵌入式方向深入ESP32的Wi-Fi蓝牙功能很强但引脚复用要考虑矩阵映射对新手反而增加理解成本。综合下来STM32是做小车最均衡的选择。注意这里说的是F103系列不是F407或H7。选型时不要盲目追求高性能对于低速小车F103C8T6性价比极高功耗也更低。后续想扩展视觉识别再考虑换更高端的芯片也不迟。1.3 传感器方案对比与选择传感器选型直接决定小车的“感知边界”这块我对比过几种主流方案各有适用场景。循迹传感器选型循迹的本质是识别地面颜色差异。目前主流方案有三类方案原理优势劣势红外反射对管TCRT5000红外LED发射光接收管检测反射强度便宜、响应快、数字/模拟输出可选易受环境光干扰灰度传感器检测反射光量化值输出模拟电压精度高、可调阈值价格略高、需要ADC摄像头视觉识别图像处理识别路径适应性最强、可识别复杂路径算法复杂、算力要求高我的选择是TCRT5000红外反射传感器5路一字排开。为什么不用单路或三路因为循迹小车过弯时如果传感器数量少很容易在弯道处丢失参考线。五路传感器可以形成一个宽度覆盖小车压线的容忍范围更大控制算法也好写。避障传感器选型避障需求核心是“测距”常用方案超声波模块HC-SR04测距范围2cm到400cm原理是发射声波并计算回波时间。优点是便宜、测距直观、精度够用缺点是响应速度慢声速340m/s测一次需要几毫秒到几十毫秒且对斜面障碍物可能漏检红外避障传感器近距离检测效果好但测距能力弱一般在10cm以内激光雷达精度高、扫描范围广但价格昂贵不适合入门项目我最终选用超声波HC-SR04加舵机云台方案就是让超声波模块安装在舵机上可以左右旋转扫描前方区域。这样既解决了单点超声波探测范围窄的问题成本也比激光雷达低得多。舵机控制需要一路PWM频率50Hz和电机PWM的频率规划要分开处理。2. 硬件搭建与模块接线详解2.1 电机驱动方案与接线小车运动执行机构是电机而STM32的GPIO输出电流很小直接驱动电机是不现实的。这里需要电机驱动芯片/模块来完成功率放大。我对比过两个常用方案L298N模块经典双H桥驱动驱动能力强支持大电流电机。但缺点是发热大、压降高用的是三极管或达林顿管控制精度一般而且模块体积大TB6612FNG模块东芝MOSFET驱动相比L298N压降小很多发热低、体积小、响应快。同样支持双电机最大驱动电流1.2A对于常见的N20减速电机和TT马达完全够用我选的是TB6612FNG。接线也很直接模块的PWMA/PWMB接STM32定时器输出的PWM引脚AIN1/AIN2、BIN1/BIN2接普通GPIO控制电机正反转STBY引脚接高电平使能模块。电机侧接左右轮子电源模块直接输入电池电压。这里有个新手很容易踩的坑驱动模块的控制信号是标准3.3V逻辑STM32 GPIO完全可以直接驱动但电源部分必须谨慎。TB6612的VM引脚接电池正极VCC引脚接3.3V或5V逻辑电源如果不接VCC模块完全不工作。另外驱动板的GND必须和STM32的GND共地否则控制信号没有参考电平小车会乱跑甚至完全不动。2.2 电机本体选择N20减速电机与TT马达电机的选择影响小车的速度、扭矩和稳定性这块我踩过不少坑。市面上常见的两种电机TT马达130减速电机便宜、扭矩一般、转速高。配套的橡胶轮安装简单适合做极低成本的小车N20减速电机微型减速电机带金属齿轮箱扭矩大、体积小、噪音低。工作电压常见3V-12V配上合适的轮胎爬坡和稳定性都更好我的最终方案是左右轮各用一只N20减速电机1:30减速比6V版本配合编码器版本。这里多花一点钱选带编码器的型号非常值得因为编码器可以测速后续做速度闭环PID全靠它。如果只靠PWM开环控制小车在电池电压变化时速度会明显漂移循迹直线都跑不直。2.3 循迹传感器布局与安装细节TCRT5000循迹传感器的安装是影响循迹效果的关键细节需要单独说一下。TCRT5000模块原理很简单红外发射管发射红外光照到黑色物体时吸收多、反射少光电接收管输出高电平照到白色物体反射强输出低电平。模块板载电位器可以调节比较器阈值用手悬空放在传感器上方1cm左右旋动电位器让指示灯刚好变化就是比较合适的阈值。安装时注意三个要点离地高度控制在1cm-1.5cm。太高红外光散射严重黑白区分度下降太低小车过颠簸路面时传感器容易撞地损坏五路传感器一字排开间距要匹配引导线宽度。我用的引导线是2cm宽黑色电工胶带五路传感器总覆盖宽度约10cm。如果间距过大小车会“跳线”弯道处容易出现全部传感器都检测不到线的情况传感器安装位置尽量靠近前轮轴线前方。这样可以提前感知车道变化给转向控制留出反应时间。装太靠后等发现偏离时车子已经冲出线了2.4 超声波避障模块与舵机云台HC-SR04超声波模块接线是标准的四针VCC、Trig、Echo、GND。工作原理是Trig引脚给一个10us以上的高电平触发信号模块自动发送8个40kHz脉冲然后Echo引脚输出一个高电平高电平持续时间就是超声波往返时间。距离计算公式是距离(cm) 高电平时间(us) / 58。这个模块接线虽然简单但有两个细节影响稳定性供电电压HC-SR04工作电压是5V如果直接接STM32的3.3V引脚模块工作不稳定测距结果跳动很大。我给模块单独接了5V电源Echo返回信号是5V电平直接接到STM32的3.3V引脚有超压风险。很多开发板引脚其实有钳位保护能正常工作但严谨做法是加一个电阻分压或者电平转换电路舵机方面我选的是SG90 9g舵机可以用一路PWM控制转动角度。PWM周期20ms高电平时间从0.5ms到2.5ms对应0°到180°。实际测试下来SG90扭矩偏小如果超声波模块加支架太重会抖动建议用MG90S金属齿轮舵机或者选扭矩更大的舵机。2.5 电源系统最容易翻车的地方电源是整个小车里最容易出问题也最容易被忽视的部分。我给小车配了两套电源电机供电两节18650锂电池串联标称电压7.4V直接给TB6612的VM引脚供电逻辑供电STM32和传感器需要3.3V/5V我用一个AMS1117-5.0稳压模块从7.4V降压得到5V再通过STM32板载稳压器得到3.3V这里有个重要的工程经验电机和逻辑电源建议分开走至少在电源入口处用大电容隔离。N20电机启动和堵转时电流尖峰很大如果和逻辑电路共用一根导线瞬间的电压跌落会直接导致STM32复位。我最初为了省事电机电源和逻辑电源共用一个开关结果小车一加速就重启。后来单独加了一个470uF电解电容并在电机电源端并让逻辑电源从电池端单独取电问题才解决。如果不用18650锂电池也可以用两节或三节AA电池盒串联但要注意电池内阻大大电流放电能力差电机急加速时电压跌落更明显。预算充足的话一块7.4V航模电池是最稳的选择。3. 软件架构与核心代码实现3.1 开发环境与工程创建软件部分我采用Keil MDK STM32标准库的组合。虽然STM32官方早已停止标准库维护、全面推广HAL库但标准库在社区中的存量资料仍然极为丰富尤其是各个教程和例程绝大多数都能直接读懂、直接改。HAL库功能分层更清晰、可移植性好但封装层次多调试时跳转逻辑比较绕。我的建议是新手先学标准库理解寄存器怎么操作有一定基础后再上手HAL库。新建工程时需要注意因为F103C8T6的Flash是64KB需要把Target选项里的ROM起始地址设为0x08000000Size设为0x10000。如果设置不对下载程序后芯片不运行。另外晶振频率要配置为8MHz外部高速晶振如果板子上没有焊接外部晶振要选择HSI内部时钟否则系统时钟会变成8MHz的一半甚至更乱。3.2 定时器与PWM信号配置小车电机调速的核心是PWMSTM32用定时器产生PWM非常方便。我用TIM2的CH1和CH2分别控制左、右电机。配置要点PWM频率选10kHz也就是定时器计数值ARR为7200-172MHz/10kHz。为什么选10kHz而不是1kHz因为频率太低时电机会发出明显的啸叫而且电流纹波大加减速响应也偏慢频率太高比如100kHzMOSFET开关损耗增加驱动芯片发热加大。10kHz是一个相当平衡的取值。初始化代码大致如下void TIM2_PWM_Init(u16 arr, u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period arr - 1; TIM_TimeBaseStructure.TIM_Prescaler psc - 1; TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 0; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM2, TIM_OCInitStructure); TIM_OC2Init(TIM2, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE); }调用TIM_SetCompare1(TIM2, pwm_val)和TIM_SetCompare2(TIM2, pwm_val)就能实时调整左右轮速度。舵机控制用的PWM要单独设置一个定时器因为舵机需要50Hz的周期性信号。我用了TIM3的CH1ARR设为19999PSC设为72这样PWM频率正好是50Hz通过调节比较值来控制舵机角度比较值范围在500到2500。3.3 循迹算法与差速转向控制循迹控制是整个小车算法的核心走了很多弯路后我总结出一套比较稳的控制方式。基本逻辑五路传感器从左到右编号Sensor1到Sensor5检测到黑线时输出低电平注意我用的模块是输出低表示检测到黑线调试时要注意自己的模块极性。按照传感器状态组合可以分为几种情况中间三路检测到线车身基本在线中央直行右边传感器检测到线车身偏左需要右转左边传感器检测到线车身偏右需要左转全部丢失可能是大弯道或已出线保持上一状态最简单粗暴的代码是用if-else判断但这样转向生硬小车会左右振荡。我用的方案是比例式差速控制int error 0; // 根据传感器状态计算一个偏差值范围假设为-4到4 // Sensor1(最左)为-4Sensor2为-2Sensor3为0Sensor4为2Sensor5为4 // 检测到黑线的传感器对应位置累加 if (sensor_state (1 0)) error - 4; if (sensor_state (1 1)) error - 2; if (sensor_state (1 2)) error 0; if (sensor_state (1 3)) error 2; if (sensor_state (1 4)) error 4; // 基础速度 int base_speed 60; // 转向修正量 int turn error * Kp; // Kp为比例系数先取3~5试 left_speed base_speed - turn; right_speed base_speed turn; // 限幅 left_speed clamp(left_speed, -100, 100); right_speed clamp(right_speed, -100, 100);这样误差越大转向修正就越强车在过弯时能更平滑地跟随曲线。Kp系数需要实际调试太小过弯跟不上太大会振荡。我实测在base_speed60时Kp取4左右比较合适。如果路面不同需要重新调。3.4 避障状态机设计避障逻辑如果用一堆if-else堆在main循环里代码很快就会乱套。更科学的做法是设计一个有限状态机。我定义了几个状态typedef enum { STATE_FOLLOW_LINE, // 循迹行驶 STATE_AVOID_WAIT, // 检测到前方障碍准备避障 STATE_AVOID_SCAN, // 舵机扫描测量周围障碍物距离 STATE_AVOID_TURN, // 执行转向动作 STATE_AVOID_RECOVER // 恢复循迹 } CarState;主循环里执行状态机切换while (1) { switch (current_state) { case STATE_FOLLOW_LINE: follow_line(); // 检测到前方障碍且距离小于阈值进入避障 if (distance OBSTACLE_THRESHOLD) { current_state STATE_AVOID_WAIT; } break; case STATE_AVOID_WAIT: stop_car(); delay_ms(200); // 先停下给系统一个稳定时间 current_state STATE_AVOID_SCAN; break; case STATE_AVOID_SCAN: // 舵机转左、中、右三个方向分别测量距离 obstacle_left scan_left(); obstacle_right scan_right(); if (obstacle_left obstacle_right) { turn_direction TURN_LEFT; } else { turn_direction TURN_RIGHT; } current_state STATE_AVOID_TURN; break; case STATE_AVOID_TURN: // 原地旋转或边转边走持续一段时间后进入恢复状态 turn(turn_direction, 500); current_state STATE_AVOID_RECOVER; break; case STATE_AVOID_RECOVER: // 前进一段距离确保绕过障碍物后回到循迹线 forward(100); current_state STATE_FOLLOW_LINE; break; } }状态机的好处是每个状态功能独立便于调试和扩展。如果后续要加蓝牙遥控只需要多一个状态即可。实际测试中我发现避障完成后小车很难找回原来的循迹线。一个改进是不要走完整的“停止-扫描-转向-前进”流程而是采用“减速-测距-偏转绕过”的方式。比如检测到前方30cm内有障碍物先减速到低速然后向无障碍物一侧偏转一个角度继续前进同时持续检测传感器状态直到重新检测到线再恢复循迹。这种策略在简单场景下可靠性更高。3.5 定时器延时与防卡死问题调试过程中我也遇到过系统“卡死”的问题最常见场景是延时函数。标准库的HAL_Delay或自带的软件延时依赖SysTick中断如果在中断服务函数里调用了延时或者延时函数被中断反复打断系统会卡死。关于STM32延时函数delay卡死这个问题我也被折腾过很久。后来采用定时器延时替代软件循环延时并且在中断函数里只做标志位置位不做耗时操作问题就消失了。具体原理软件延时的本质是空转CPU如果中断频繁抢占延时时间会大幅缩短无限循环等待某个标志位时就可能永远等不到。另外补充一点DWT替换STM32 HAL库延时是近期比较热门的一个优化方向。DWTData Watchpoint and Trace单元可以用于精确计时原理是读取内核时钟计数器实现微秒级延时精度远高于软件循环延时。如果项目对延时精度要求高可以研究一下。3.6 测速闭环与简易PID实现做了开环PWM控制后你会发现同样的PWM占空比在充满电和快没电时速度完全不一样。为了让小车速度稳定尤其是循迹直线段不走偏需要加入测速闭环。N20减速电机自带的编码器一般是霍尔式每转输出一定数量的脉冲。我用STM32定时器的输入捕获模式来测量脉冲频率从而算出轮子转速。配置要点是编码器A相输出接TIM某个通道选择上升沿触发在中断里计数也可以直接用TIM编码器接口模式。测出实际速度后PID控制器输出PWM修正量。例如期望速度为60cm/s实际速度为52cm/sPID计算输出一个增量加到当前PWM上。公式我用的增量式PID// 增量式PID int pid_control(int target_speed, int current_speed) { int error target_speed - current_speed; integ error; deriv error - last_error; last_error error; return Kp * error Ki * integ Kd * deriv; }PID参数调起来需要耐心。我的经验是先只调Kp让速度快速接近目标值再加入Kd抑制超调最后根据稳态误差决定是否加Ki。增量式PID的好处是输出不会发生大幅跳变即使参数不完美也不至于让电机瞬间暴走。串口调试在这里非常关键。我在代码里用串口1发送速度值和PID输出值通过USB转TTL模块在电脑上实时观察不用猜参数。4. 联调、调试与常见问题排查4.1 串口调试与OLED显示小车调试有两个手段组合使用效率最高串口打印 OLED实时显示。串口打印用于动态数据的流水分析。我在STM32上初始化UART1波特率115200重定向printf到串口。每次循环打印当前状态、传感器状态、超声波距离、PID输出等。电脑端用串口助手查看数据量大时也可以记录到文件再分析。OLED显示则更适合现场快速查看状态。我用的是0.96寸I2C接口OLEDSSD1306驱动。接线只需SDA、SCL两根线加电源占用IO少。界面设计我通常分三行第一行显示当前状态循迹/避障/停止第二行显示超声波距离第三行显示左右轮PWM值。这样不用连电脑就能判断程序有没有跑对。OLED刷屏频率不要太高I2C速率400kHz刷新20Hz完全够用。顺便说一句STM32串口接收不定长数据在做无线遥控或上位机指令时很常用。可以用串口空闲中断配合DMA接收或者简单的做法是每收到一个字节就进中断根据帧头帧尾打包解析。4.2 循迹传感器灵敏度调试循迹最常见的问题是传感器阈值漂移。小车跑到不同地面同一个电位器设置下的输出可能完全不同。比如在白色瓷砖上测试正常换到浅色木地板上传感器可能全部误判为“检测到黑线”。解决思路有两个每次开机自动校准上电后小车原地旋转一会儿采集各传感器在“当前地面”上的最大/最小值把阈值设置为两者中值。这个方法实现不难代码不超过30行但效果提升巨大使用模拟量输出模式TCRT5000模块有些版本同时提供数字和模拟输出模拟量输出接STM32的ADC引脚通过软件设定阈值。优点是可以精细调节还方便后期做更复杂的模糊控制我后来直接改用模拟量读取 软件阈值的方案ADC配置用多通道扫描循环采样配合DMA能同时读取五路传感器的模拟电压值CPU不用逐个等待转换完成。这个模式在STM32标准库里的配置稍微繁琐一点但一旦配好后面扩展传感器数量就很方便了。4.3 避障误判与响应慢的排查思路避障功能调试中我遇到过两类典型问题。第一类是超声波测距跳动大。HC-SR04在空旷环境下测距比较稳定但靠近障碍物边缘或对着倾斜表面时回波信号弱距离值会突然变远。解决方法是做数据滤波。我用了最简单的滑动平均滤波连续采集5次距离去掉最大最小值取中间3个平均值。这样处理虽然会引入约几十毫秒延迟但对低速小车完全够用。第二类是避障响应慢车撞上障碍物还没有转向动作。排查后发现是程序结构问题主循环里先做超声波测距等Echo引脚变化用了ms级延时再做循迹控制再刷OLED整个循环周期拉到了100ms左右。而超声波测距一次最多需要约30ms4m量程如果再加上舵机扫描多个角度时间直逼200ms。优化方向很明确把测距放到定时器中断里比如每50ms触发一次超声波测距主循环只读取最新距离值舵机扫描不要一次占满主循环改成每200ms换一个扫描角度逐步更新三方向距离数据OLED刷屏频率适当降低不要每轮循环都刷这样优化后主循环周期稳定在10ms以内循迹和避障响应都流畅多了。4.4 复位、跑飞与电源干扰问题小车最烦人的问题就是跑着跑着突然复位而且毫无规律。排查这类问题我的步骤是先排除软件问题关掉所有中断只保留基本逻辑看是否还会复位再查电源用示波器或万用表观察电机启动瞬间的电源电压。N20电机启动电流峰值可能达到1A以上如果电池内阻大或者导线细电压跌落到3V以下STM32直接断电复位检查共地驱动板逻辑地和MCU地没连好可能造成控制信号电位漂移严重的会触发硬件保护重启针对排查结果我做了三个改动电机电源入口并联470uF电解电容和104陶瓷电容吸收瞬态尖峰逻辑电源和电机电源从各自回路走线只在最前端汇合串口调试时USB转TTL模块供电不要和电机共用一个电源否则电机转动瞬间串口断开解决复位问题后再加一道保险开启STM32独立看门狗IWDG。主循环里定时喂狗如果程序跑飞或死循环看门狗超时自动复位车子不至于保持失控状态。这在比赛和演示场景下是最后一道安全保障。4.5 PWM频段与电磁干扰实测关于PWM频率还有一个容易忽略的点PWM频率高时导线会形成天线效应产生电磁干扰影响超声波模块甚至循迹传感器。我实测过20kHz PWM下超声波测距偶尔会报错降到10kHz后恢复正常。如果你的小车出现“传感器数据莫名跳动但是接线也没问题”的情况试试降低PWM频率或者让电机线远离传感器信号线。5. 扩展思路与个人实操体会5.1 增加蓝牙遥控与手机App控制循迹避障小车做完基础功能后加一个蓝牙模块是性价比很高的扩展。HC-05或HC-06模块通过串口和STM32通信波特率9600电压3.3V可以直接接。我在程序里增加了一个UART回调函数收到“F/B/L/R/S”开头的指令时切换为遥控模式。手机端用现成的蓝牙串口App就能控制不需要自己写App。注意蓝牙模块和Wi-Fi模块同用串口时要处理竞争问题最简单的方法是物理上二选一。5.2 加装测速编码器做速度闭环如果你用的是带编码器的N20电机强烈建议把速度闭环加上。我自己是从开环控制改到闭环控制的体验差别非常大。开环时直线循迹会慢慢偏斜特别是在地面上有轻微灰尘时闭环后小车在直线段几乎纹丝不动。编码器接口选择上STM32有专门的定时器编码器模式配合AB相正交信号可以同时判断方向和计数。初始化时把两个GPIO配置成浮空输入打开TIM的编码器接口模式即可。速度测量我用的是定时器1ms中断读取计数器值换算成RPM再折算成线速度。5.3 多车组网与上位机监控如果手头有两辆小车可以考虑加一个简单的无线通信模块比如NRF24L01。STM32通过SPI接口跟NRF24L01通信组一个简单的星型网络。上位机电脑或手机作为主机发送启动/停止指令小车作为从机上报位置和状态。这个扩展做出来后整个项目的复杂度就从一个“点”变成“系统”了对理解物联网通信模型很有帮助。5.4 个人实操经验总结做这辆STM32循迹避障小车我的整体感受是难点不在于某个模块单独工作而在于所有模块协同工作时怎么保持稳定。单独测循迹跑得很好单独测避障也没问题合在一起可能因为一个延时函数没处理好整个逻辑就崩了。几条比较深的心得调试时尽量用串口把关键变量打出来不要靠猜软件架构用状态机比一堆if-else省心得多电源问题优先级最高电源不稳其他调试都是白费底盘机械结构要简单牢固螺丝松一点在高速循迹时都会导致传感器抖动进而影响判断最后再分享一个小技巧做联调之前花十分钟把每个模块单独测试一遍写个极简测试代码确认每个模块都能正常工作再接主程序。这样能省下大量“不知道是哪个模块的问题”的排查时间。每次烧录新程序时先把速度设低一点等确认控制逻辑正确了再加大速度能避免很多意外冲撞。小车的价值不在它本身跑得多远而在于你在搭它的过程中建立的系统调试能力和排查思路。这些能力以后换到任何嵌入式项目都能复用。如果你也正在做类似的小车项目希望这篇内容能让你少踩几个我已经替你踩过的坑。本文还有配套的精品资源点击获取