1. 项目概述:双光PID巡线小车的核心价值
去年在机器人社团招新时,有个大二学生拿着他的小车问我:"为什么我的巡线车遇到急弯就冲出去?加了五个传感器还是抖得像帕金森"。当时我给他看了这个超轨双光PID方案,三周后他拿了省赛一等奖。这个看似简单的双传感器方案,实际上藏着不少精妙的设计哲学。
传统巡线方案常见两种极端:要么是单传感器"盲人摸象"式巡线,要么是堆砌七八个传感器的"过度设计"。而这个开源方案用两个光电传感器配合改进型PID算法,实现了95%场景下的稳定巡线。最让我惊讶的是它的自适应模块——在不同曲率弯道和交叉线路况下,参数会动态调整,这比我们公司某些商用机器人还聪明。
2. 硬件架构解析
2.1 传感器布局的黄金法则
方案采用两个灰度传感器呈"八"字形安装,前间距20mm后间距35mm,形成梯形探测区域。这种非对称布局有三大优势:
- 前窄后宽的结构天然形成预测窗口,当后方传感器检测到线缘时,前方传感器已经提前1-2cm感知到走向
- 35mm的后间距确保即使遇到5cm宽的黑线也不会同时触发双传感器
- 倾斜安装使传感器对弯道内外侧产生不同的响应延迟,这个时间差恰恰是计算转向角度的关键参数
实测发现传感器距地面最佳高度为1.2cm,此时检测黑线的有效区域直径约3mm。太近容易受反光干扰,太远则降低灵敏度。
2.2 核心控制单元选型
主控使用STM32F103C8T6并非偶然,它的定时器资源恰好满足需求:
- TIM3用于生成PWM驱动电机
- TIM2和TIM4分别捕获两个传感器的中断信号
- 内置的12位ADC以1kHz频率采样传感器模拟值
电机驱动采用TB6612FNG而不是常见的L298N,因为它的效率高出30%,且支持1MHz的PWM频率。这个细节让小车在低速巡线时几乎没有步进感。
3. 算法核心:双光PID的独特实现
3.1 误差计算的二阶差分法
传统单光PID的误差计算是二值化的(在线左/在线右),而这个方案引入了灰度值的连续微分:
c复制float error = (sensor_left - sensor_right) / (sensor_left + sensor_right + 0.001f);
float error_diff = error - last_error;
float error_diff2 = error_diff - last_error_diff;
这种计算方式带来三个好处:
- 能感知即将到来的弯道陡峭程度(通过二阶差分)
- 在浅色地面上的抗干扰能力更强
- 遇到交叉线时自动降低P参数防止振荡
3.2 动态权重分配策略
程序里最精妙的是这个权重函数:
c复制float weight = fabs(error_diff) * 0.6 + fabs(error_diff2) * 0.4;
output = (Kp * error * (1 + weight)) + (Kd * error_diff / (1 + weight));
当检测到急弯(error_diff2增大)时,自动提高比例项权重;而在直道时增强微分项作用。实测表明这种动态调整比固定参数PID的巡线速度提升40%。
4. 实操部署指南
4.1 校准流程的隐藏技巧
官方文档没写的校准秘诀:
- 在校准白值时,要在传感器前方放置一张A4纸,消除环境光影响
- 黑值校准要分三步:先中心对准黑线,然后左右各偏移5mm测量
- 保存校准数据时建议写入Flash而不是EEPROM,因为STM32的EEPROM有写入次数限制
4.2 参数整定的快速方法
分享我的快速调参口诀:
- "P大了抖,D大了飘,I多了绕"
- 先设D=0,增大P直到小车开始高频振荡
- 然后增大D直到振荡消失
- 最后加微量I(0.001左右)消除静态误差
一个经验参数:对于1:48的TT马达,Kp=3.2, Ki=0.001, Kd=1.8是比较通用的起点。
5. 典型问题排查手册
5.1 弯道冲线问题
现象:90度弯道总是冲出去
排查步骤:
- 检查传感器高度是否>1.5cm
- 测量黑线宽度是否<3cm(超出双光检测极限)
- 用示波器看PWM输出是否达到最大值
5.2 十字路口误判
现象:遇到十字路口原地转圈
解决方案:
- 在代码中增加最小误差阈值(建议0.15)
- 添加通过十字路口的计时器保护
- 或者更暴力但有效的方法——在路口贴反光条
6. 进阶改造思路
给想深度改造的玩家几个方向:
- 加入光流传感器做速度闭环控制
- 用磁编码器替代电机自带的霍尔传感器
- 尝试三阶PID(在现有代码基础上增加error_diff3项)
- 最有趣的改法:把第二个传感器换成ToF测距,实现立体巡线
这个开源方案最值得借鉴的是它"少即是多"的设计哲学。去年比赛后,我把这个思路用在了仓库AGV上,仅用两个传感器就替代了原来五万块的商业导航模块。有时候最好的解决方案,往往藏在最简单的设计里。
