做 Arduino 巡线机器人这个题目我前后折腾过七八台车从最早用三路开关量传感器、L298N 驱动、PID 写成纯 P 调节的那种“能跑但不稳”的版本到后来给竞赛队做的带编码器、能跑 3m/s 的版本中间踩的坑足够写一本小册子。很多人以为巡线的难点在 PID 算法本身实际上真正决定成败的是硬件层的几个基础决策和调试环节的信息可见性传感器间距差 3mm赛道上的表现能差一个档次PID 参数没调好还能慢慢试出来但电源设计有缺陷车跑起来会随机复位调参根本无从谈起。这篇内容把 Arduino 巡线机器人从硬件选型到 PID 算法调试的完整链路拆开讲包含参数计算过程、代码落地的关键细节、以及实际赛道上常见的十几种故障的排查思路。不管你是刚买回一套套件准备做课程作业的新手还是已经能跑起来但速度上不去想突破瓶颈的老手下面这些内容都能直接拿去用。1. 先想清楚巡线机器人的核心矛盾在哪1.1 巡线本质上是一个位置闭环问题把巡线机器人剥开看它的核心只有一个变量车身相对于黑线的横向偏移量。传感器负责把这个几何量转换成电信号控制器负责算出“该往左打多少方向”执行机构负责把方向变成左右轮的转速差。整条链路上任何一环有延迟、有噪声、有非线性最终都会体现为车在赛道上画龙或者冲出弯道。理解这一点特别重要因为它决定了你做设计时的优先级排序。很多新手的第一反应是“我要把 PID 算法写得漂亮一点”于是花大量时间去研究微分先行、不完全微分、抗积分饱和这些理论结果车还是抖。原因往往在于传感器间距 20mm 配 30mm 宽的赛道线中间永远有一段“两路都不压线”的盲区误差量在正负之间来回跳变再好的 PID 也治不了这种硬件层的信息丢失。我用一个生活化的类比说明这件事想象你蒙着眼睛在一条窄路上走靠脚尖感知路面边缘。如果你的脚特别大一脚踩过去直接跨过了路沿你根本不知道自己是偏左还是偏右如果你的脚特别小感受很灵敏但每走一步都要重新确认反应就慢。传感器间距就是这个“脚的大小”它必须和赛道线宽匹配这是设计的第一性原则任何算法都替代不了。所以一个合理的开发顺序应该是先确定车要跑什么样的赛道由赛道线宽反推传感器间距和数量再确定车速和电机规格然后才是控制算法。反过来做先写算法再配硬件大概率要推倒重来。1.2 三条技术路线的取舍开关量、模拟量、摄像头巡线传感器在市面上主要有三大类选错方向会让后续开发效率差好几倍。第一类是开关量传感器典型代表是 TCRT5000 模块输出高低电平一位数字量。它的优点是便宜、接线简单、单片机直接读数字口不需要 ADC。缺点是阈值靠板载电位器手动调场地光线一变就失效而且只能告诉你“这一路在线上/不在线上”没有程度信息。如果你做的是课程作业、赛道固定、室内光照稳定它完全够用但如果你想做速度它的信息量太少了。第二类是模拟量灰度传感器通常是 5 路、7 路或 8 路集成模组每一路输出一个模拟电压反映该点反射光强。它比开关量多了一个关键能力可以做归一化可以算出亚像素级别的偏差量。用插值法可以做到比物理间距更精细的分辨率这是提速的基础。第三类是摄像头方案用线阵 CCD 或者低分辨率摄像头信息量最大前瞻距离远适合高速循迹。代价是需要处理图像对主控算力有要求调试门槛明显更高。我的建议很明确第一次做选 5 路模拟量灰度模组能跑通完整链路又不会太难要打比赛冲速度上 7 路或 8 路模拟量配合加权法算偏差摄像头方案放在最后等你把前两种玩明白了再说。2. 硬件选型每一分钱该花在哪个环节2.1 主控板UNO 够用但要知道它的边界主控选型的核心约束不是“性能越强越好”而是“资源是否匹配需求”。Arduino UNO 用的是 8 位 AVR主频 16MHz32KB Flash2KB SRAM10 位 ADC6 路 PWM 输出。对于巡线这个任务它其实完全够用——模拟量读取加 PID 运算加 PWM 输出一个控制周期的工作量在几百微秒量级2ms 的控制周期绰绰有余。但要知道它的几个硬边界。第一是 2KB SRAM这意味着你不能开大数组做图像缓冲浮点运算也要省着用一个 float 占 4 字节几个数组下去再加上串口缓冲就紧张了。第二是 10 位 ADC理论分辨率 1024 级实际有效位数会掉到 8 位左右做归一化的时候要注意噪声。第三是 ADC 采样保持电路的输入阻抗特性如果你用一个大的分压电阻网络采样会不准建议传感器输出阻抗控制在 10kΩ 以内。如果要升级Nano 是同芯片的小体积版本做小车更合适Mega2560 引脚多适合接一堆外设的复杂版本ESP32 是我现在更推荐的方向12 位 ADC、双核、自带蓝牙方便在线调参、主频高到可以跑浮点运算毫无压力。用 ESP32 唯一的麻烦是 3.3V 逻辑电平接 5V 的传感器模块要注意电平匹配和 ADC 输入范围别把引脚喂烧了。注意ESP32 的 ADC2 在开启无线功能时不可用接传感器时优先用 ADC1 对应的引脚这个坑我在第一次用的时候卡了整整一个下午。2.2 传感器间距与安装高度两个被严重低估的参数传感器间距是整套硬件设计里最值得反复推敲的参数。假设你用的是 20mm 宽的电工胶带做赛道线那么相邻传感器的间距应该略小于线宽让车在任意偏移位置下都至少有一到两路压在线附近。具体算一下如果间距 15mm5 路传感器总跨度 60mm中心线到最外一路 30mm那么当车偏移量在 ±30mm 内都能检测到线这个范围足够用了。如果间距做到 25mm5 路总跨度 100mm虽然检测范围大但中间会出现“空隙”线正好落在两个传感器之间时两个读数都在中间值加权算出来的位置是准的可一旦噪声让其中一个掉下去误差就跳变。我实际测试的经验值是传感器间距取线宽的 0.6 到 0.75 倍比较合适20mm 线宽对应 12mm 到 15mm 间距。7 路模组跨度在 72mm 到 90mm 之间检测范围够宽同时保持足够的分辨率。安装高度同样关键。红外反射式传感器的最佳检测距离通常标称 2mm 到 15mm实际用在 8mm 到 12mm 之间最稳。装太低容易剐蹭地面尤其是赛道有接缝的时候装太高则发射管的光斑扩散反射回来的信号弱黑白对比度变差归一化之后动态范围不够。我一般先用一块活动支架把传感器固定在 10mm 高度跑起来之后再微调同时给传感器加一个遮光罩避免环境光直射和相邻传感器的串扰。2.3 电机与驱动差速转向的物理基础巡线车的转向完全靠左右轮转速差实现所以电机的一致性直接决定了车的直线性。廉价的 TT 马达1:48 减速比空载 200rpm 左右的问题是同一批次内两个电机的转速差异可能有 10% 甚至更多导致你不给指令它自己就跑偏。这个偏差在代码里靠 I 项或者一个固定的偏置量来补偿但补偿是静态的负载变化后又会失配。我推荐的方案是带编码器的减速电机用编码器测速做速度闭环把左右轮的实际转速反馈到控制回路。这样一来电机个体差异、电池电压跌落、地面摩擦变化这些扰动都会被速度环吸收掉外层的巡线环只需要专心处理位置偏差。这是从“能跑”到“跑得稳”的关键一步。驱动选型上L298N 是老牌方案但它的问题是内部达林顿管压降大标称 2V 左右实际带载时发热严重效率损失明显。TB6612FNG 是更现代的选择MOSFET 输出压降小持续电流 1.2A支持 100kHz PWM封装小到可以直接焊在转接板上。我做过对比测试同样的 7.4V 电池、同样的电机L298N 方案在满载时电机两端电压只有 5.4V 左右TB6612 能到 6.8V转速差出 20% 以上这直接决定了你最高能跑多快。还有一个容易忽略的点是 PWM 频率。Arduino 默认的 PWM 频率在引脚 5、6 上约 980Hz在引脚 9、10 上约 490Hz。这个频率落在人耳可听范围内跑起来电机会有啸叫更麻烦的是低速时每个 PWM 周期只有几十微秒的导通时间电机的电流还没建立起来就被切断了表现为低速启动困难、抖动明显。解决办法是通过修改定时器预分频寄存器把 PWM 频率提到 4kHz 以上或者干脆用支持高频 PWM 的驱动芯片。改定时器会影响到 millis() 和 delay() 的时基改完要重新核对时间函数这个坑我踩过做完之后串口打印的时间全乱了。2.4 电源设计随机复位的根源电源是巡线车最容易出问题、又最难排查的一环。典型的故障现象是车放在地上静止时一切正常一给电机指令就重启或者跑过弯道时随机复位。原因几乎都是电机启动瞬间的大电流把电池电压拉低导致主控的稳压器输出跌出工作范围触发掉电复位。计算一下就能明白两个 TT 马达堵转电流各 1.5A 左右启动瞬间就是 3A2S 锂电池的内阻加保护板内阻按 150mΩ 算瞬态压降就是 0.45V从 7.4V 掉到 6.95V看起来还好。但如果你用的是 9V 层叠电池内阻几百毫欧压降能到 2V 以上主控必挂。所以电源第一原则不要用 9V 层叠电池给电机供电那是课程作业里最常见的错误。实用的方案是 2S 锂电池或两节 18650 串联供电电机直接吃 7.4V主控通过降压模块或 LDO取 5V。关键是两点一是主控的供电和电机供电在走线上要分开从电池端子分别引出两路避免电机大电流在共用走线上产生压降干扰主控二是电机电源端并一个 470μF 到 1000μF 的电解电容再并一个 0.1μF 陶瓷电容前者吸收低频浪涌后者滤高频毛刺。这一套加上去复位问题基本消失。3. 传感器数据处理从原始 ADC 到可信的偏差值3.1 归一化让参数在不同场地复用模拟量传感器直接读出来的原始值没有通用意义。同一辆车在白色地板上读 800在黑线上读 200换到深色地毯上白底可能只有 500黑线 150。如果你把阈值写死在代码里换个场地就要重调这在比赛现场是非常危险的。归一化的做法是在标定阶段把车分别放在纯白区域和纯黑区域记录每一路传感器的最大值和最小值然后按公式换算。norm[i] (raw[i] - white[i]) * 1000 / (white[i] - black[i])换算后每一路的输出在 0 到 1000 之间0 表示完全在黑线上1000 表示完全在白色背景上。这样做的好处是参数和场地的绝对亮度解耦Kp、Kd 这些系数调好之后换场地基本不用动。标定的实操细节让车在赛道上缓慢走一圈同时通过串口把每一路的原始值打印出来取每一路的最大值和最小值作为标定值。要注意避免标定值被异常值污染比如传感器边缘扫过反光胶带时读到的极端值所以标定的时候最好做一次排序取 5% 和 95% 分位数而不是简单的 max/min。3.2 加权法算偏差把离散读数变成连续量有了归一化数据下一步是把它变成一个单一的偏差量。最常用的是加权平均法也叫质心法。假设 5 路传感器编号为 0 到 4中心是 2那么权重就是 -2、-1、0、1、2。weighted_sum Σ ( (2 - i) * norm[i] ) // 或者用 (1 - norm[i]) 表示黑度 weight_sum Σ norm[i] error weighted_sum / weight_sum这里有一个关键点用白度还是用黑度做权重。如果传感器在黑线上读数小归一化后接近 0在白底读数大接近 1000那么我们真正关心的是“哪一路最黑”所以权重应该用黑度也就是 1000 减去归一化值。这样算出来的误差量符号表示偏移方向绝对值表示偏移程度物理意义清晰。算出来的 error 范围大约在 -2 到 2 之间。这个量纲直接决定了后面的 PID 系数大小。如果你用 7 路传感器权重变成 -3 到 3同样的控制效果下 Kp 的数值会小一些。所以网上抄来的 PID 参数一定要结合自己的误差量纲来看直接照搬大概率不对。这里还有一个技巧用插值可以提高分辨率。5 路传感器物理间距 15mm但通过加权计算实际能分辨的偏移量远小于 15mm因为相邻两路的读数比例是连续变化的。这就是模拟量方案比开关量方案精细的根本原因。3.3 特殊赛道元素的识别与处理普通弯道靠 PID 就能过但赛道上的十字路口、断线、直角弯、终点线这些元素必须单独处理否则车会在十字路口直接冲出去。判断思路是利用误差量的两个特征有效传感器数量和总黑度。正常循迹时总黑度大约对应一到两路压线如果所有路都检测到黑总黑度达到满量程那就是横向的十字路口或终点线如果所有路都是白总黑度为 0那就是断线。处理逻辑全黑且持续时间超过设定阈值判定为十字路口进入直行模式锁定当前舵量或直接给左右轮相同速度持续固定时间或固定距离后恢复循迹。全白先做“记忆循迹”保持上一次的转向方向继续走一段同时降低速度如果在设定时间内容错仍未恢复就原地转向搜索。单侧多路持续黑、另一侧全白可能是直角弯需要加大转向力度甚至允许原地转向。提示十字路口的直行延时不要用固定毫秒数因为速度一变延时对应的距离就变了。用编码器累计脉冲或者用固定时间乘以当前速度估算距离换速度时不用重新调参。4. PID 算法落地从数学公式到定时器中断4.1 位置式还是增量式先看你的执行机构PID 有两种常见形式位置式和增量式。位置式直接算出控制量的绝对值增量式算的是本次比上次应该增加多少。巡线场景下我更推荐位置式因为执行机构是 PWM 占空比本身就是一个绝对量位置式算出来直接映射到 PWM逻辑清晰。增量式的好处是不需要累加误差、天然抗积分饱和、切换手动自动时无扰但它的输出需要做累加一旦中间有一步算错误差会一直累积下去现场的“车越跑越歪”很多时候就是增量式累加器溢出或初始化不当导致的。位置式的公式error 目标位置 - 当前位置 // 巡线中目标位置恒为 0 P Kp * error I Ki * (I_prev error * dt) D Kd * (error - error_prev) / dt output P I D因为采样周期 dt 固定实际写代码时可以把 dt 吸收进系数里变成纯离散形式output Kp * error Ki_sum Kd * (error - error_prev) Ki_sum Ki * error这样每一步只有两次乘法和几次加法AVR 上跑起来毫无压力。4.2 采样周期这个参数比 Kp 更容易出错采样周期是我见过最多人忽略的参数。很多人把 PID 运算直接丢在 loop() 里读传感器、算 PID、写 PWM然后循环。问题是 loop 的执行时间不固定串口打印会拖慢它中断服务程序会插队传感器读取如果用了带延时的库函数更是灾难。结果就是实际的 dt 在 2ms 到 20ms 之间随机波动而你代码里假设它是固定的微分项直接炸掉。正确的做法是用定时器中断或者 millis() 做严格的时间片调度。我一般用 5ms 一个控制周期具体选择依据是车的最高速度 2m/s传感器前瞻 30mm那么通过前瞻距离的时间是 15ms控制周期必须明显小于这个值才能及时响应5ms 对应 3 次控制够用。如果车速更高控制周期要相应缩短到 2ms。用 millis() 实现固定周期的骨架大概是这样unsigned long last_time 0; const unsigned int PERIOD_MS 5; void loop() { unsigned long now millis(); if (now - last_time PERIOD_MS) { last_time PERIOD_MS; // 注意不是 last_time now int error readLineError(); int output computePID(error); setMotor(output); } }注意last_time PERIOD_MS这一行而不是last_time now。区别在于前者能自动补偿处理耗时长期运行不会累积漂移后者会把每次的执行时间误差累积起来跑几分钟之后周期就完全走样了。4.3 输出限幅、死区补偿与抗积分饱和PID 算出来的 output 是转向量需要叠加到一个基础速度上才能变成左右轮的 PWMleft_pwm base_speed output right_pwm base_speed - output这里有几个必须处理的边界情况。输出限幅output 的绝对值不能超过 base_speed否则一边轮子会变成负值出现“倒转”车会原地打转。正确做法是先对 output 做限幅限幅范围取 base_speed 的一定比例比如 0.9 倍。死区补偿直流电机有启动死区PWM 低于某个值实测 TT 马达大约 30 到 50取决于负载和电池电压电机根本不转。当 base_speed 较小、output 又让某一侧 PWM 掉到死区以下时那个轮子会停转车的转向特性和你算的完全不一样表现为低速循迹时“一顿一顿”。解决办法是给 PWM 输出加一个最小绝对值映射非零输出统一抬到死区以上或者用查表补偿。抗积分饱和积分项在车长时间偏离中心时会一直累加等车回到中心后积分项还很大导致过冲。标准的处理是积分分离加限幅当误差绝对值超过阈值时停止积分同时给积分项一个上下限比如限制在 output 最大值的 0.3 倍以内。巡线场景下I 项其实经常可以不用。因为理想情况下赛道左右对称机械误差可以通过一个固定的偏置量补偿掉比积分项更可控。我大部分作品里 Ki 都是 0只在电机差异特别大的廉价套件上才开一点取值大概是 Kp 的 1/50 到 1/100。4.4 完整控制代码的结构把上面几块拼起来一个可用的控制循环大概长这样const int BASE_SPEED 130; float Kp 32.0, Kd 180.0, Ki 0.0; float error_prev 0, integral 0; const int DEAD_ZONE 40; int computePID(float error) { float P Kp * error; integral Ki * error; integral constrain(integral, -40, 40); float D Kd * (error - error_prev); error_prev error; float out P D integral; return constrain((int)out, -110, 110); } void setMotor(int turn) { int left BASE_SPEED turn; int right BASE_SPEED - turn; left compensate(left); right compensate(right); drive(left, right); } int compensate(int pwm) { if (pwm 0 pwm DEAD_ZONE) return DEAD_ZONE; if (pwm 0 pwm -DEAD_ZONE) return -DEAD_ZONE; return constrain(pwm, -255, 255); }这一套跑起来就是最小可用版本。注意 error 的量纲是 -2 到 25 路所以 Kp 取 32输出最大约 64配合 base_speed 130 就能在急弯上实现明显的差速。5. 调参实录一套可复现的整定流程5.1 先调机械再调参数在动 PID 参数之前必须先确保机械状态是好的否则你调出来的参数是在补偿机械缺陷换台车就失效。检查清单包括两个轮子直径一致、轮胎没有偏心、车轴平行、重心在几何中心略偏后、传感器板刚性固定不晃动。一个特别容易被忽略的点是传感器板的固定方式。用扎带或双面胶固定的传感器板跑起来会有微小振动采样值跟着抖表现为 PID 微分项输出尖刺。我一开始不信后来换了一块 2mm 亚克力板用四个螺丝固定抖动立刻小了一半。这个改进零成本收益比调两天参数还大。还有一个基础检查是做“直线测试”给左右轮相同的 PWM在空地上跑 3 米看车的偏移量。偏移量超过 30cm 说明电机差异太大要么换电机要么在代码里加补偿系数。这个测试能帮你判断后面遇到的问题是机械的还是算法的。5.2 分步整定P、D、I 的顺序不能乱我用的整定流程是从 Ziegler-Nichols 的临界振荡法简化来的不追求理论最优追求快速可复现。第一步Ki 和 Kd 全部置 0只留 Kp。把车放在赛道上Kp 从 5 开始逐步增大每次加 20% 左右观察直线段。Kp 太小的表现是车在直道上懒洋洋地慢慢往线中间靠过弯时贴不住线切内道或者冲出去。Kp 增大的过程中会到达一个点车开始在直道上左右摆动这叫临界振荡记录下此时的 Kp 记为 Ku摆动的周期记为 Tu。第二步按经验公式给初值纯 PD 控制取 Kp 0.6 × Ku 到 0.8 × KuKd 取 Kp × Tu / 8 到 Kp × Tu / 10。这个初值不一定最优但能让你直接跳到“基本能跑”的状态省掉大量瞎试的时间。第三步精调。先小幅增加 Kd观察直道上的摆动是否收敛更快。Kd 太小的表现是过弯后车头回正慢来回摆两次才稳定Kd 太大的表现是直道上高频抖动像筛糠一样同时电机发热明显因为微分项在放大噪声。Kd 合适的标志是车过弯时有一个干脆的“切入”动作切完立刻稳住不拖泥带水。第四步只有当车在长直道上持续向一侧偏、或者左右弯表现明显不对称时才引入 Ki。Ki 从 Kp 的 1/100 开始每次翻倍直到偏移在 2 秒内被纠正。Ki 一旦过大车会在直道上出现周期很长的缓慢摆动比 P 项的摆动频率低但幅度大非常难看。阶段参数状态观察什么典型现象下一步粗调 PKiKd0直道收敛速度P 小则懒散P 大则左右摆找到临界振荡 Kp加 DKp0.7Ku过弯后回正次数D 小回正慢D 大高频抖D 增到刚好不抖加 IKi 从 0 起长直道是否单侧偏偏则加不偏则不加加到偏移 2 秒消提速复核三参数固定最高速下过急弯冲出去说明 P/D 不够回退速度或重调5.3 让参数“看得见”在线调参与波形观察调参效率的高低取决于你能不能实时看到 error 曲线的形状。我强烈建议在调试阶段把 error 值通过串口发出来用串口绘图器看波形。一个调好的系统error 曲线在直道上应该是一条贴着零的小幅波动线过弯时是一个平滑的峰过弯后迅速回落没有二次振荡。串口打印本身会占用时间5ms 周期打印十几个字符在 115200 波特率下大约耗时 1ms还在可接受范围。如果控制周期更短就要改成每 N 个周期打印一次避免影响实时性。更进一步的做法是在线调参。三种常见方案一是接三个电位器到模拟口分别映射 Kp、Kd、base_speed比赛现场直接拧电位器改参数最土但最可靠二是接蓝牙模块手机发字符串指令P32.5、D180解析后更新参数适合调试阶段三是接一个 OLED 加两个按键做菜单适合成品。我在比赛现场最信任的还是电位器方案因为它不依赖任何无线链路不会在关键时刻连不上。经验做法是电位器映射到参数的一个合理区间比如 Kp 映射到 10 到 60转动的时候串口同步打印当前值调好之后记下来写死到代码里。6. 常见问题与排查技巧实录6.1 直道画龙与过弯冲出两个方向的故障直道画龙蛇形走位是最常见的投诉。原因按概率排序Kp 过大、Kd 不足、采样周期抖动、传感器间距过大导致误差跳变、机械振动。排查顺序建议从采样周期开始先确认 loop 的实际执行周期是否稳定用示波器量一个调试引脚的高低电平翻转间隔或者在中断里翻转引脚看周期。如果周期稳定再动参数。过弯冲出赛道的原因通常是速度过高而前瞻不足、Kp 不足导致转向不够、传感器检测范围太窄在急弯时丢线。这里有个反直觉的点很多时候不是 PID 参数不够猛而是传感器根本“看不见”弯道。5 路传感器总跨度 60mm在半径 100mm 的急弯上线很快就会移出检测范围。解决办法是加大传感器跨度换 7 路或 8 路或者过弯时主动降速用速度换检测窗口。降速的实现可以用一个简单的规则当 |error| 超过阈值时把 base_speed 按比例降低。这个逻辑在代码里加三行就够效果比调半天 PID 明显。int speed BASE_SPEED; if (abs(error) 1.2) speed BASE_SPEED * 0.7; if (abs(error) 1.8) speed BASE_SPEED * 0.5;6.2 低速抖动与启动困难低速时车一顿一顿、走不直八成是 PWM 死区问题。前面提过直流电机有一个最小启动占空比低于它电机不转或者转得很勉强。当 base_speed 只有 80而 output 让一侧变成 40 时这一侧可能完全停转车就往一边偏PID 又猛拉回来形成低频抖动。诊断方法把车架空逐个给固定 PWM 值从 0 开始每 5 递增记录电机开始稳定转动的阈值。两个轮子的阈值可能不一样要分别测。然后在代码里做补偿任何非零的 PWM 输出绝对值都不低于对应的启动阈值。另一个低速抖动来源是电机减速箱的齿轮间隙。TT 马达的塑料齿轮组间隙能达到好几度正反转切换时有一段“空行程”PID 输出在零点附近反复穿越时就表现为咔哒咔哒的抖动。这个没法从软件根治只能通过设置一个小的输出死区来缓解当 |output| 小于某个值时直接输出 0让车滑行而不做微调。6.3 电源、干扰与复位类问题车跑起来随机复位按这个顺序排查先量电池电压跑动过程中用万用表或者分压后接 ADC 监测如果跌到主控稳压器输入下限以下就要改电源方案再检查所有地线是否单点汇聚电机地和信号地不能串成一条细线然后看电机端有没有加续流电容没有的话电机换向时产生的尖峰会通过电源线窜进主控最后检查复位引脚有没有被拉低有些扩展板会把复位信号引到外部走线太近容易耦合干扰。传感器读数偶发跳变特别是车经过特定位置时突然全黑或全白通常是反光或者环境光干扰。排查方法是用手机摄像头对着传感器发射管看能看到紫红色的光点如果光点在白色地面上的反射面积很大说明安装高度太低。另外传感器之间会互相串扰相邻两路的发射光打到地面后反射到隔壁的接收管里解决办法是给每个传感器加一个黑色热缩管做遮光筒或者分时点亮分时点亮需要更复杂的驱动电路一般不值得。现象最可能原因快速验证处理直道蛇形Kp 过大 / Kd 不足减小 Kp 看是否改善重调参数过弯冲出速度高 / 检测范围窄降速跑是否正常降速或换宽传感器低速一顿一顿PWM 死区 / 齿轮间隙架空测启动阈值加死区补偿随机复位电源压降 / 干扰监测电池电压分路供电加电容读数突跳环境光 / 串扰遮光后复测加遮光罩调高度十字路口冲出未做特殊元素识别观察是否全黑加全黑判定直行单侧持续偏电机差异 / 传感器不对称直线测试加偏置或速度环参数换场地失效未归一化看原始值范围做黑白标定我个人在实际操作中的体会是巡线车这个项目最像真实工程的地方在于它的问题从来不是单点的而是层层嵌套的。你以为是 PID 参数没调好其实是传感器间距不对你以为是传感器不行其实是电源在抖你以为是电源问题其实是地线走了同一条细线。所以真正高效的做法不是“遇到问题改参数”而是建立一套可观测的调试手段让 error 曲线看得见让采样周期量得准让电源电压监测得到。这套东西搭起来要多花两三个小时但能省掉后面几十个小时的盲试。最后分享一个提速阶段的小技巧当参数调到极限、车在直道上已经很稳但过弯还是会甩出去时别急着继续加大 Kp先试试把传感器往前挪 10mm。前瞻距离增加带来的过弯改善往往比调一周参数都明显代价只是需要重新标定一下安装支架。