简介基于STM32F103ZET6的循迹小车资源包是一套完整的智能车竞赛/课程设计工程面向嵌入式初学者与竞赛队伍。方案采用舵机加双编码电机的机械结构以72MHz主频的STM32F103ZET6为核心通过一字排列的灰度传感器阵列识别黑线结合位置式PID算法进行舵机与电机的差速控制可较好应对直道、环岛、S弯及连续直角弯等典型赛道元素。压缩包内共207个文件包含36个C源文件、38个头文件以及.o/.d/.crf等编译中间文件同时提供.uvprojx工程文件、.hex烧录文件和.axf调试文件另有.sct、.map、.lst等链接/列表文件覆盖了从源码、编译配置到烧录调试的完整链路整体约5.48MB目录结构清晰方便直接打开工程学习或二次开发。已有8435人学习下载尤其适合正在筹备循迹竞速比赛或需要快速上手STM32电机控制与PID调参的开发者是一份可直接运行、便于拆解对照的赛题方案。1. 循迹小车项目面试先弄懂三个被反复追问的底层选择“基于STM32F103ZET6的循迹小车”这个项目出现在简历上频率很高但面试官真正追问的往往不是“你能不能跑通”而是三个底层选择为什么用灰度传感器而不用摄像头为什么舵机转向用位置式PID而电机差速用增量式弯道里速度到底是固定值还是偏差的函数这三个问题能答顺项目分基本就拿到了。本文按硬件选型、PID控制、舵机电机协同、易错点、现场答题五个模块拆解每道真题都给出答题思路适合正在准备嵌入式或自动化方向面试、以及要参加循迹竞速类比赛的人直接对照练。这份笔记更偏向“怎样把项目讲得像自己调出来的”而不是把代码背给面试官听。2. 硬件架构STM32F103ZET6的资源分配与灰度传感器选型面试官问硬件通常不是考你记不记得引脚编号而是想看你怎么做选择、怎么解释选择理由。这一章把资源分配、灰度传感器选型、电源设计三个高频点拆开讲每部分都配一道真题。2.1 资源分配引脚、定时器与中断怎么安排才能答得清STM32F103ZET6 有 144 个引脚、多个定时器和丰富的中断资源做循迹小车时资源其实是过剩的正因为过剩面试官才会问“你怎么分配”。回答这类问题核心是讲出原则传感器读值优先用外部中断或输入捕获PWM 输出优先用定时器通道而不是软件模拟重要状态量用 DMA 或直接寄存器读取避免阻塞主循环。常见分配方案是定时器 TIM2 或 TIM3 输出舵机 PWMTIM4 输出电机 PWM灰度传感器接到普通 GPIO 或 ADC 通道编码器如果有接 TIM1 的编码器模式。这样安排的好处是舵机和电机各自占用独立的定时器通道互不干扰传感器读取不占用 PWM 输出资源方便在中断里快速采集。真题一“为什么不用软件延时产生 PWM而要用定时器”答题思路是软件延时会产生阻塞延时期间无法响应传感器中断小车在弯道里每隔几毫秒就要读一次灰度延时一长就会丢线定时器靠硬件翻转输出CPU 只需要改比较寄存器占空比更新既精准又不阻塞主逻辑。面试官想听的其实是“你理解 PWM 输出的实时性要求”。2.2 灰度传感器数字阈值与模拟ADC两条路线怎么选灰度传感器是循迹小车的核心输入两条技术路线各有适用场景面试几乎必问。第一条是数字型灰度传感器内部带电压比较器输出只有 0 和 1阈值由电位器调好第二条是模拟型灰度传感器输出是随反光强度变化的电压值需要 STM32F103ZET6 的 ADC 采集后软件判阈值。数字型的优势是简单、抗干扰强适合赛道底色和黑线反差很大的标准场地模拟型的优势是能读到灰度梯度适合有浅色辅助线、坡道阴影或光线变化明显的场地。回答时别只说“我用了数字型”而要补一句“我用 ADC 测过黑线和白色底板的电压差发现大约在 0.6V 左右于是把阈值定在中间值这样光线变化时也不容易误判”。这句话一出来面试官就知道你不只是会接传感器。真题二“如果赛道换了一条浅蓝色跑道你的小车还能跑吗”答题思路分两层硬件层说明模拟型传感器读取的是反射电压差浅蓝色和白色底板的灰度差可能变小需要重新标定阈值软件层说明可以把阈值改成动态阈值——取最近 N 次采样最大值和最小值的中间值作为判断线避免手动调电位器。这个答案既展示了硬件理解又展示了软件处理能力。2.3 电源与布线掉压是循迹小车翻车的第一原因做循迹小车最容易翻车的不是代码而是电源。舵机启动瞬间电流可达 1A 以上如果单片机和舵机共用一个稳压源舵机一打角电源电压瞬间跌落STM32F103ZET6 就会复位现象是“小车一转弯就重启”。这种问题查代码永远查不出来必须先查电源。正确做法是分级供电舵机单独一路电源或者至少在舵机电源线上加大容量电解电容单片机、传感器、电机驱动的地线要单点接地避免大电流在地线上产生压差干扰 ADC 采样。面试回答时强调“我会用示波器量复位瞬间的电源波形”这句话比背一堆理论有用得多。真题三“舵机一打角小车就重启你怎么排查”答题思路必须按顺序说先确认供电——用万用表测舵机动作时的电压跌落再用示波器看复位引脚的波形然后隔离负载——把舵机改为独立电源看是否复现最后才考虑软件——检查是否有看门狗误触发或中断优先级配置问题。顺序反了面试官会觉得你遇到问题只会乱试。3. PID控制位置式与增量式的循迹落地PID 是循迹小车项目里分值最高的考点面试官喜欢从公式问到实现细节再追问“你为什么这么选”。这一章先讲清楚两个基本算法怎么选再给一份可以直接背的代码模板最后落到调参顺序的标准化回答。3.1 位置式PID与增量式PID什么时候选哪个位置式 PID 的输出直接对应目标量比如舵机需要的绝对角度公式里带有一个积分项它会对历史误差累加累加过头就叫积分饱和增量式 PID 输出的是“这一次要比上一次多转多少”不需要累加历史误差只需要保存最近三次误差程序实现更简单天然不会积分饱和。结合循迹小车“舵机加电机”的结构最合理的分工是舵机转向用位置式或 PD因为舵机需要一个绝对打角值误差大时快速打过去误差小时回到中位电机速度用增量式因为速度要平滑变化不能有跳变。面试真题“你用的是位置式还是增量式”别只报一个答案要把这个分工逻辑说完整。这里有个容易混淆的点位置式PID并不一定比增量式好关键在于输出物理含义是否匹配。舵机要的是“角度”所以位置式合适如果硬把位置式输出直接给电机调速小车起步时会猛冲一下因为积分项在启动瞬间会累积一个大值。3.2 循迹PID代码模板舵机打角的实现与参数说明下面这份代码是舵机打角用的位置式 PID面试时能把限幅逻辑讲清楚就超过了大部分只会抄库函数的候选人。// 位置式PID实现用于舵机打角 // 输入当前灰度传感器方向偏差 err 目标值 - 测量值 // 输出舵机PWM脉宽增量单位us float pid_position(float err, float Kp, float Ki, float Kd) { static float integral 0.0f; static float last_err 0.0f; integral err; // 积分限幅防止长时间偏差导致积分饱和 if (integral 200.0f) integral 200.0f; if (integral -200.0f) integral -200.0f; // 微分项只取本次与上次的差未做滤波 float output Kp * err Ki * integral Kd * (err - last_err); last_err err; // 输出限幅防止舵机打死或超出PWM有效范围 if (output 500.0f) output 500.0f; if (output -500.0f) output -500.0f; return output; }这份代码的关键不在公式而在两个限幅。积分限幅控制的是“I 项不能积累到失控”输出限幅控制的是“舵机不能一下打死”。面试官问到这段代码时主动说出“我给积分和输出都加了限幅”这就是加分项。参数含义要能讲清楚Kp 决定转向力度Kp 太小入弯迟钝Kp 太大直道来回抖Ki 用来消除静态残差只在直道上有一点偏移时起作用弯道里 Ki 往往是累赘Kd 提供阻尼抑制过冲但会放大传感器噪声。采样周期在这个项目里默认取 5ms 到 20ms 之间采样太快微分项频繁跳动采样太慢弯道里反应不过来。改参数的方法是先把 Ki、Kd 设为 0只加 Kp调到小车在直道上不抖、弯道能达到最大打角然后加 Kd 消除入弯过冲最后加一点点 Ki 消除直道残差。如果弯道太急导致转向不足优先调大输出限幅而不是盲目加 Kp。3.3 调参顺序从P到I到D的面试回答模板调参过程几乎是必问题“你怎么把小车调到能稳定跑完全程的”很多人的回答是“一点点试”这等于没答。标准回答分三步先说明从 Kp 开始持续加大直到直道出现轻微振荡然后回退 20%再加 Kd 抑制振荡观察入弯是否过冲最后加 Ki并确认直道是否画龙。每一步都要带现象描述比如“Kp 太大时直道会左右画龙”“Kd 太大时高速入弯会抖舵”。还有一个面试官常挖的坑“如果弯道里偏差很大PID 输出直接打到限幅值怎么处理”这时候要答出“输出限幅到 PWM 饱和点等待偏差减小后自然回退”而不能说“放大 Kp 让它更快打过去”因为限幅值已经决定了最大转向速度再加 Kp 也没有用。这里踩坑的人很多答案的关键词是“饱和”和“积分限幅配合”。4. 舵机与电机协同打角、差速与竞速策略循迹竞速项目里舵机和电机从来不是一个独立工作面试官问“怎么跑得快”时考点其实是速度与转向怎么配合。这章讲 PWM 脉宽映射、速度规划方法和竞速时序附带一份可以直接用的速度映射代码。4.1 舵机打角PWM脉宽与转向映射STM32F103ZET6 的定时器输出 PWM 控制舵机标准频率是 50Hz周期 20ms脉宽范围大约 500us 到 2500us其中 1500us 对应中位。映射公式是目标脉宽 舵机中位脉宽 PID输出 × 比例系数。这个系数怎么定用角度实测一遍左打死、中位、右打死分别量脉宽再把 PID 输出的最大值映射到左死点和右死点。面试问“舵机最大打角是多少度”别只回答角度数要补一句“我用限幅把 PID 输出限制在对应脉宽范围内防止超出机械限位导致舵机堵转”。堵转会导致电流飙升轻则掉压复位重则烧舵机说出这个细节说明你真正接过线、调过车。4.2 电机差速控制直道加速、弯道减速怎么配合舵机负责转向电机负责推进两者配合的原则是“转向越急速度越低”。实现方式有两种一种是两轮差速转向适合只用电机转向的小车另一种是舵机转向加电机推进也就是本项目“舵机加电机”的结构转向由舵机完成电机只管给一个合适的速度。面试里说清职责分离很重要舵机转向不会因为电机加减速而改变角度但电机的速度会直接影响入弯稳定性速度太快时舵机打满角度也会因为惯性冲出赛道。所以速度不能是固定值而应该是偏差的函数——偏差大说明正在急弯速度要降下来偏差接近零说明在直道速度升上去。真题四“为什么弯道不保持全速反而是入弯前减速更省时间”答案是弯道里的时间损失主要来自横向打滑和路线偏移全速入弯会导致实际转向半径大于理论半径反而要走更远的路入弯前减速可以让前后轮在更短时间内完成较大的角度变化出弯后提前加速整体时间更短。这个逻辑放到任何竞速类项目都通用。4.3 竞速策略入弯减速、出弯加速的时序安排竞速策略的实现本质是给目标速度建立一个偏差映射表。下面这份代码把“偏差大就慢、偏差小就快”做成了分段映射面试时可复述思路。// 弯道速度规划根据当前偏差大小决定目标速度 // err来自灰度传感器融合方向偏差越大表示偏离越明显 uint16_t speed_map(int16_t err) { if (err 0) err -err; // 取绝对值左右对称 if (err 100) return 1200; // 急弯速度压到最低 if (err 60) return 2000; // 中等弯道中等速度 if (err 30) return 3000; // 缓弯适当降速 return 4000; // 接近直道全速输出 }这份代码背后是一个控制周期统一的概念每个控制周期里先由传感器算出偏差再由 speed_map 得到目标速度然后把速度交给电机 PWM、把偏差交给舵机 PID两个输出同时更新。面试时强调“速度是偏差的函数且与舵机打角在同一次控制循环里计算”就能避开“转向和速度脱节”这个最常见的坑。参数调整方面需要说清楚速度分段阈值 30、60、100 是根据赛道曲率实测出来的不是拍脑袋定的。第一次跑全赛道时发现某处弯道打角接近限幅但速度还是太快就把对应分段阈值调大或降低该段速度直道段全速不够再往上提。坡度、轮胎打滑、电池电量都会影响分段效果所以面试回答时要说“我会留一组参数每次换场地先跑一圈标定”。5. 易错点五个高频失分点与正确应答这一章集中讲面试里最容易失分的点每一条都按照“错在哪、为什么错、怎么答对”展开建议直接背下回答框架。5.1 丢线误判把出界当成正常信号错在哪小车压出赛道时几个灰度传感器全部输出为同一电平算法把这种状态当成“循迹正常”继续沿用上一次的转向输出小车直接冲出赛道。为什么错丢线状态没有单独定义PID 拿到一个不存在的偏差自然给出错误的打角。怎么答对先说“我会把全丢线状态单独处理判定为出界执行回退并减速”再补一句“检测到恢复有效信号后重新进入循迹模式而不是直接给 PID 一个巨大偏差”。丢线处理是循迹项目软件层最常被问的细节之一必须答出“状态机”意识。5.2 积分饱和直道画龙找不到原因错在哪小车入弯后长时间保持同一个方向偏差Ki 项不断累加出弯后偏差已经归零积分值还停在那里舵机继续往一个方向打表现为直道上画龙或走偏。为什么错没有对积分项做限幅或者限幅值设得太大。怎么答对直接说“我给积分加了限幅并规定偏差大于某个阈值时积分不累加”如果更进一步可以答“直道使用 PD 控制入弯才引入小的积分项”。这个解答比“我调小 Ki”高级得多因为面试官听到的是你对积分项局限性的理解。5.3 速度与转向脱节弯道里舵机满了电机还在全速错在哪舵机 PID 和电机调速是两套独立代码弯道里舵机打角到了限幅电机仍然全速输出车由于惯性冲出赛道。为什么错没有把速度设计成偏差的函数速度策略没有和控制周期绑定。怎么答对先描述现象“弯道内侧轮离中心线越来越远”再给出解法“我在主循环里先算偏差再映射速度最后同时输出舵机脉宽和电机 PWM”最后补一句“实际测试中急弯速度压到直道的一半过弯就稳定了”。5.4 一打角就复位问题出在供电而不是代码错在哪舵机启动瞬间电流拉低电源电压单片机掉电复位现象是每次转弯小车就重启很多人以为是代码死循环或中断冲突查了半天毫无结果。为什么错电源系统没有按负载隔离舵机电流冲击直接传导到单片机电源轨。怎么答对回答顺序必须是“先用示波器测断电瞬间的电源波形再验证是否为负载耦合”如果波形显示跌落幅度超过 10%就是供电问题解法是舵机独立供电或加大电解电容。面试官不喜欢听“可能是电容问题”喜欢听“我通过测量定位到是电源跌落导致的复位”。5.5 只背公式不背选型依据“为什么用这个算法”直接哑火错在哪能完整写出 PID 公式也能说出一堆参数但被问“为什么舵机用位置式、电机用增量式”时当场卡住。为什么错把算法当作调用接口来背没有理解输出物理含义。怎么答对把这句话背熟——“舵机需要的输出是绝对角度所以用位置式电机需要的是平滑的速度变化量所以用增量式增量式不累加历史误差天然没有积分饱和问题”。先答原理再答实现最后补一个实际现象比如“我把增量式输出直接累加到 PWM 上小车提速明显更顺”。这个回答框架适用于所有算法类问题。6. 现场答题技巧把项目讲成调参闭环面试官让你“介绍一下你的循迹小车”时最容易犯的错是上来就讲代码结构讲完发现对方完全不知道你想解决什么问题。正确做法是讲一个闭环系统由什么组成 → 最难的问题是什么 → 我选了哪种方案 → 我怎么调出来的 → 结果怎么样。五句话之内把这条线走完面试官就有兴趣追问细节了。我这里给一套直接能用的开场框架你可以按自己的实际情况替换具体数值系统由 STM32F103ZET6、五路灰度传感器、舵机和电机驱动组成最难的问题是弯道里转向和速度配合不好高速入弯总是冲出赛道我选灰度传感器加模拟 ADC 采集舵机用位置式 PID电机用增量式速度规划调参时先只加 Kp 把直道跑稳再加 Kd 消过冲最后把速度做成偏差的分段函数最终高速入弯不再偏离中心线全程完赛率从不到 50% 提升到稳定跑完全程。这段话大约 30 秒信息密度够而且每一步都暗示“这是我实际调出来的”。讲完框架后面试官通常会在一个点上深挖。常见追问是“你刚才说速度是偏差的函数具体怎么实现”这时候把你 speed_map 的思路讲一遍再补一个翻车案例。我自己的教训是有一次为了追求直道速度把低速阈值调得特别小结果入弯后速度还没降下来舵机就已经打满车尾直接甩出去。后来我把速度映射改成两段式偏差超过 60 先压 40% 速度过弯后偏差回落到 20 以下再恢复全速跑起来反而更快了。从那以后我每次调竞速策略都强制先跑一遍全赛道记录每个弯的偏差峰值再回头改速度映射而不是靠感觉调参数。最后提醒一点回答任何调参问题时都要把“我先量化现象、再改参数、再验证效果”这个顺序说出来哪怕现象很简陋。面试官判断真做过的方法从来不是参数背得多熟而是你说出来的每个结论有没有对应的现场现象支撑。希望这篇笔记能帮你在面试把循迹小车项目讲成自己真正跑出来的东西而不是背下来的代码片段。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?