资讯详情

21届智能车疯狂电路组开源仓库全解析:从电路到控制算法

📅 2026/11/6 7:25:10 | 华诺云谱 👁 阅读
21届智能车疯狂电路组开源仓库全解析:从电路到控制算法
21届疯狂电路组比赛结束后的第三个星期我终于把Soberup战队的仓库做了最后一次清理。git log里最后一笔的是“release: 21届开源归档”看着那串commit记录忽然觉得这九个月的时间终于有了一个看得见的句号。这篇博文不打算写成一份正经的项目文档更想以队长的身份带你把我们整个开源目录从头到尾逛一遍——哪里是能直接拿来用的哪里是踩了坑不值得再碰的还有那些写在注释里但没写进README的细节我都尽量说出来。先交代一下背景。Soberup战队21届全国大学生智能车竞赛疯狂电路组最终成绩是分区赛一等奖加国赛一等奖。我们的备赛周期是大半年从硬件改版到算法重构折腾了整整三轮。整个开源仓库放在Gitee上内容包括原理图与PCB源工程、底层驱动库、上层控制算法串级PID、路径规划、特殊元素状态机、Windows上位机工具、以及全套调试笔记和比赛现场录屏。无论你是下一届准备打疯狂电路组的新人还是只对某一小块技术比如“PID输出角速度”的工程实现感兴趣的老手这个仓库里应该都有你需要的参考。接下来我会按仓库里的实际目录顺序来讲。这篇文章是目录的导航也是我们整个设计思路的还原。1. 开源动机与仓库结构我们为什么敢把全部家底放出来1.1 开源不是炫技是给后来者省半年时间说实话第一次考虑全量开源的时候队里是有争议的。有人担心“把核心算法放出去明年怎么打”但最后我们统一了一个观点智能车竞赛的最优解从来不是靠藏着掖着拿到的而是靠一代一代人的公开经验叠加出来的。我们队里所有人都是从看学长学姐的开源资料起步的如果每一届都闭门造车那竞赛水平只会原地踏步。另一个更现实的原因是疯狂电路组这个组别比的是“综合硬实力”。赛场上比的不是某一段代码有多骚气而是整个系统在极限状态下的稳定性。你就算把我们的控制代码原封不动搬到另一台车上机械结构、电路布局、传感器安装角度不一样参数照样得从头调。所以开源真正的价值不在“代码能不能直接用”而在“设计思路能不能被复现和理解”。我们把仓库里每份文档都当成了“教案”来写而不是“交付物”。1.2 仓库目录怎么读先看文档再碰代码很多人在开源仓库里最容易犯的错就是一上来就扒代码然后被一堆抽象概念劝退。我们刻意把仓库分成五个顶层目录每个目录对应一段备赛阶段的核心产出目录内容适合谁hardware/原理图、PCB源工程立创EDA格式、BOM表、3D模型想复刻硬件或学习电路设计的人firmware/底层驱动基于NXP i.MX RT1064 逐飞库、各外设初始化代码需要移植驱动或学习RT1064的人algorithm/图像处理、电磁采样、串级PID、角速度控制、元素状态机研究控制算法和特殊元素处理的人tools/上位机、串口解析工具、图像离线查看器C#写的小工具想提高调试效率的人docs/设计文档、调参记录、比赛复盘、踩坑清单所有人建议第一优先阅读推荐顺序是先读docs/00_START_HERE.md里面有一张完整的技术方案选型表然后看hardware/README.md了解整车硬件架构再去algorithm/看控制框架的说明文档最后才是按需翻代码。很多人看开源项目喜欢从README开始这没错但我们的README更像是一张“地图”真正的宝藏全在子目录各自的说明文件里。1.3 开源许可证怎么选我们选了GPL-3.0并说清楚原因这个细节很多搞开源的爱好者容易忽略但对一个面向竞赛的开源项目来说许可证其实决定了这个仓库“能走多远”。我们最终选了 GPL-3.0理由很简单第一我们希望对后续使用者保留约束——如果你基于我们的代码做了改进并且把改进后的版本用于比赛之外的地方我们希望这些改进也能回流到社区。第二GPL-3.0对专利和“使用即接受条款”有更明确的表述能在法律层面减少一些模糊地带。第三对于一个教学性质很强的项目GPL-3.0能保证它不会被人“闭源封装后拿去售卖”这是我们对整个竞赛社区的承诺。如果你也在准备开源自己的智能车项目我建议别纠结太久纯想分享、希望尽量多人用的选MIT或BSD想强制改进回流的选GPL家族完全不想被商用碰的可以考虑CC BY-NC-SA一类的知识共享协议。选完之后在README头部写清楚就行不用搞得太复杂。2. 疯狂电路组的赛题理解与整车方案选型2.1 疯狂电路组到底在考什么电路可靠性和系统鲁棒性疯狂电路组是21届智能车竞赛里的一个“硬核”组别。相对传统摄像头组和电磁组它的特殊之处在于赛题设计上故意把“电气噪声、供电波动、信号完整性”这些平时被忽略的问题放大到了决定成败的程度。赛场上同一条赛道你可能同时面对电机大电流瞬间压降、舵机回抽时的反电动势、无线模块的射频干扰还有摄像头数字信号在长排线里的串扰。谁家的电路能在这种“恶劣环境”下稳定输出正确信号谁就赢了一半。所以我们整个方案选型的第一原则不是“性能最强”而是“最皮实”。以主控为例我们最终锁定 NXP i.MX RT1064Cortex-M7内核运行在600MHz够跑灰度图像处理加控制算法而且片上资源丰富不需要外扩SDRAM减少了布线复杂度和故障点。摄像头用的总钻风MT9V034同级别灰度摄像头电磁传感器用工字电感加谐振电容的方案。转向执行器选的是数字舵机但没有跟风用大扭矩金属齿而是选了响应速度更快、线性度更好的中端型号——因为我们在后期测试中发现对疯狂电路组这种需要频繁小幅度修正的场景舵机响应速度远比绝对扭矩重要。2.2 传感器布局电磁为主、摄像头为辅的融合依据很多队伍喜欢“摄像头为主电磁为辅”但我们在疯狂电路组反过来了电磁是主传感器摄像头是辅助传感器。这个决策经历了三轮实车验证才定下来。电磁方案的核心优势是鲁棒性强。工字电感配合谐振电容构成LC选频网络只对赛道下方导航线通入的特定频率一般是100kHz左右交变磁场敏感受环境光、路面颜色变化的影响极小。摄像头方案信息量大但受曝光、逆光、阴影干扰严重在赛场顶灯条件下经常出现图像二值化不稳定。疯狂电路组的比赛时间跨度长一天内自然光变化很大如果主控依赖摄像头调试工作量会爆炸。所以我们的实际架构是电磁信号负责“全局导航”——提供赛道中心线的连续横向偏差信号两个水平电感加两个斜45度电感组成阵列通过差比和算法算出车体相对导航线的横向偏移和航向偏差摄像头负责“特殊元素识别”——环岛、十字、坡道、断路这些电磁难以区分的地面结构靠图像特征来判别并触发对应的处理状态。2.3 整车机械与重心配平预算不够时优先做什么我们队的经费不算充裕买不起顶级车模套件所以机械部分全是我们自己用3D打印件和碳纤维板搭的。这里分享一个我们反复验证的结论重心越低、越居中控制算法越好调。这句话听着像废话但很多人实际操作时完全没当回事。我们曾经把电池横放在车身后部方便走线结果过弯时车尾摆动严重PID参数怎么调都抖。后来把电池竖立放在车辆几何中心正上方、重心离地高度压到3厘米以内同样的参数弯道极限速度直接提升了15%。另外疯狂电路组因为要跑特殊元素整车重量克制也很重要——我们在每个螺丝上都做了减重最终整车含电池控制在1.1公斤左右这对舵机和电机的响应负担都小很多。如果你预算有限我建议钱优先花在四样东西上好的舵机、好的电机驱动、好的陀螺仪IMU、质量靠谱的电池。这四样决定了你调参的天花板。3. 电路与PCB设计的核心细节疯狂电路组真正的战场3.1 电源树设计与稳压方案电机一启动单片机不能复位疯狂电路组最经典的翻车现场是电机突然大油门起步主控瞬间复位整车失控撞墙。这背后是典型的电源跌落问题。我们花了很多精力设计电源树这里把完整方案列出来供参考。整车使用2S锂电池标称7.4V满电8.4V经过防反接电路后分为三路电机驱动路直接接电池电压经大容量电解电容470uF x2和陶瓷电容100nF x若干去耦再进MOSFET驱动芯片。电机驱动是最大的干扰源所以它的地和系统信号地必须严格分开。舵机路同样是电池电压直接供给数字舵机工作电压6-8.4V但串联了一个磁珠和一个47uF电解电容用来吸收舵机回抽时产生的尖峰反电动势。逻辑电路路先经过一颗低压差线性稳压器LDO降到5V再经过一颗高PSRR的LDO降到3.3V给主控和传感器供电。之所以两级降压而不是直接用DCDC是因为摄像头模拟部分对电源纹波极其敏感DCDC的开关纹波会在画面上形成水波纹干扰。有一点提醒新手注意LDO不是万能的。线性稳压器的压差乘以电流就是它的发热功率如果直接把7.4V降到3.3V且电流上了300mA芯片烫得能煎鸡蛋。我们的做法是先用一颗低噪音DCDC降到5V给数字部分再用LDO从5V降到3.3V这样LDO的压差只有1.7V发热量还在安全范围内。3.2 电磁采样电路LC谐振、精密整流与运放放大电磁传感器听上去简单实际上模拟前端做得好不好对控制稳定的影响巨大。我们的电路结构是这样的LC谐振选频工字电感10mH级别并联一个电容10nF级别谐振频率对准导航信号的100kHz。这一步是为了在强噪声环境下把目标频率信号“选”出来同时抑制其他频段干扰。精密整流谐振出来的信号是交流小信号幅值几十毫伏不能直接被ADC采样。我们需要用运放配合二极管做精密整流把交流变成直流电平。放大与滤波整流后的信号再经过一级同相放大器放大到0-3.3V范围内然后做一阶低通滤波截止频率几百赫兹最后接进单片机的ADC引脚。我们实测过如果省掉LC谐振直接用运放放大电机一启动采样值会叠加一堆100Hz左右的脉动噪声控制算法就会被带偏。另外所有电磁采样通道的地线要单独走一圈回形针一样回到主控的模拟地引脚避免数字地噪声串入。3.3 PCB布局布线的三条铁律在疯狂电路组的PCB设计上我们总结了三句话基本可以当成原则来用大电流路径短而粗电机驱动和电池主回路上的走线至少2mm宽以上最好加铺铜回路面积要小因为回路电感会造成开通关断时的振铃电压尖峰。模拟地和数字地单点连接摄像头、电磁采样、陀螺仪属于模拟/敏感电路主控、电机驱动属于数字/大电流电路两者的地平面必须区分开最后只用一颗0欧电阻或一个磁珠在单一节点连接。否则数字开关噪声会直接灌进模拟信号里。去耦电容贴着电源引脚放主控每个电源引脚旁边0.5厘米内必须有一颗100nF陶瓷电容和一颗10uF钽电容这不是可选而是必选。很多莫名其妙的主控死机、图像花屏最后都是因为去耦电容放太远。这三个原则说来简单但我们在第二轮改版时就是因为没遵守第三条导致图像在舵机转向时出现横条纹干扰排查了整整一个周末才发现是电源去耦不到位。4. 控制核心实现PID输出角速度的工程细节4.1 为什么角度环不直接输出舵机PWM而是输出角速度这是很多初学者最困惑的地方我的转向控制直接拿横向偏差喂给PID输出直接映射到舵机PWM不也能跑吗能跑但很快会到瓶颈。直接偏差映射PWM本质上是一个“只看位置不看变化趋势”的控制方式。当车辆以高速冲入弯道时横向偏差突然增大PID输出也会突然增大舵机猛地打过去——这时候车子会有一个明显的侧倾和横摆震荡如果车速再高一点后轮就会失去抓地力甩尾。问题的根源在于舵机转角的变化速度即前轮转角角速度没有被约束和控制。所以我们采用了串级控制架构。内环是角速度环外环是位置环/角度环。外环根据横向偏差计算出“我需要车身以多大的横摆角速度去修正轨道”内环则控制陀螺仪测到的实际角速度去跟踪这个目标值。这样即使外环输出骤变内环也会像一个缓冲器一样限制前轮转角的实际变化速率避免车辆动态失稳。用一句话概括角速度环解决的不是“往哪转”而是“转得多快、转得稳不稳”。它让转向动作有了“阻尼感”这是高速稳定过弯的关键。4.2 串级控制代码从横向偏差到PWM的完整链路我们仓库里algorithm/control/下的核心代码结构如下C语言实现已在RT1064上跑过实车// 控制主循环调用频率 500Hz void control_task(void) { float err_lateral; // 横向偏差电磁差比和 * 归一化系数 float err_heading; // 航向偏差陀螺仪积分与导航线方向的差 float omega_target; // 期望横摆角速度 float omega_actual; // 实际横摆角速度陀螺仪Z轴 // 1. 外环位置环输出期望角速度 omega_target position_pid_calc(pos_pid, err_lateral, err_heading, car_speed); // 2. 限幅期望角速度不能超过机械极限 omega_target constrain(omega_target, -MAX_OMEGA, MAX_OMEGA); // 3. 内环角速度环输出舵机PWM控制量 steer_pwm omega_pid_calc(omega_pid, omega_target, omega_actual); // 4. 舵机PWM输出50Hz / 或高刷300Hz视舵机型号 servo_set_pwm(steer_pwm); }关键在位置环的PID参数要“软”不追求快速回中追求平滑内环角速度环要“硬”快速跟踪目标角速度消除陀螺仪测量滞后。我们最终整定出来的一组有效参数在整车1.1kg、转向舵机中位脉宽1500us条件下参数外环位置环内环角速度环Kp2.818Ki0.050.8Kd0.10.4输出限幅±120 deg/s±500 usPWM变化量这组参数不是抄来的是大量现场调校的产物。我的经验是内环Kp先从20附近往下扫看车子的蛇形摆动是否收敛外环Kp先从2附近往上加直到入弯出现轻微过冲再往回调10%。如果你也做串级不要直接套任何人的参数车子和车子之间差异太大了。4.3 角速度测量陀螺仪Z轴的数据质量决定一切内环控制效果好不好一半取决于陀螺仪数据的质量。我们选用的是6轴IMU加速度计陀螺仪陀螺仪Z轴原始数据经过如下处理链路以1kHz读取原始角速度先做低通滤波截止频率约50Hz滤掉机械振动带来的高频噪声静态时采集2000个样本做零偏校正把这个零偏值保存在Flash里开机时自动加载运行时再用滑动窗口窗口50ms估计算法实时修正剩余零漂漂移。这里有一个我们在调试中反复头疼的问题陀螺仪的零漂会随温度变化。比赛现场从早上到中午车内温度升高10度陀螺仪零漂可能从0.2度/s漂到0.8度/s。这如果不做实时补偿内环就会一直存在一个“虚假角速度”导致车辆走直线时方向盘慢慢偏。我们的解决方案是运行时加入“静止检测”检测到车辆被支架架起或原地停稳超过3秒且没有转向指令时自动将当前陀螺仪输出刷新为零漂基准。这个小功能直接让我们在决赛日中午的稳定表现远超其他队伍。4.4 特殊元素处理环岛、十字、断路的状态机实现疯狂电路组的赛道元素里环岛是最容易翻车的。直道冲进环岛如果只靠电磁差比和导航车会在环岛入口处做出错误的转向判断因为环岛入口处导航线会从单一连续线突然变成环形结构电磁信号会出现“双侧信号同时强”的假象。我们最终用摄像头识别来辅助解决这个问题。核心思路是一个五状态状态机S_SLAM直线/普通弯道默认状态电磁导航为主。S_ISLAND_ENTER检测到环岛入口图像中出现左侧或右侧的弧形边缘特征且电磁横向偏差持续处于某一侧极限值超过200ms判定进入环岛预备此时切换到图像导航沿环岛内侧边缘跟踪。S_ISLAND_INSIDE环岛内连续跟踪环岛弧线角速度环的目标值由“跟随半径期望角速度”计算保证车辆沿固定半径行驶。S_ISLAND_EXIT检测到出口图像中弧线特征消失、电磁信号恢复正常单侧导航线结构切换回电磁导航。S_STRAIGHT_RECOVER出口修正出口后100ms内用位置环大Kp快速回中防止冲出去。这个状态机的代码在algorithm/state_machine/下我们通过串口上位机把状态切换点叠加在录制的图像上做成了一段调试视频放在docs/里。看视频你会发现其实出口判断比入口判断难得多——很多队伍进环岛成功但出环岛时因为判断太迟直接切到环岛外圈跑飞了。我们的经验是出口判断不要只依赖单一特征必须“图像边缘消失”和“电磁导航线回到中线”两个信号同时满足才允许切换。5. 软件工程落地从裸机轮询到模块化状态机5.1 代码结构设计为可调试性而设计坦白说我们第一版控制代码也是把所有功能堆在一个main函数里全局变量满天飞。到了第二版重构的时候我们确定了三条代码规范一直沿用到比赛结束每个传感器一个驱动模块只暴露“获取最新数据”和“数据是否有效”两个接口禁止在控制代码里直接操作寄存器控制逻辑与传感器解耦控制任务只拿“归一化后的偏差值”不管这偏差来自电磁还是图像所有关键变量调用时打点每隔50ms通过串口发送一份调试数据帧上位机实时绘图。这一条是效率提升的最大功臣过去是“数据不对劲猜是哪里”现在是“曲线摆在那一眼定位”。5.2 上位机工具一个C#写的串口调试助手我们在tools/里放了一个自己写的小上位机用C# WinForms写的。功能不复杂但非常实用串口选择、数据帧解析、曲线绘制、示波器式缩放、录像回放。它能同时绘制6条曲线——电磁左/右水平电感值、摄像头的实时横向偏差、目标角速度、实际角速度、舵机PWM——比赛现场调参时这块屏幕就是我们队的“眼睛”。还有一个功能值得一说图像离线查看器。我们把摄像头的原始灰度数组通过串口或赛后从SD卡导出存成bin文件上位机可以一帧一帧回放并且把状态机的切换时刻用颜色标注出来。这让我们能离线复盘整场比赛找到“在哪个具体位置状态切错了”这种很难现场重现的问题。5.3 版本管理与开源许可证落地用git记录每一次失败我们队从备赛第4个月开始强制用Git管理代码每人每天至少一个commitmessage必须写清楚“改了什么、为什么改”。听起来繁琐但比赛前一周你会庆幸有这套习惯——因为总会有“昨天还能跑今天怎么突然不行了”的时刻git diff一下就能定位是哪一行引入的问题。我们的仓库在Gitee上面向竞赛社区做了开源许可证选的GPL-3.0前面说过了。顺带分享一个经验不要只把最终代码开源要把“阉割版”和“失败版”也放进去。我们的docs/experiments/目录里存了四个失败的调试记录比如“摄像头自动曝光参数导致过曝丢线分析”“舵机中位漂移的三种解决尝试”等。后来有学弟反馈说这些失败记录比最终代码还有用因为避坑的经验往往是文档里最缺的部分。6. 实车调试的完整链路线从一次神秘抖动说起6.1 一个真实案例高速直道上的莫名正弦摆动备赛后期我们的车在高速直道上出现了一种奇怪的现象行驶时速到8m/s以上时车身会自发以大约1Hz的频率左右摆动幅度不大但肉眼可见且无法通过调低PID来解决。排查过程如下第一步排除算法问题。把位置环、角速度环全部旁路直接把舵机固定在正中央PWM值跑直道——仍然摆动。这证明不是控制参数的事而是机械或电气的问题。第二步检查机械部分。把车架起来空转车轮观察前后轮是否有跳动——前轮有一点轻微晃动但不足以解释1Hz摆动。换了一套新轮子问题依旧。第三步检查电源。用示波器同时测电池电压和舵机电源发现摆动频率和电池电压振荡频率完全一致。进一步追踪发现是舵机供电线路中那颗47uF电解电容和磁珠构成的LC滤波网络在特定负载电流下形成了低频谐振谐振频率刚好落在1Hz附近。舵机每做一个微小修正电源电压就波动一下波动又反馈回舵机电路形成了自激振荡。解决方案很简单在舵机电源滤波网络里再并联一颗470uF电解电容把谐振频率压到更低的频带同时等效增加阻尼振荡立刻消失。这个案例最终被我们写进了docs/experiments/因为它太典型了——高速工况下电源网络本身就是一个隐藏的“控制回路”你调PID调不动的时候不妨先看看电源纹波。6.2 调参顺序与手法从机械中位到高速刷圈的完整流程调参是智能车最神秘的环节但把它拆解成流程之后就没那么玄学了。我们队的标准流程是第一步机械调零。舵机中位、前轮束角、胎压、重心全部校准保证车辆在无控制指令时能沿直线滑行十几米不跑偏。第二步开环逻辑测试。先用手推车在不同速度下过固定的弯道记录车辆的“自然轨迹”了解机械特性的极限。第三步内环角速度环闭环。先让车辆原地旋转给不同目标角速度调内环参数让实际角速度快速平滑跟随目标值。第四步外环位置环闭环。低速1-2m/s跑简单弯道加入位置环输出观察修正是否平滑无震荡。第五步逐步提高速度。每次提高0.5m/s重新微调外环Kp和Kd。速度上去了系统相位裕度会下降往往需要降低Kp、提高Kd。这套流程每一步都有明确的完成标准不会越调越乱。比赛中很多队伍是“哪条赛道跑不好就调哪里”的随机搜索式调参那是最耗精力的做法。6.3 最容易翻车的五个点给下一届的警告回看整个备赛过程我整理了五个最普遍、最隐蔽的翻车点放在这里当“防坑手册”电池电压跌落充满电和接近没电时同样一组PID参数的表现会明显不同。我们的处理是在程序里根据电池电压实时缩放舵机PWM限幅和电机油门上限保证低电量时系统行为不过分劣化。摄像头曝光跟不上明暗变化赛场灯光一亮一暗的瞬间图像亮度突变二值化阈值来不及跟随容易丢线。我们后来给二值化阈值加了“前帧记忆”的阻尼大幅减少了闪烁。电磁信号在环岛附近的双峰误导前面提到了必须用状态机而不是单纯数值阈值去处理环岛。舵机中位随温度漂移跑几轮之后舵机发热中位脉宽会偏几个微秒千万别小看这几个微秒高速下就是持续单侧转向。我们每个调试小节前都会重新做一次舵机中位校准。排线接触不良赛车振动大杜邦线连接传感器极易松脱。我们在所有接头处打上了热熔胶同时用扎带做应力释放。赛场上因为一根线接触不良而崩溃的队伍太多了务必重视。7. 开发者的最后一件事这份开源目录还希望有人这样使用写到这该聊的基本都聊完了。最后想说的是开源目录的价值不在量级而在“被别人用起来”。我们最希望看到的使用方式是你读完了docs/里的设计笔记拿我们的方案当“靶子”然后做出比我们更合理的判断——比如“我觉得这里用摄像头为主更合适”“我觉得这个状态机还可以再加一个状态”。如果你在复现的过程中发现哪里和我们写的不一样优先相信你的实车测试结果然后欢迎提issue或者直接到仓库留言告诉我们。我自己在整个项目里最大的体会是“稳定”这东西不是靠某一个环节的超常发挥实现的而是靠所有环节都不出大差错堆积出来的。疯狂电路组尤其如此——你的电路可以不漂亮但必须可靠算法可以不激进但必须能在每一个弯道稳定复现。希望这份开源目录能帮你把踩坑的时间省下来花到更有意思的调试和优化上去。下一届赛场见。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑