完全模型组智能车方案:从视觉识别到ROS控制的完整实践
简介:来自湖北工业大学蓝电YYDS Car队的第十七届全国大学生智能汽车竞赛完全模型组完整参赛工程包,面向智能车竞赛参赛者及嵌入式开发者,可复现车队的工程组织与算法实现。压缩包共539个文件,大小约69.67MB,以C/C++源码为主,含262个h头文件、150个c源文件及若干hpp/cpp实现,配套xml工程配置、cs/prefs等IDE设置、jpg/png图像、mp4演示录屏、md说明文档及代码工作区配置,覆盖从底层驱动到上层控制策略的完整链路。已有881人浏览学习。通过本包能系统查看车队在赛道元素识别、控制策略、调试脚本与工程管理上的实际做法,并参考其模块划分和关键函数实现,对备赛或入门MCU开发都有很好的借鉴意义。 每年全国大学生智能汽车竞赛结束之后,总会有一批优秀的工程文件在校园里流传。“完全模型组”是这几年关注度很高的赛项,它和传统的竞速组、直立组最大的区别在于:模型车要面对的不只是固定的赛道元素,而是更像一个简化版的“自动驾驶小车”,需要在复杂场景里完成识别、规划、控制这一整套闭环。第十七届比赛我们队做的是完全模型组,最后拿到的成绩还行,车队代号“蓝电YYDS Car”。这篇博文我就把这套方案从设计思路到具体落地,再到比赛现场踩过的坑,完整整理一遍,给后面准备参赛的学弟学妹,以及想从零开始做视觉智能车的朋友一个参考。
这套系统最核心的部分,并不是某一个传感器或者某一个算法,而是“感知—决策—执行”三者之间的耦合关系。很多人一开始把精力全放在模型训练上,结果车跑起来却东倒西歪,或者识别很准但速度上不去。我先把我们队的整体设计思路拆开讲清楚,这样你后面看代码、调参数时才能理解为什么要这么做。
1. 整体设计思路与赛题拆解
1.1 完全模型组到底在比什么
完全模型组这个名称里的“完全”,指的是车模本身使用官方推荐的模型车平台,而不是自己搭的车架,硬件限制相对固定。但它和传统摄像头组不一样,赛道里不仅有锥桶、路障、横断路障,还有十字路口、环岛、停车区这些元素,形状和颜色也比普通赛道复杂得多。简单说,赛题要求小车具备一次完整的“感知—决策—执行”能力,非常接近真实自动驾驶的简化场景。
我们队第一件事就是确定技术路线。官方推荐了基础平台,但软件框架和算法完全自主选择。有的队用深度学习直接做端到端控制,我们考虑过,但最终没有采用。理由是端到端固然酷,但可解释性差,比赛现场出了问题很难快速定位。我们最终选择了传统视觉识别 + 规则决策 + PID控制为主,同时引入轻量级神经网络辅助做元素分类。这样既保证了速度,又保证了调试效率。
1.2 为什么选ROS作为软件骨架
很多人觉得ROS太重,跑在嵌入式板子上性能跟不上。但完全模型组不是纯单片机电控,我们可以使用性能更强的计算平台。我们选ROS,核心原因是它天然提供了模块间通信的机制,摄像头节点、识别节点、决策节点、控制节点可以分别独立开发、独立测试。个人体会是,比赛这种多人数月协作的场景,模块解耦的价值远远大于那一点点通信开销。
通信中间件选好之后,整个系统的数据流就很清晰:摄像头采集图像,送入识别节点;识别节点输出目标列表和自身位置估计;决策节点根据这些信息生成目标速度与转向角;控制节点最终把指令下发到底盘驱动。每个环节都有独立的调试工具,这一点在后期的实车调参中帮了大忙。
2. 核心硬件选型与软件架构解析
2.1 算力平台与传感器选择了什么方案
计算平台我们用了常见的AI边缘开发板,属性上就是一块带GPU/NPU的小型电脑,性能足够跑轻量级神经网络。摄像头方面,一开始试过双目方案,后来发现比赛的场景深度信息并不一定要靠双目获取,单目加合理的几何假设就够用,于是最后用了一颗全局快门彩色摄像头,视野更稳定,不会因为车体震动出现严重的果冻效应。
有一个细节很多人会忽略:摄像头安装高度和俯仰角。我们的车把摄像头装到离地面大约35厘米的高度,俯仰角大约朝下15度。这样既能看到近处的车道线,也能兼顾两三米外的锥桶。如果装得太低,近处元素畸变严重;太高的话,远处目标太小,识别模型容易漏检。这个参数是我们反复标定后确定的,不同车架不同安装位置都要重新调整。
2.2 识别模块用轻量网络替代大模型
最开始我们直接拿YOLOv5s训练,精度确实不错,但在边缘设备上实时性有点紧张。后来换成了轻量化的检测网络,并且做了通道剪枝和INT8量化,推理帧率从不到20FPS提升到30FPS以上,准确率几乎没掉。我的建议是:比赛场景目标类别少、背景相对固定,完全不需要上大模型,轻量模型加数据增强才是正确方向。
关于数据集的构建,我们不是单纯依赖官方给的样本,而是大量采集了现场赛道在不同光照、不同角度下的图像。这个工作量很大,但非常值得。最终数据集中约七成来自自家场地实拍,三成来自网络公开数据集增强,经过人工清洗和标注,训练出来的模型泛化性明显比只用通用数据集好很多。如果你要复现,一定要记住一个原则:训练数据里必须包含你们实际场地光照条件的图像,否则赛场上会很惨。
3. 实操过程与核心环节实现
3.1 车道线检测与循迹实现细节
车道线检测是实现稳定跑图的基础。我们采用的方法是:图像预处理(灰度化、高斯模糊、边缘提取)→ 感兴趣区域裁剪 → 透视变换 → 滑动窗口搜索车道线像素 → 拟合二次多项式。
透视变换是花费时间最多的环节。变换矩阵选哪些点,直接决定后续曲线拟合的准确性。我们选的是相机画面中近处两条车道线的四个边界点,映射到一个固定宽高的俯视图中。调试时我习惯用调试工具实时显示变换前和变换后的图像,叠加车道线拟合结果,这样能快速确认矩阵是否准确。最终控制时,我们根据拟合曲线计算当前车辆相对车道中心的横向偏差和航向偏差,作为PID控制器的输入。
一个小技巧:PID参数不要一开始就在整车上调,先架起后轮,让车悬空,只让转向机构响应,观察是否出现振荡。但要注意,这个空载状态和地面状态差异很大,悬空微调只能解决方向响应问题,最终的P、I、D参数还是一定要放到地面上实际跑。地面摩擦和轮胎抓地力对转向动态影响极大,跳过这个步骤会多走很多弯路。
3.2 元素识别与减速决策策略
比赛场景里最常见的三个元素是锥桶、路障和横断路障。我们的策略不是对每个元素都做完全不同的处理,而是统一成“障碍物类目标 + 减速标志类目标”两种行为类型。
锥桶用检测框中心坐标加宽高信息,估算它的距离;路障和横断路障因为形状统一,直接用分类网络区分。决策逻辑用状态机实现:正常循迹状态 → 检测到障碍物 → 进入减速状态,同时根据目标在图像中的横向位置决定微小避让方向 → 通过障碍物后恢复循迹状态。这里要特别注意的是,减速不能太猛,否则车身重心转移会导致转向不足,尤其是在连续弯道遇到路障时,极易冲出赛道。
我们调试中发现,针对路障的减速距离,经验值大约在1.2米到1.8米之间比较合适。太早减速影响圈速,太晚减速容易来不及。这个参数和最高车速强相关,如果最高车速设到3m/s以上,减速距离就要相应拉长,需要反复实测。
3.3 环形赛道与十字路口的特殊处理
环岛和十字路口是很多队伍翻车的地方。我们采用的方案是维护一个简单的赛道拓扑逻辑:通过识别到的元素类别和车体当前的姿态,判断当前处于十字路口还是环岛入口,然后切换对应的转向策略。
环岛策略的难点在于出口的判断。我们利用环岛内部斑马线区域作为出口信号,当检测到斑马线出现并持续数帧后,才认为可以出环。这里必须有帧数确认机制,因为单帧噪声会导致提前出环。我们设置的是连续5帧检测到出口标志才动作,实测下来可靠性很高。
十字路口则简单一些,主要靠车身磁罗盘数据和陀螺仪积分来判断大致方向。但要注意,陀螺仪零漂会随时间累积,长时间跑下来会偏,所以我们的做法是每次检测到起跑线时,用起跑线的方向做一次全局角度校正。这个策略保证三圈以上的长跑测试方向不会漂移。
4. 常见问题与排查技巧实录
4.1 模型训练准但实车识别差怎么办
这个是最常见的问题,也是我们第一版方案栽过的坑。训练时测试集准确率高达95%,到了实际赛道上,掉到70%都不到。原因基本出在数据分布不一致上。解决办法:一是增加现场实拍数据占比;二是做数据增强时加入亮度扰动、高斯噪声、运动模糊和随机裁剪。特别是运动模糊,因为赛道里高速运动场景很多,没有模拟过模糊的模型动态识别能力确实差很多。
另一个容易被忽略的细节是摄像头白平衡。不同时间段的自然光色温差异非常大。我们后来在代码里加了自动白平衡,并且模型训练时把RGB通道做了归一化增强,模型的色彩鲁棒性一下子提升了很多。
4.2 实车运行中偶发抖动和异响
车跑起来有时候会出现方向盘小幅抖动,车轮部位嘎吱响。这类问题通常不在算法,而在机械结构。先是检查转向机构球头有没有松动,然后是舵机臂和拉杆的虚位。模型车本身精度有限,跑久了螺丝很容易松动,每次训练前扭一遍关键螺丝是基本操作。
如果机械没问题,那大概率是PID中D项过大。D项过大的典型表现是高频小幅振荡,尤其在直线高速段格外明显。我们把微分项从0.8降到0.3左右,配合一点低通滤波,抖动立刻就好了很多。不要迷信拉高D能提升响应速度,比赛车对稳定性要求远大于响应速度。
4.3 算力占用过高导致偶发卡顿
边缘设备的算力有限,识别、决策、通信、显示同时跑,很容易出现卡顿,卡顿几帧对控制来说就是灾难。我们最后做了一次彻底的软件瘦身:识别节点和决策节点之间的图像传输只传压缩后的JPEG,不再传原始BGR图像;显示窗口只在调参模式开启,比赛模式全部关闭;模型推理时锁定CPU和NPU核心,避免被其他进程抢占。
最终实车运行时的CPU占用率从85%降到了40%上下,帧率稳定在30FPS。如果你也遇到卡顿,先不要急着换硬件,把系统里每个节点的耗时打点统计一下,往往能发现某个节点在疯狂占用资源。
5. 从备赛到比赛的几个关键时间节点
5.1 备赛前两个月该完成什么
备赛节奏很重要。我强烈建议,赛前两个月的节点,车至少能稳定完成一圈完整赛道,哪怕速度很慢。因为后面所有优化都是建立在“你已经有一台能跑完全程的车”这个基础之上的。很多队伍前两个月还在反复调识别准确率,导致后面没有时间做长距离稳定性测试,结果比赛时跑两圈就出问题。
前一个半月重点做元素的专项测试,把每个元素的识别阈值、距离参数都记录成表格。这个表格非常有用,比赛前可以直接对照检查,不会因为紧张忘记参数。
5.2 比赛现场的快速应急策略
现场环境往往和训练场地不同,光线、地毯材质、赛道摩擦都会变。我们到赛场后的第一步不是急着跑,而是携带电脑在赛道边采集一圈图像,用当天数据快速做一次模型微调,只训练10到20个epoch就够了。这个方法帮我解决了现场光线不适应的很大一部分问题。
另外,现场一定要带齐备用螺丝、扎带、热熔胶和充电器。比赛检修时间往往很短,现买根本不现实。还有,赛前把所有配置文件备份到U盘和网盘,曾经亲眼见过有队伍电脑坏了、配置全丢,只能临时重新调参的情况。
5.3 团队协作与代码版本管理
这个说多了都是泪。我们队早期没有用代码版本管理,各改各的,结果有一次把别人调试好的参数覆盖了,找了一整天才恢复。后来强制使用Git管理,每人的分支独立,合并前必须跑一遍仿真或场地测试。配置文件和参数文件也纳入版本管理,谁改了什么东西一清二楚。
“蓝电YYDS Car”这个名字其实也寄托了我们的心态——年轻人做技术,要有点自嘲和趣味,但追求极致的决心不能少。
6. 给小白的入门路线建议
如果你是完全零基础,不要一上来就想着深度学习、端到端。我的建议路径是:先把PID调好,让车能沿着一条直线稳定跑;再做一个最简单的OpenCV循迹,让车能在白色背景黑色线条的模拟跑道上跑起来;然后再加入检测网络,最后再上ROS完整架构。
很多人觉得前面步骤“太低级”,直接跳到最后一步,结果发现基本概念都不清楚,出了问题根本无从下手。技术这东西,很难跳级,每层都有每层的坑,老老实实走一遍反而是最快的路径。
第二个建议是,一定要学会看懂调试曲线。我们的上位机软件可以实时显示图像检测结果、拟合曲线、PID输出量和速度反馈。建议所有调参都基于数据而不是“感觉”。我自己见过太多人盲目调参,调了一个下午,最后发现是电机驱动板供电不足,根本不是软件问题。先检查硬件,再调软件,这是基本的工程素养。
7. 结语:一些实际体会
我做这个项目最大的感触是:比赛成绩固然重要,但更重要的是它逼着你把“能跑”变成“跑得稳”,再把“跑得稳”变成“出了问题三分钟能定位到具体模块”。这个工程化思维,是课堂上学不到的。你可能会在深夜十一二点还在调车道线、测阈值,会在比赛前一天对着一个莫名其妙的bug崩溃,但等它终于稳定跑完全程的时候,那种成就感确实非常真实。
最后再分享一个小经验:每一次对参数或者代码做出修改,不要只记录“改了什么”,要记录“为什么改”和“改完以后效果怎么样”。这份修改日志,不仅帮你避免重复踩坑,还能在答辩时提供非常清晰的技术演进脉络,这也是评委很喜欢看到的东西。
希望这篇整理能帮到在准备完全模型组的你。我们赛场见。
本文还有配套的精品资源,点击获取
