☰
巡线小车实战:从传感器标定到PID调参全记录
2026/10/24 21:27:58 网站建设 项目流程

巡线小车大概是嵌入式入门里最容易让人产生“我好像会了”错觉的项目。硬件上确实不复杂:一块 STM32 或者 Arduino 主控、几个灰度传感器、一个电机驱动、两个电机加一个底盘,通电之后基本都能走。但真到赛道上,能把车开起来不叫巡线,能稳定跟住一条黑线、连续通过直角弯和 S 弯、不抖不冲不丢线,才叫巡线。这篇文章就是一份巡线小车从硬件选型、传感器标定、差速控制到 PID 调参的实测记录,适合正在做课程设计、准备竞赛,或者刚接触开源小车项目的读者。我踩过的坑基本都写进去了,照着走一遍,能少走不少弯路。

1. 巡线小车到底在做什么,难点在哪

1.1 一个小项目,三条链路

巡线,说白了就是让小车沿地面上的固定色带自主行驶。常见场景是在白色地面贴黑色胶带,或者直接打印黑线赛道。整个运行过程可以拆成三步:传感器检测线的位置,主控根据偏差算左右轮速度,电机驱动执行。每一步都不复杂,但串在一起就有很多现实问题。

第一个问题是实时性。小车跑起来以后,传感器读数每秒变化几十次甚至上百次,如果主控处理速度太慢,或者代码里加了不必要的延时,车就会延迟反应,过弯时直接冲出去。

第二个问题是稳定性。同样一段直道,不同光照条件下传感器读数会变;同一辆车,电池电压下降后电机转速也会变。能不能在各种条件变化时仍然稳稳定贴线,才是巡线项目的核心难点。

第三个问题是可重复性。调好的 PID 参数换个场地可能就不灵了。这个不是玄学,多半是因为赛道反光、线宽、场地平整度不一样。

所以,巡线项目真正值得投入的时间,不在硬件焊接,而在传感器标定、控制参数和调试流程。这也是我写这篇实录的原因。

1.2 开源项目能直接拿走什么,拿不走什么

搜索开源小车项目时会发现,GitHub 和 Gitee 上有不少巡线小车仓库,常见的有基于 STM32 的、基于 Arduino 的,也有基于 OpenMV 视觉方案的。这些项目一般会提供原理图、PCB 源文件、主控代码和调试说明。

我的建议是:把这些开源项目当成参考资料,不要当成成品。原因很直接:

  • 引脚定义不一定和你的板子一致,拿回来要重新映射。
  • 传感器阈值是根据原作者场地标定的,换个地板就不准。
  • 电机型号和电池电压不同,PID 参数基本要重新调。
  • 不少仓库文档不全,只有源码,需要自己补环境。

比较合理的流程是:先找一个资料相对完整、和你硬件接近的项目,把代码读一遍,跑通一次,然后在自己板子上重写底层驱动,最后再调参数。这样既保留了开源项目的思路,又不会被动接受一套不适合自己的配置。

2. 硬件选型:主控、驱动、传感器怎么搭配

2.1 主控选型,先看你自己熟悉什么

巡线小车的主控选择,常见就三类:STM32、Arduino 系列和 ESP32。各有各的适用场景。

STM32F103 系列在竞赛和课程设计中非常常见,资料多,外设丰富,ADC、定时器 PWM、串口都有,跑 5 路或者 8 路灰度传感器完全够用。缺点是入门门槛稍高,需要熟悉 HAL 库或标准库,配置外设要花时间。

Arduino 系列上手快,IO 操作简单,适合第一次接触硬件的人。如果你之前没写过单片机,用 Arduino 先跑通巡线逻辑,再去迁移到 STM32,会更顺。

ESP32 的优势是自带 WiFi 蓝牙,适合后续做无线调试、上位机交互,但纯巡线任务里这些功能不是必须的,反而会增加复杂度。

我的建议很朴素:比赛和课程设计选 STM32 的居多,资料最好找;新手自学选 Arduino;想做远程监控再考虑 ESP32。没有绝对的最好,关键是你能把环境配明白。

2.2 电机驱动:不要只看“能转”

电机驱动模块常见的几种,我列一个对比。

驱动模块典型输出能力压降适合场景特点
L298N大电流较高入门、大功率电机简单便宜,但发热明显
TB6612中电流低小型两驱四驱车模效率高,竞赛常用
DRV8833小电流低微型小车体积小,适合轻量底盘

选驱动要看电机额定电流和电池电压。驱动输出能力不够,电机会无力;驱动压降太大,电池电压会被吃掉,满电和低电时车速差别明显。

另外要注意,电机电源和主控电源尽量分开。电机启动瞬间电流波动很大,如果和单片机共用一个稳压电路,很容易导致主控复位。常见做法是电池直接给驱动供电,驱动模块的 5V 输出再单独给主控,或者在主控侧加稳压和滤波。

2.3 传感器方案:灰度阵列还是摄像头

巡线传感器主流有两种:红外反射式灰度传感器阵列和摄像头视觉方案。

灰度传感器的原理是红外发射管发出红外光,接收管根据地面反射强弱判断颜色。黑色吸光,反射弱;白色反光强,反射强。把多个这样的传感器排成一排,就能知道黑线在车头什么位置。常见的有 3 路、5 路、8 路,数量越多,采样点越密,弯道上越不容易丢线。

摄像头方案典型代表是 OpenMV。它通过图像处理提取黑线中心点,视野比灰度阵列宽,能处理更复杂的赛道元素,比如十字、断线、急弯,但处理速度、光照敏感度和调参复杂度也要考虑。

如果刚入门,我建议先从 5 路灰度阵列开始。5 路已经能覆盖大多数直道和常规弯道,价格便宜,调试直观,逻辑也好写。等灰度方案跑稳了,再上视觉巡线,这样每一步都知道问题出在哪。

2.4 软件环境和最小接线清单

以 STM32 为例,常见的开发方式是用 STM32CubeMX 生成初始化工程,再用 Keil 或 STM32CubeIDE 写逻辑。Arduino 就用 Arduino IDE,选择对应开发板型号,安装驱动即可。OpenMV 需要专用 IDE,可以连接摄像头实时查看画面。

接线方面,以 5 路灰度传感器加两路电机驱动为例,通常涉及这几类连接:

  • 传感器 VCC 接主控 3.3V 或 5V,GND 共地,OUT 接 ADC 引脚。
  • 电机驱动 IN1、IN2 控制方向,PWM 接定时器通道引脚。
  • 电机正负极接驱动输出,别接反,否则方向反。
  • 编码器若存在,接对应定时器输入捕获,用于测速。

注意:接线之前先确认传感器和驱动的逻辑电平,5V 传感器输出接到 3.3V 主控时,最好加电平转换或确认引脚容忍度。这个细节常在启动阶段就踩坑。

3. 从传感器标定到一条稳定的误差曲线

3.1 第一步:别写控制,先读传感器

很多新手拿到开源代码后第一件事就是烧录跑车,结果车乱跑,还以为是控制代码问题。实际上,绝大多数奇怪行为都来自传感器读数不对。所以我强烈建议,拿到板子先写一个最简单的程序:循环读取每路传感器的值,通过串口打印出来。

在串口助手或者终端里,你应当能看到类似这样的输出:

s0=123 s1=45 s2=860 s3=12 s4=200 s0=110 s1=38 s2=900 s3=15 s4=180

如果传感器在黑色胶带上,对应通道的值会明显升高或降低,具体方向取决于模块是模拟输出还是数字输出,以及内部电路。调整传感器高度和间距,让每个通道在越过黑线时都有明显变化。

这一阶段的判断标准是:

  • 每个通道的数值在黑白之间变化足够大,差异至少达到几十以上。
  • 数值变化稳定,不跳动过猛。
  • 传感器离地面高度合适,一般在 1 到 2 厘米附近,具体以模块说明为准。

如果读数抖动严重,先检查共地、供电电压和传感器高度,不要急着改程序。

3.2 阈值、二值化和归一化

灰度传感器输出的本质是一个与反射强度相关的数值。为了让逻辑简单,通常先把连续数值转成“看到黑线”或“没看到黑线”的二值信号。如果模块已经内置比较器输出数字量,那只需要在程序里直接判断 0 或 1。

如果需要自己设阈值,做法是:把传感器分别放在白底和黑线上,采样取平均,得到 white 和 black 两个参考值,然后取中间值作为阈值。

#define THRESHOLD ((white_value + black_value) / 2) if (sensor_value > THRESHOLD) { line_detected = 1; } else { line_detected = 0; }

如果后续要做视觉巡线,思路类似,OpenMV 里就是设置 LAB 颜色阈值,把目标色从背景里分割出来。

更精细一点,可以把模拟量做归一化:

// 把原始值映射到 0 到 1000,越接近 1000 表示越黑(以自身传感器特性为准) normalized = (raw_value - white_ref) * 1000 / (black_ref - white_ref); if (normalized < 0) normalized = 0; if (normalized > 1000) normalized = 1000;

归一化的好处是换场地后只改 white_ref 和 black_ref,不用改控制逻辑。我一般会把这个过程做成单独的标定函数,每次换场地先跑一遍标定,再上赛道。

3.3 多路传感器怎么算“线的位置”

多路传感器排成一排,不能只看某一单独通道。常用的方法叫加权误差计算,也叫重心法。给每个传感器一个位置权重,比如 5 路从左到右分别是 -2、-1、0、1、2,中心通道权重为 0,然后根据每路的黑线检测结果求加权平均。

float sum = 0, weighted_sum = 0; const int weight[5] = {-2, -1, 0, 1, 2}; for (int i = 0; i < 5; i++) { if (sensor_black[i]) { sum += 1; weighted_sum += weight[i]; } } float error = 0; if (sum > 0) { error = weighted_sum / sum; }

这里 error 的含义就是黑线相对车头中心线的横向偏移。error 越接近 0,说明线在正中间;error 为正,说明线偏右;为负,说明线偏左。所有传感器都丢线时 sum 为 0,这时需要单独处理,通常先保持上次方向或者直接停车,不要盲目加速。

这个 error 是整个控制系统的核心信号。后面所有转向控制,都是围绕它展开的。所以我建议把 error 和每路传感器状态一起通过串口打印,跑车时观察数值是否平滑变化。

3.4 什么算“读数正常”

读传感器这步有没有做好,可以按下面几条验证:

  • 把车放在直线上,error 应该在 0 附近小幅波动。
  • 手动把车往左偏,error 应该稳定变成负值。
  • 往右偏,error 变成正值。
  • 线移到最左或最右通道时,error 接近极限值但不跳变。
  • 读数的刷新频率够快,肉眼观察串口发来的 error 在移动时有连续性。

如果以上都满足,说明“感知”链路已经通了,可以进入控制部分。很多调车问题其实出在这一步,后面调 PID 怎么调都不顺,就是因为 error 本身是乱的。

4. 差速转向和 PID 调参实测顺序

4.1 为什么巡线小车要用差速转向

两轮差速底盘是巡线小车最常见的结构。左右轮各由一个电机驱动,通过两侧速度差实现转向。直道时两侧速度相等,车直行;需要左转时左轮减速右轮加速,车就向左偏。

差速转向比原地转向更适合巡线,因为车在转向过程中仍然在向前移动,不会因为停下来而丢失线的位置。巡线的关键是“边看清边调整”,差速控制天然符合这个思路。

具体到代码,可以先定义一个基础速度 base_speed,再根据误差计算一个调整量 adjust,最后输出:

int16_t base_speed = 120; // 基础占空比 int16_t adjust = Kp * error + Kd * (error - last_error); int16_t left_speed = base_speed + adjust; int16_t right_speed = base_speed - adjust; // 限幅 if (left_speed > MAX_SPEED) left_speed = MAX_SPEED; if (left_speed < -MAX_SPEED) left_speed = -MAX_SPEED; if (right_speed > MAX_SPEED) right_speed = MAX_SPEED; if (right_speed < -MAX_SPEED) right_speed = -MAX_SPEED;

注意左右轮的转向映射要根据实际电机接线确认。如果车越调越偏,很可能是左右 speed 和车轮方向的关系反了,可以先在代码里把输出交换验证一次。

4.2 PID 参数从哪里开始调

PID 里的 P 是比例,Kp 越大,对偏差的反应越猛;D 是微分,Kd 能抑制快速变化,减少抖动;I 是积分,主要用于消除静态误差,巡线小车一般先用不到,不必要时不加。

调参顺序我建议固定为:

  1. 先把 I 设为 0,D 设为 0,Kp 给一个较小的值,比如 1 或 2,不同代码量纲不同,要自己试。
  2. 在直道上测试,看车能不能快速回到线中间。如果回正太慢,增大 Kp。
  3. 出现左右抖动,说明 Kp 偏大,具体现象是车头来回甩,这时减小 Kp 或先加一点 Kd。
  4. 加 Kd,从很小的值开始加,比如 5 或 10,观察过弯是否更稳定。
  5. 最后再上 S 弯和连续弯,反复微调。

这里有个容易误解的点:不是说 Kp 越大越好。Kp 太大,车会过冲,线在中间反而左右摇摆;Kp 太小,弯道跟不住。判断标准是,直道不抖、常规弯道能快速回正,这是第一目标。

调参时每次只改一个参数,改完跑一圈记录现象,再改下一个。最忌讳同时改好几个参数,出了新问题都不知道是哪个参数引起的。

4.3 加 D 要小心噪声

D 项是对误差变化的响应。问题是传感器读数天然有噪声,如果 error 本身抖动,D 项会把噪声放大,表现为电机声音发毛、车头高频颤动。

如果出现这种情况,先确认 error 是否平滑,再降 Kd。也可以对 error 做简单的滑动平均,或者降低传感器采样抖动。永远记住,滤波和参数调整都是为了让控制量干净,而不是掩盖传感器问题。

4.4 验证控制效果的四个标准

调完 PID 之后,不要只看“能跑”。我会用四个标准来验收:

  • 直道稳定:车身不左右摆动,误差范围通常在 0 附近小幅波动。
  • 弯道不丢线:常规圆弧弯和直角弯都能通过,不冲出赛道。
  • 加速后仍可控:把 base_speed 提高一档,观察是否还能稳定贴线。
  • 连续多圈可重复:同一赛道连续跑几圈,结果一致性高。

如果第 3 条不满足,说明参数是在低速下“试”出来的,不是真正稳定的参数。这时候要么降低目标速度,要么从机械和传感器层面找原因,而不是继续加 Kp。

5. 现场实战中容易翻车的几个点

5.1 光照、反光和场地变化

灰度传感器虽然用的是红外发射,但环境光和外物干扰仍然会影响读数。常见情况是比赛场地灯光很强,或者赛道纸面反光,导致白底也测出接近黑线的数值。

处理思路有几条:

  • 传感器抬高一点或压低一点,找到受环境光影响最小的安装高度。
  • 标定不只在开机时做一次,换场地后重新标定。
  • 软件里加动态阈值,根据最近几百个读数的最高最低值设置上下界。
  • 如果反光严重,可以考虑换传感器型号或加遮光罩。

实测中最常见的问题不是“检测不到黑线”,而是“把白底当成黑线”。一旦白底被误判,车就会沿着反光条纹跑偏,非常难查。

5.2 急弯、十字和断线

直角弯是灰度阵列方案的一个考验。原因很简单:直角弯的线路在弯心处会短暂超出传感器阵列覆盖范围,如果车速太快或者转向过度,就容易丢线。

应对办法:

  • 提前减速,过弯后恢复速度。
  • 增加传感器路数,扩大检测范围。
  • 在控制逻辑里检测到只有最外侧通道触线时,快速给出较大转向。

十字路口(交叉线)也需要单独处理。如果不加逻辑,车经过十字时会同时看到多条黑线,error 可能突然归零,导致直接直行,这在有些赛道是对的,但在需要转弯的十字处就不对。简单做法是记录最近一段时间的运动状态,或者根据赛道规则把十字区域当成一个特殊事件,执行固定转向动作。

断线区域更考验策略。常见做法是检测到全部传感器丢线后,采用“盲跑”策略:按上一次的有效方向继续行驶一小段距离,并计时,超过一定时间还没重新上线就停车。这个计时值要实测,太短容易误判,太长可能冲出赛道。

5.3 电池电压和电机一致性

电池电压对巡线的影响比很多人想象的大。刚充满电时电机转速高,跑一段时间后电压下降,同样的 PWM 占空比实际速度会变慢。如果 PID 调参是在满电状态调好的,低电状态很可能就失控。

处理方式:

  • 尽量使用稳压能力好的电源方案,让主控和传感器供电稳定。
  • 电机端可以根据电压做速度补偿,但这会更复杂,新手可以先不用。
  • 更实用的做法是,调试和比赛用同一块电池状态,或者在多个电量水平下分别跑一遍,确认参数余量足够。

左右电机的一致性也是一个坑。两个电机的特性、轮子的摩擦力、安装松紧都可能造成差速,直道上车会偏。可以在程序里加一点点静态偏置补偿掉基础偏差。注意这个偏置是在 error 为 0 时也能让车走直的东西,和 PID 无关。

5.4 机械细节:重心、轮距和传感器高度

机械上的小问题经常被忽略,但影响非常直接。

重心偏高或偏后,急弯时容易侧翻或甩尾。电池、主控这些比较重的部件尽量往底盘中部放。

轮距和轴距决定了过弯的极限。一般来说,轴距短一点,小车转向更灵活,但直线稳定性会差一点;底盘宽一点,稳定性好,但弯道半径会变大。具体调法看赛道情况。

传感器高度和角度也很关键。传感器离地太近容易被地面小颗粒卡住,太远则数值不清晰。安装时要保证阵列和地面平行,左右高度一致,否则 error 在直道上也是偏的。

6. 巡线出问题时,按这个顺序排查

6.1 先看现象,再定位层级

巡线出问题的现象通常就几类:

  • 上电没反应。
  • 电机转,但车不巡线,直线乱跑。
  • 直道抖动。
  • 过弯冲出赛道。
  • 偶尔丢线,表现不稳定。

我的排查原则是:先硬件后软件,先信号后控制,先单通道再整体。不要一上来就改 PID,也不要猜。按顺序走一遍,大多数问题都能定位。

6.2 具体排查顺序

  1. 查电源。测量电池电压、主控供电、驱动供电,确认在正常范围。电机转动瞬间电压是否掉得厉害,这里最容易看出电源问题。
  2. 查传感器供电和共地。传感器没共地会出现读数漂移,共地不好会出现偶尔跳变。
  3. 查串口日志。把每路传感器原始值和 error 打印出来,移动车,看数值变化是否符合预期。如果这里就不对,后面控制不用看。
  4. 查电机方向。单独给左右轮发固定 PWM,确认两个轮子方向一致,且 IN 引脚逻辑和预期相符。
  5. 查 PWM 输出。确认占空比变化时车轮速度真的有变化,而不是只在满功率和停之间跳。
  6. 查控制逻辑。打印左右轮的目标速度和实际输出,确认限幅、方向映射是否正确。
  7. 最后查参数。以上都正常,才开始调 PID。如果前面某一层有问题,PID 怎么调都不会好。

6.3 常见现象和可能原因对照

现象优先排查项可能原因
上电没反应电源、接线供电不足、引脚接错、程序没烧进
一直原地打转电机方向、传感器状态左右轮方向反、传感器误判全部偏一侧
直道左右抖动error 噪声、Kp/KdKp 太大、传感器读数不稳、D 项放大噪声
过弯冲出赛道车速、丢线策略base_speed 过高、转向不足、急弯处丢线处理不对
偶尔跑偏一次传感器、接线传感器插头松动、共地接触不良、反光干扰
高电量正常低电量失控电源补偿电压下降导致实际速度变化,参数余量不足

这张表不是万能答案,但能帮你快速缩小范围。实际排查时,每改一个变量就重新跑一次,不要一次动多个地方。

7. 从灰度巡线走向视觉巡线和仿真

7.1 视觉巡线,值得什么时候上

灰度阵列能做到稳定巡线之后,可以考虑上视觉方案。OpenMV 这类摄像头模块处理的是图像,能看到黑线走向,视野更宽,也能识别十字、箭头甚至色块标志。

视觉巡线的复杂度主要在

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询