【STM32最小系统板】从状态机到PID:细铁丝高速循迹小车的算法演进与实践

张开发
2026/4/14 18:30:17 15 分钟阅读

分享文章

【STM32最小系统板】从状态机到PID:细铁丝高速循迹小车的算法演进与实践
1. 细铁丝循迹小车的技术挑战用STM32最小系统板做循迹小车的朋友应该都玩过黑胶带或白线循迹。但当我第一次接触0.6mm细铁丝循迹时才发现这完全是另一个维度的挑战。就像用毛笔写字和用绣花针刻字的区别——前者允许一定误差后者稍有不慎就会失控。细铁丝带来的核心难题有三个首先是检测精度普通红外对管在1cm黑线上的检测方式完全失效必须改用涡流传感器或高灵敏度霍尔元件其次是控制响应速度当小车以400mm/s以上速度行驶时传统延时转向方案会让小车像醉汉一样走S形路线最后是机械适配性我曾亲眼见证某参赛队伍因为车轮轴承的0.1mm间隙导致直线行驶时持续偏航。这里有个实测数据对比同样使用四路传感器时1cm黑线循迹的容错宽度约为±5mm而0.6mm铁丝的允许偏差仅有±0.8mm。这意味着传感器安装角度偏差超过2度或者车体震动幅度大于1mm都会导致循迹失败。这也是为什么很多队伍初期用状态机方案时小车总在转弯处飞出赛道。2. 状态机从混沌到有序的进化2.1 传统延时方案的致命缺陷最早我做黑线循迹时用的就是典型的延时逻辑void xunji() { if(左传感器触发){ 左转(); delay(10); // 魔法数字 } else if(右传感器触发){ 右转(); delay(8); // 另一个魔法数字 } }这种方案在细铁丝场景下会暴露两个致命问题一是delay时间需要根据速度动态调整速度提升10%就可能需要重新校准所有参数二是没有状态记忆当传感器因震动短暂误触发时小车会像无头苍蝇一样乱转。2.2 五状态机的实战实现升级后的状态机方案引入了行驶状态记忆就像给盲人配了导盲杖enum State { RapidLeft -2, // 急左转 TurnLeft -1, // 普通左转 Straight 0, // 直行 TurnRight 1, // 普通右转 RapidRight 2 // 急右转 };关键改进在于状态切换逻辑if (Left10 Left21 Right11) { st RapidLeft; // 左前轮压线需要急转 } else if (Left11 Left21 Right10) { st RapidRight; } else if (st TurnLeft 所有传感器1) { st Straight; // 仅当从转弯状态恢复时才切回直行 }实测表明加入状态记忆后在半径20cm的弯道上通过率从38%提升到92%。但新的问题出现了——当速度超过500mm/s时小车在直线段会出现持续振荡。3. PID控制让小车学会自动驾驶3.1 增量式PID的落地实践状态机解决了转弯问题但直线稳定性需要PID出场。我选择增量式PID主要考虑三点计算量小STM32F103C8T6资源有限、抗积分饱和避免长时间偏离导致的失控、参数易调比赛时间紧迫。具体实现时有几个关键点int Incremental_PI(int Encoder, int Target) { static float error, Last_error, Last_Last_error; error Target - Encoder; Pwm Kp*(error-Last_error) Ki*error; // 增量计算 Last_Last_error Last_error; Last_error error; return Pwm; }参数调节时有个小技巧先用示波器观察编码器波形将P值从小往大调直到出现等幅振荡此时取该值的60%作为最终P值。比如我测试时振荡临界P5.3实际采用P3.2。3.2 速度与位置的串级控制高阶玩法是结合编码器速度环和传感器位置环[目标速度] → [PID速度控制] → [电机PWM] ↑ [编码器反馈] ← [电机转动]同时[传感器位置] → [状态机] → [目标速度修正]这种架构下小车在直线段会保持300mm/s匀速检测到弯道时状态机动态修改左右轮目标速度差。实测在800mm/s高速下仍能保持±1.5mm的循迹精度。4. 硬件设计的魔鬼细节4.1 传感器选型血泪史试过三种方案后最终选择LDC1314涡流传感器其优势在于检测距离可精确到0.1mm响应频率高达4MHz应对高速数字输出避免模拟信号干扰但要注意三个坑传感器线圈必须与铁丝垂直倾斜超过10度灵敏度下降50%铝合金底盘会形成涡流干扰解决方案是用3mm亚克力板作支架供电必须独立LDO电机启停时的电压波动会导致误检测4.2 机械结构的毫米级优化几个关键尺寸影响巨大轮距建议保持90-100mm过小易侧翻过大转向迟钝传感器安装高度距铁丝3±0.5mm用尼龙螺丝方便微调牛眼轮要选带陶瓷轴承的版本摩擦系数降低60%特别提醒车轮的同心度要用百分表校准我遇到过因为0.2mm偏心导致的速度波动问题这种机械误差是软件无法完全补偿的。5. 竞速模式的极限调参当基础功能实现后要突破20秒/圈的关键在于5.1 动态速度规划弯道不是全程降速而是采用入弯减速-弯心加速策略if(进入弯道){ Target 常规速度 * 0.7; flag 1; // 标记入弯 } else if(弯心 flag){ Target 常规速度 * 1.3; // 利用离心力加速出弯 flag 0; }5.2 控制周期优化把PID计算从主循环移到定时器中断关键配置void TIM4_IRQHandler() { if(TIM_GetITStatus(TIM4, TIM_IT_Update)){ LeftPwm Incremental_PI(LeftEncoder, LeftTarget); RightPwm Incremental_PI(RightEncoder, RightTarget); SetPwm(LeftPwm, RightPwm); TIM_ClearITPendingBit(TIM4, TIM_IT_Update); } }定时器周期设置为5ms时系统响应延迟从原来的120ms降到8ms这也是能实现高速控制的基础。6. 硬币检测的工程化处理虽然比赛要求检测1角硬币但实际会遇到硬币氧化程度不同导致信号差异多硬币相邻时的信号叠加高速通过时的信号抖动我的解决方案是采用移动窗口滤波取最近20次AD值的滑动平均差分检测算法只有当|V_current - V_previous| 3σ时才触发状态锁存检测到信号后屏蔽后续100ms的重复触发具体实现时注意ADC采样时钟要配置为12MHzSTM32F103的极限这样才能在高速下获取足够采样点。7. 从实验室到赛场的经验谈最后分享几个只有踩过坑才知道的经验电池电压监测必不可少当电压低于7.4V时PID参数会漂移建议在代码中加入电压补偿系数现场灯光可能干扰光电编码器我们的解决方案是用黑色热缩管包裹编码盘赛前要用热风枪均匀加热车体温度变化1℃会导致铝合金底盘膨胀0.01mm足以影响传感器读数准备至少三组参数备用上午/下午的环境温湿度差异可能导致需要微调PID这套系统后来在省赛中跑出了18.7秒/圈的成绩关键不在于用了多高级的算法而在于每个环节都做到了工程级的精细打磨。现在回头看从最初的状态机到完整的PID控制就像给小车装上了大脑和小脑让它真正具备了应对复杂环境的能力。

更多文章