ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

巡线小车实战:从传感器标定到PID调参全记录

巡线小车实战:从传感器标定到PID调参全记录 巡线小车大概是嵌入式入门里最容易让人产生“我好像会了”错觉的项目。硬件上确实不复杂一块 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 或 5VGND 共地OUT 接 ADC 引脚。电机驱动 IN1、IN2 控制方向PWM 接定时器通道引脚。电机正负极接驱动输出别接反否则方向反。编码器若存在接对应定时器输入捕获用于测速。注意接线之前先确认传感器和驱动的逻辑电平5V 传感器输出接到 3.3V 主控时最好加电平转换或确认引脚容忍度。这个细节常在启动阶段就踩坑。3. 从传感器标定到一条稳定的误差曲线3.1 第一步别写控制先读传感器很多新手拿到开源代码后第一件事就是烧录跑车结果车乱跑还以为是控制代码问题。实际上绝大多数奇怪行为都来自传感器读数不对。所以我强烈建议拿到板子先写一个最简单的程序循环读取每路传感器的值通过串口打印出来。在串口助手或者终端里你应当能看到类似这样的输出s0123 s145 s2860 s312 s4200 s0110 s138 s2900 s315 s4180如果传感器在黑色胶带上对应通道的值会明显升高或降低具体方向取决于模块是模拟输出还是数字输出以及内部电路。调整传感器高度和间距让每个通道在越过黑线时都有明显变化。这一阶段的判断标准是每个通道的数值在黑白之间变化足够大差异至少达到几十以上。数值变化稳定不跳动过猛。传感器离地面高度合适一般在 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 是积分主要用于消除静态误差巡线小车一般先用不到不必要时不加。调参顺序我建议固定为先把 I 设为 0D 设为 0Kp 给一个较小的值比如 1 或 2不同代码量纲不同要自己试。在直道上测试看车能不能快速回到线中间。如果回正太慢增大 Kp。出现左右抖动说明 Kp 偏大具体现象是车头来回甩这时减小 Kp 或先加一点 Kd。加 Kd从很小的值开始加比如 5 或 10观察过弯是否更稳定。最后再上 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 具体排查顺序查电源。测量电池电压、主控供电、驱动供电确认在正常范围。电机转动瞬间电压是否掉得厉害这里最容易看出电源问题。查传感器供电和共地。传感器没共地会出现读数漂移共地不好会出现偶尔跳变。查串口日志。把每路传感器原始值和 error 打印出来移动车看数值变化是否符合预期。如果这里就不对后面控制不用看。查电机方向。单独给左右轮发固定 PWM确认两个轮子方向一致且 IN 引脚逻辑和预期相符。查 PWM 输出。确认占空比变化时车轮速度真的有变化而不是只在满功率和停之间跳。查控制逻辑。打印左右轮的目标速度和实际输出确认限幅、方向映射是否正确。最后查参数。以上都正常才开始调 PID。如果前面某一层有问题PID 怎么调都不会好。6.3 常见现象和可能原因对照现象优先排查项可能原因上电没反应电源、接线供电不足、引脚接错、程序没烧进一直原地打转电机方向、传感器状态左右轮方向反、传感器误判全部偏一侧直道左右抖动error 噪声、Kp/KdKp 太大、传感器读数不稳、D 项放大噪声过弯冲出赛道车速、丢线策略base_speed 过高、转向不足、急弯处丢线处理不对偶尔跑偏一次传感器、接线传感器插头松动、共地接触不良、反光干扰高电量正常低电量失控电源补偿电压下降导致实际速度变化参数余量不足这张表不是万能答案但能帮你快速缩小范围。实际排查时每改一个变量就重新跑一次不要一次动多个地方。7. 从灰度巡线走向视觉巡线和仿真7.1 视觉巡线值得什么时候上灰度阵列能做到稳定巡线之后可以考虑上视觉方案。OpenMV 这类摄像头模块处理的是图像能看到黑线走向视野更宽也能识别十字、箭头甚至色块标志。视觉巡线的复杂度主要在
返回列表