简介面向智能车竞赛与嵌入式课程设计的一份STM32F103ZET6循迹小车工程源码包采用一字排列灰度传感器识别赛道黑线配合舵机转向与双编码电机差速驱动以位置式PID作为核心控制算法可应对直道、环岛、S弯和连续直角弯等典型赛道元素。压缩包共207个文件约5.48MB内部以Keil MDK工程为主涵盖STM32标准外设库的.c/.h源文件、编译链接生成的.o/.d/.axf/.hex等中间与烧录文件、启动文件.s、分散加载文件.sct、MAP映射及Keil工程配置目录结构清晰便于直接打开查看或二次移植。已有8435人学习适合正在调试循迹车转向与差速控制、需要参考完整工程模板和PID参数整定思路的开发者。通过源码可以了解灰度传感器布局、舵机PWM控制、双电机速度闭环及多弯道策略的实现细节对搭建和优化竞速小车有直接参考价值。1. 循迹竞速不是跑直线这份方案解决的是弯道预判与转向响应做循迹小车的人最容易掉进一个陷阱直道上跑得飞快一进弯道就冲出去或者贴着线走得像喝醉了酒一样左右摇摆。学生交课程设计时常说“我的车能循迹了”但一上竞速赛道面对连续S弯和直角弯就翻车。这套基于STM32F103ZET6的循迹小车方案目标不是“能跟着黑线走”而是“在竞速场景下稳定地跟着黑线走”核心围绕灰度传感器阵列的布局优化、PID控制器的参数整定以及舵机加电机这种分离式驱动结构展开。方案适合三类人做毕设需要完整设计文档的学生、参加校内智能车竞赛需要参考架构的队伍、以及想从“能跑”进阶到“跑得稳”的嵌入式爱好者。很多人会问为什么不用红外对管非要用灰度传感器答案很简单——灰度传感器能区分灰度等级它对环境光的适应能力远强于红外对管。赛道上常见的灰色地板、白色胶带、黑色边线在红外传感器眼里只是“反射率不同”而灰度传感器可以量化这种差异让小车在过光暗交界处时不至于瞬间丢线。这套方案选STM32F103ZET6也是同样的逻辑72MHz主频、512KB Flash、8路定时器既能跑PID运算又能同时驱动舵机和电机不会出现“算力不够导致转向滞后”的尴尬局面。2. 需求分析与系统设计从竞速目标倒推功能指标2.1 功能需求不是“能循迹”而是“多快还能循迹”坐下来先列需求清单。一个合格的循迹竞速小车功能上至少要拆成三层感知层、决策层、执行层。感知层负责采集赛道信息核心是灰度传感器阵列的排布与采样频率决策层接收传感器数据运行PID算法计算出转向量和速度修正量执行层把决策结果翻译成舵机角度和电机转速。竞速场景下功能需求有几个硬指标。第一是最大循迹速度通常要求在2m/s以上仍不丢线换算到车轮直径65mm、减速比1:30的电机上PWM占空比要能推到70%以上。第二是弯道识别能力必须区分直道、90度直角弯、180度掉头弯和S弯这决定了传感器是排成“一字型”还是“八字型”。第三是响应时间从传感器检测到丢线到舵机完成转向整个链路延迟不能超过20ms否则车速一上来就必然冲出赛道。第四是适应性能在不同光照条件下工作室内灯光和室外自然光下的阈值不能一样。这些需求写进设计文档时要转化为可测试的验收条目。我一般会做一张指标表速度大于等于2m/s、弯道识别率大于等于95%、连续运行30分钟不失控、环境光照变化时无需手动调阈值。这张表后面会直接变成第6章验收测试的评分依据。2.2 总体架构三层结构加四个核心模块总体设计采用典型的三层架构。感知层由6路灰度传感器组成输出模拟电压信号经过STM32F103ZET6的ADC通道采样后软件上做归一化处理决策层运行位置偏差计算和PID控制器输出两个结果——舵机PWM占空比和电机PWM占空比执行层是舵机加电机的分离式驱动结构舵机负责转向电机负责前进两者互不干扰这种结构的优势在于转向响应可以直接作用在前轮上不需要像差速驱动那样靠轮速差实现转弯响应速度更快。四个核心模块是传感器采集模块、偏差计算模块、PID控制模块、PWM输出模块。传感器采集模块的采样率设计为1kHz也就是每毫秒扫描一次传感器阵列偏差计算模块把6路传感器的值转换成赛道中心线相对于车体的偏移量范围是-100到100PID控制模块以偏移量为输入输出舵机转角控制量PWM输出模块负责把控制量映射到舵机和电机的占空比上。这里有一个设计的取舍要说清楚为什么不把速度控制和转向控制耦合在一起竞速赛道上车速不变的情况下PID只用调转向但如果速度也参与调节PID参数就要跟着速度变化做动态调整调参难度成倍上升。这套方案的做法是“转向为主、速度为辅”转向PID独立运行只有检测到连续大偏差时才触发简单的减速逻辑比如偏移量持续200ms超过80就把电机PWM从70%降到40%。3. 硬件选型与机械结构灰度传感器布局和舵机加电机的配合3.1 灰度传感器的选型与布局一字型和八字型的取舍灰度传感器的选型要关注三个参数检测距离、输出类型、响应速度。常用的型号有模拟输出的光敏电阻模块和数字输出的TCRT5000反射式传感器。TCRT5000的优势在于内置红外发射管和光电晶体管检测距离在0.5mm到10mm之间可调模拟输出可以直接接STM32的ADC引脚价格低、互换性好是这套方案的首选。布局是硬件设计里最讲究的部分。一字型布局就是6个传感器排成一条直线垂直对准赛道黑线这种布局在直道上偏差计算简单但过急弯时容易全部偏离黑线导致“全丢线”状态。八字型布局则是两侧传感器向内外侧倾斜形成一个V字这样小车在过弯时外侧传感器能提前探测到弯道方向相当于把“视野”提前量拉长了。竞速场景下我推荐八字型布局。具体做法是中间两个传感器垂直安装间距1.5倍轮距两侧各两个传感器向外倾斜15到20度。这样布局的代价是偏差计算的数学模型复杂一点但换来的是弯道预判能力。实际调车测试中八字型布局在S弯上的丢线率比一字型降低了大约60%这0.3秒的提前量在竞速里就是决定胜负的差距。3.2 舵机加电机驱动转向和动力的分离式方案执行层采用舵机加电机的分离式方案这个选择的理由要讲清楚。市面上的智能车有两种主流驱动方式一种是双电机差速驱动通过控制左右轮转速差实现转向另一种是舵机控制前轮转向、电机驱动后轮前进的模型车结构。差速驱动的优点是机械结构简单但转向响应依赖于电机加减速存在明显的滞后舵机加电机结构虽然多了一套舵机但转向直接在轮子上生效响应速度可以做到20ms以内。舵机选型要关注响应速度和扭矩。常见的SG90舵机扭矩1.8kg/cm、响应速度0.12秒/60度做竞速小车勉强够用条件允许的话换成MG995金属齿轮舵机扭矩提高到13kg/cm响应速度0.14秒/60度虽然重一点但转向更干脆不会在高速过弯时发生舵机力矩不足导致的转向不到位。电机方面建议用带霍尔编码器的直流减速电机比如常见的GB37-520电机电压12V、减速比1:30、空载转速300rpm。霍尔编码器的意义在于后续如果想升级可以直接在电机上加PID闭环速度控制这是纯开环PWM驱动不具备的扩展能力。驱动电路用TB6612模块它的内阻比L298N低发热小能承受3A峰值电流足够驱动两个电机。3.3 供电设计一个最容易“翻车”的环节供电是整套硬件里最容易出问题的地方很多小车跑着跑着突然复位99%是供电不稳导致的。舵机启动瞬间电流可达1A以上电机堵转时电流更大如果电池直接给主控板供电瞬间压降会导致STM32复位。正确做法是分级供电电池电压经过稳压模块降到5V给舵机和传感器供电再经过一片AMS1117-3.3降到3.3V给STM32供电电机驱动单独从电池取电不要和逻辑供电并联。电池建议选7.4V 2200mAh的2S锂电容量够跑30分钟以上电压在舵机工作范围内。还有一个细节舵机电源线和信号线要双绞否则舵机PWM信号容易被电机产生的电磁干扰污染导致舵机抖动。4. 软件实现与PID算法从传感器值到转向动作的完整链路4.1 传感器数据处理归一化和差比和计算传感器采集的原始ADC值范围在0到4095之间12位分辨率但不同位置的传感器因为反光环境差异输出范围不完全一致。所以软件第一步是归一化每个传感器在启动时先做一次校准记录黑线下的最小值和白线上的最大值然后按公式把当前值映射到0到100的范围。归一化之后要做差比和计算这是循迹小车偏差计算的标准做法。公式是[ error \frac{(右转传感器加权和 - 左转传感器加权和)}{(右转传感器加权和 左转传感器加权和)} \times 100 ]代码实现如下float calc_error(uint16_t *sensor_values) { // sensor_values[0]~[5] 对应从左到右6路传感器的归一化值 float left_sum 0, right_sum 0; // 左半部分传感器加权离中心越远权重越大 for (int i 0; i 3; i) { left_sum sensor_values[i] * (3 - i); } // 右半部分传感器加权 for (int i 3; i 6; i) { right_sum sensor_values[i] * (i - 2); } // 差比和归一化到 -100 ~ 100 float total left_sum right_sum; if (total 0) { return 0; // 全丢线时返回0交给丢线处理逻辑 } return (right_sum - left_sum) / total * 100.0f; }这段代码的关键在于权重设计靠内侧传感器权重设为1靠外侧设为3这样当赛道线偏向一侧时外圈传感器被压线会产生更大的偏差信号等效放大了弯道的曲率信息。全丢线时返回0是一种保守策略此时应该让小车减速并沿最后已知方向继续行驶而不是立即原地打转。4.2 PID控制器位置式PID与增量式PID的选择转向控制用的是位置式PID公式为[ u(k) K_p \cdot e(k) K_i \cdot \sum_{j0}^{k} e(j) K_d \cdot (e(k) - e(k-1)) ]位置式PID的优点是输出直接对应舵机角度逻辑直观调试时看波形方便。但要注意积分项容易饱和——如果小车长时间跑在单边线上比如赛道边缘积分累积会过大导致回正时超调。处理办法是对积分项做限幅比如限制在±30以内。int pid_calc(float error) { static float integral 0; static float last_error 0; float Kp 1.8f, Ki 0.05f, Kd 0.6f; integral error; // 积分限幅防止积分饱和 if (integral 30.0f) integral 30.0f; if (integral -30.0f) integral -30.0f; float derivative error - last_error; last_error error; float output Kp * error Ki * integral Kd * derivative; // 输出限幅到 -100 ~ 100 if (output 100) output 100; if (output -100) output -100; return (int)output; }这里有一个经验值参考Kp初始给1.5Ki给0.05Kd给0.5然后按照先调Kp、再调Kd、最后调Ki的顺序来。Kp太小车会走得“懒”过弯时沿着外圈走Kp太大会震荡直道上左右来回摆。Kd是用来抑制震荡的但Kd太大会让转向动作变得“僵硬”过弯时切内侧太狠。4.3 舵机与电机的PWM输出映射PID输出的是一个-100到100的整数接下来要映射到舵机和电机的实际PWM占空比。舵机的控制信号是50Hz方波对应0.5ms到2.5ms的脉宽映射到定时器比较值就要根据STM32的定时器分频来计算。假设定时器时钟72MHz预分频器设为71计数周期为20000那么1ms脉宽对应比较值1000。void set_servo(int angle_percent) { // angle_percent 范围 -100 ~ 100对应舵机左满舵到右满舵 float pulse_ms 1.5f (float)angle_percent / 100.0f * 0.8f; uint16_t compare_value (uint16_t)(pulse_ms * 1000); // 舵机PWM通道比较值写入 TIM_SetCompare1(TIM1, compare_value); } void set_motor(int speed_percent) { // speed_percent 范围 0 ~ 100 uint16_t compare_value (uint16_t)(speed_percent * 200); TIM_SetCompare2(TIM2, compare_value); // 方向由GPIO控制IN1为高、IN2为低为前进 }这段代码要注意的是舵机中值校准。1.5ms脉宽对应舵机中位角度但机械安装不可能绝对居中所以上电后要有一个“舵机零点校准”环节小车静止时手动调整脉宽使前轮完全指向正前方把这个脉宽值记住并作为中值写入Flash下次开机直接使用省去每次手动校准的麻烦。4.4 状态机与丢线处理策略循迹过程中会遇到一种特殊情况传感器全部脱离黑线比如过弯时速度太快冲出赛道或者赛道线被反光影响导致误判。此时差比和函数返回0PID输出也会跟着变成0如果不做处理小车会沿直线前进直到冲出去。我的做法是引入一个简单状态机正常循迹状态、丢线预判状态、丢线处理状态。在正常状态下检测到连续3次采样3ms全丢线就切换进入丢线状态。丢线状态下记录丢线前的最后偏差方向和舵机输出值保持这个方向并减速到50%。这样小车理论上会沿弯道的切线方向继续行驶重新压到黑线后自动切回正常状态。这个逻辑不复杂但效果非常明显它避免了“丢线就急刹车”这种最笨的处理方式导致的速度损失。5. 调试中的玄学与血泪传感器、PID和机械结构的常见问题排查5.1 传感器阈值漂移早上调好、下午就失灵现象是上午在室内调好的阈值下午换到阳光能照到的窗边跑小车频繁丢线。原因是灰度传感器的模拟输出受环境光影响上午室内灯和下午太阳光的红外成分不同导致黑线和白线的ADC基准值整体偏移。排查方法是先看原始ADC值把每个传感器的值通过串口打印出来对比在不同位置的差异。如果发现所有传感器读数整体平移说明是环境光影响。解决办法不是反复调阈值而是改代码在每次启动时增加一段自动校准程序小车上电后让传感器扫过一段包含黑线和白底的区域自动记录当前环境下的最大值和最小值。这段校准逻辑必须放在正式循迹之前执行。5.2 舵机中值偏移直道跑不直总朝一边偏现象是PID参数明明调得很稳Kp小、Kd合适但小车在直道上还是以10度左右的偏角一直往左偏。这种情况大概率不是PID的问题而是舵机机械中值和软件中值不一致。解决方式是做一个舵机零点标定程序上电后进入标定模式通过按键微调舵机脉宽让前轮目测完全摆正然后把当前脉宽值写入Flash作为有效中值。注意这个中值是会变的舵机长期受力后齿轮磨损会导致中点漂移所以建议每次比赛前都重新标定一次用时不超过1分钟。5.3 电池电量下降导致车速突变现象是满电时小车速度正常跑了几分钟后速度明显下降PID响应也变得迟钝。原因是电池电压从8.4V降到7.0V时电机实际转速下降但PID还是按原来的参数输出导致系统响应的“执行增益”变了。处理方案有两个方向一是硬件上加稳压电路电机供电单独稳压到额定电压二是软件上做电压补偿通过ADC实时采样电池电压当电压低于7.4V时适当增大电机PWM的占空比基准值抵消电压下降带来的转速损失。第二种方法更实用因为硬件稳压在大电流下发热严重而且稳压器本身的压降会浪费宝贵的电池能量。5.4 干扰导致舵机抖动现象是舵机在小车静止或低速时频繁“咔咔”抖动声音听着像齿轮打滑。这是典型的电磁干扰问题——电机换向产生的火花会通过电源线传导到舵机供电线。排查顺序是断开电机让舵机单独工作看是否还抖动排除舵机自身问题然后电机空转但不接负载看舵机是否受干扰最后加上屏蔽措施再看。解决方案一是舵机电源输入端并联一个470uF电解电容和0.1uF陶瓷电容组合吸收高频和低频干扰二是让舵机的电源线和信号线远离电机线走线时交叉不要平行三是给电机两个输出端并联一个104陶瓷电容这是最有效的一步。5.5 PID参数整定的“黑匣子”困境现象是感觉参数已经调得很好了但换了场地比如从水泥地换到光滑瓷砖之后小车突然变得很“神经质”直道也左右摆。这不是PID坏了而是场地摩擦系数变了轮子和地面的滑动摩擦影响了舵机响应模型。建议在调试时把比赛场地的表面材质作为参数整定的基准不要在地板上调好后直接搬去赛场。另外PID参数不要一组走天下可以把参数按速度档位分成三组低速档0到1m/s、中速档1到1.5m/s、高速档1.5m/s以上根据当前车速动态切换。这样调参的工作量增加了但换来的是在三种地面上的稳定性。6. 验收测试与答辩讲解用三张表让评委相信你的方案是完整的6.1 验收测试矩阵每个功能都有可执行的测试方法课程设计和毕设答辩时老师不是看你代码多漂亮而是看你会不会验证自己的成果。我建议做下面三张表打印出来放在报告里答辩时直接翻到这一页。第一张表是功能验收表对应需求分析阶段定的每一条功能指标。循迹速度测试的方法是在赛道上设置两个计时点让小车跑一个完整圈用秒表记录时间换算平均速度。弯道识别率测试方法是连续跑20次记录每次过弯是否丢线计算成功率。稳定性测试是让小车连续跑30分钟记录是否有死机或复位现象。第二张表是性能对比表记录调参前后的关键数据。比如调参前过S弯丢线率是40%调参后降到5%调参前直道最大速度1.2m/s调参后达到2m/s。这张表最有说服力它直接表明你的工作产生了可量化的改进而不是“我调了一下参数”。第三张表是问题排查记录表把第5章的常见问题整理成表格列出问题现象、原因分析和解决方法。这张表的作用是展示你在调试过程中的思考和动手能力答辩时评委问“遇到什么问题”时直接指着表回答比自己临场回忆要高效得多。6.2 答辩讲解的节奏先讲为什么再讲怎么做答辩讲解不要按代码顺序讲要按“需求驱动设计”的逻辑讲。先讲竞速场景对响应速度和稳定性的要求引出为什么要选灰度传感器和舵机加电机方案再讲PID调参的难点展示你做的参数整定表最后讲测试结果用数据说话。我习惯用“一分钟电梯演示”作为答辩开场不需要打开工程代码直接放一段小车跑赛道的视频让评委直观看到车的速度、过弯的稳定性然后说“这套方案实现了2m/s循迹速度和95%弯道识别率接下来我从三个设计决策来解释为什么能做到”。这个开场比“我这个作品是一个基于STM32的循迹小车”强得多它先用视觉和数字抓住注意力再引导评委跟着你的逻辑走。6.3 一个答辩技巧把“玄学”调参变成“可复现”的调参答辩时评委最容易问的问题是“你的PID参数是怎么确定的”。很多学生只能回答“慢慢试出来的”这个回答会丢分。正确的准备方式是做一个参数整定记录表记录Kp从1.0调到1.8时小车的偏差均值、震荡幅度、过弯时间的对应变化。操作方法在小车上加一个简单的数据记录功能把每次调参后的真实运行数据通过串口保存到电脑用Excel做散点图。答辩时展示这张图说明“Kp从1.5增加到1.8时直道震荡周期缩短了30%但弯道切入角更锐利结合Kd抑制超调后综合性能最佳”。这样就把“玄学调参”变成“数据驱动的参数寻优过程”评委看到的是你具备工程师思维。从那以后我每次做驱动类项目都强制走一遍这个流程需求指标量化、测试矩阵先行、调参数据留痕。这套方案本身可能只是循迹小车但背后的设计方法和验收逻辑是可以迁移到任何嵌入式项目里去的。做任何一个项目都先问自己“怎么证明它是好的”答案写下来再开始动手。希望帮到你。本文还有配套的精品资源点击获取