ARTICLE DETAIL

资讯详情

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

智能车竞赛实战:从YOLO训练到ncnn部署与控制调参

智能车竞赛实战:从YOLO训练到ncnn部署与控制调参 简介这套资源是全国大学生智能汽车竞赛百度智慧交通组国二获奖方案涵盖完整源码、项目说明与全部工程资料适合竞赛参赛者以及高校人工智能、自动化、电子信息等专业学生用于课程设计、毕业设计或项目进阶。压缩包共220个文件以六十六个Python脚本和五十八个头文件为核心附带模型与参数文件、编译构建脚本、说明文档、配置文件及演示视频整体约174.67MB目录结构清晰便于定位代码、文档和数据。目前已有42人学习下载。内容经过严格测试可正常运行既有完整源码和设计文档也涵盖模型部署所需的参数文件、构建脚本及视频演示便于读者对照项目说明理解整体架构、核心算法与配置流程并可根据基础修改扩展直接用于相关课题、毕业设计或竞赛二次开发。1. 百度智慧交通组国二方案在解决什么问题发车信号落下之后模型车要在几十秒里连续应对红灯停车、绿灯起步、限速标志降速、斑马线前二次确认这几类事件。全国大学生智能汽车大赛里的百度智慧交通组核心不是把模型训练得多炫而是让一台搭载摄像头和有限算力主控的小车在实体沙盘上把“看到什么”和“该怎么做”这两件事连贯地接起来。国二方案意味着这条链路没有明显短板感知模型扛得住现场光照变化主控能在规定周期内给出控制量车体能停在距离停止线厘米级的位置上。这类方案对外发布时常见形态就是压缩包里层是源码、项目说明和全部资料三个部分。源码解决“怎么实现”的问题项目说明解释“为什么这样设计”全部资料则是调试过程里沉淀下来的数据集、标定表、训练脚本和实测记录。对于准备参赛的新队伍来说这是难得的起步模板不需要从零去试错主控选型、数据集格式和模型导出链路。对想要了解嵌入式视觉完整落地流程的开发者这份方案也展示了从训练框架到边缘设备推理的全套工程习惯。2. 赛道系统架构主控选型与数据采集2.1 规则倒推出来的算力需求百度智慧交通组的赛道元素很多红绿灯、限速标志、停止线、斑马线、施工绕行指示牌在不同组合下出现。近几届规则里元素识别和车控策略的耦合越来越紧单纯把车跑得快已经没有优势真正拉开差距的是识别后的行为切换是否准确。倒推算力需求时要先定一个目标帧率。我通常会要求感知链路在板子上跑出不低于 15 FPS 的处理速度原因在于车速 1.5 m/s 时每帧间隔约 66 ms车会前进约 10 cm如果帧率降到 8 FPS同样的距离会翻倍停车精度就很难再看下去。这个帧率压力会直接影响主控选型。沙盘场地小、元素固定不需要桌面级显卡那样的算力但也不能用裸机单片机直接跑神经网络。常见方案是在带 Linux 系统的嵌入式板卡上部署轻量目标检测模型再用串口或总线把结果发给下位机完成运动控制。选型时真正要对比的不是跑分而是三点模型能否在目标帧率下完成推理、板上能否方便地接入 USB 摄像头和 PWM 控制信号、散热和供电是否适配模型车的底盘结构。2.2 主控选型与传感器搭配这里给出三档常见的主控方案按控制板、算力特点、适配模型、供电与散热要求四个方面对比。选择任何一档都要结合队伍现有硬件不要只看峰值算力。主控方案算力特点适配模型供电与散热Jetson 系列Nano 及以上算力充裕带 GPU开发效率高YOLO 系列直接部署可跑 FP165V/4A 以上供电需要主动散热瑞芯微系列RK33xx/RK35xx带 NPUINT8 推理效率突出需要转 RKNN 格式校准环节较多功耗低散热压力小树莓派 4BCPU 推理算力中等只能跑轻量模型要降分辨率供电要求高高负载下易降频三种方案里Jetson 系列最容易把训练好的 YOLO 模型直接跑起来适合第一年参赛的队伍。瑞芯微系列一旦把 NPU 链路调通功耗和成本都比较理想但需要额外处理模型转换和量化校准前期投入时间多。树莓派 4B 不是不能跑而是要把输入分辨率降到 320x240 左右识别精度受限制通常只用于备赛早期的原型验证。嵌入式场景还需要考虑系统层面的配合。模型车上的板子启动时间要短外设要少我一般会裁剪内核模块并精简根文件系统只保留推理需要的运行库和摄像头驱动。这个环节虽然琐碎但能省出几秒的启动时间和可观的运行内存它和核心推理链路的源码是同等重要的交付物。2.3 摄像头角度与采集脚本摄像头安装角度直接影响数据质量和推理效果。前视摄像头俯仰角要保证画面中同时看到近处的车道线和远处的标志牌一般让画面下沿贴近车头前方 20 cm 处画面上沿看到 2 m 以外的区域。白平衡要锁定不要用自动白平衡否则现场灯光色温变化会让同一种颜色的表现来回跳。曝光时间也不要全自动优先保证运动模糊最小可以用固定短曝光再配合补光。数据采集脚本要解决两个问题按固定帧率保存图片并记录每帧的时间戳和保存路径。这样后续做离线回测时可以精确知道每一帧对应的车速和位置。import cv2, csv, time, os cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) cap.set(cv2.CAP_PROP_AUTO_WB, 0) # 关闭自动白平衡 save_dir ./capture os.makedirs(save_dir, exist_okTrue) meta_path os.path.join(save_dir, meta.csv) seq 0 with open(meta_path, w, newline) as f: writer csv.writer(f) writer.writerow([seq, ts_ms, filename]) while True: ret, frame cap.read() if not ret: break if seq % 3 0: fname f{seq:06d}.jpg cv2.imwrite(os.path.join(save_dir, fname), frame) writer.writerow([seq, int(time.time() * 1000), fname]) cv2.imshow(preview, frame) if cv2.waitKey(1) 0xFF ord(q): break seq 1 cap.release() cv2.destroyAllWindows()脚本里seq % 3 0的意思是每 3 帧只保存 1 帧用时间戳记录真实间隔避免存下大量重复画面。采集时让车在赛道上慢速跑几圈而不是停在原地拍因为后处理的推理目标主要是运动状态下的图像。关闭自动白平衡很关键它能让标注数据集的颜色一致性更好这也是赛道实景和普通拍照场景差异最大的地方。2.4 标注规范与增强策略标注工具的选用没有绝对标准常见做法是 labelImg 用来画矩形框labelme 适合需要分割标注的场景。就红绿灯、限速标志、锥桶这些矩形目标而言labelImg 效率更高输出 YOLO 格式的 txt 文件每行是类别 x_center y_center width height坐标都是归一化后的值。数据集目录按 images 和 labels 分开类别顺序写在一个 data.yaml 里这样训练脚本不会读错标签。增强策略要克制不要一上来就上大规模仿射变换和随机擦除。沙盘场地本身是固定环境模型要适应的是不同时间的光照差异、摄像头安装角度微调而不是复杂自然场景。我一般只做亮度扰动、小角度旋转和轻微缩放mosaic 增强可以开但不要加太多随机颜色扰动否则红绿灯这类高饱和目标的颜色特征会被冲淡。3. YOLO 模型训练到嵌入式部署的完整链路3.1 轻量化模型的取舍目标检测模型里YOLO 系列在竞赛场景中使用最多。v5n 和 v8n 两个轻量版本在百度智慧交通组的方案里都常见差距体现在解码结构和部署难度上。v5n 的输出层直接给出坐标和置信度转 ONNX 再到 ncnn 的流程非常顺。v8n 的检测头是解耦结构精度略高但导出和转换时多一步输出层处理部署坑也多一些。如果队伍第一次进这个赛道我会建议直接用 v5n。原因是参赛方案的完整度更依赖链路顺畅而不是那一点精度提升。如果把大量时间耗在模型转换的排错上留给控制调参的时间就会被压缩。模型选型的核心原则是精度达到元素识别要求即可剩余算力要留给帧率和控制余量。3.2 数据集组织与训练命令数据集准备好后先写数据配置文件再启动训练。下面是一个典型的smart_traffic.yaml里面定义了训练集和验证集路径以及类别名称。path: /home/user/smart_traffic train: images/train val: images/val nc: 5 names: 0: red_light 1: green_light 2: speed_limit 3: crosswalk 4: cone训练命令用 YOLOv5 的常规入口主要参数是输入尺寸、批次大小和训练轮数。python train.py \ --data smart_traffic.yaml \ --weights yolov5n.pt \ --img 640 \ --batch-size 16 \ --epochs 120 \ --device 0--img 640会带来更高的检测精度但对嵌入式部署不太友好因为输入分辨率直接决定推理耗时。如果主控算力一般训练时用 416 甚至 320部署时就用同样尺寸不要训练和部署不一致。--epochs 120对赛道元素这种目标数量少、类别清晰的数据集来说足够再多反而容易过拟合。训练完成后看验证集上的 mAP 和每类别的 PR 曲线重点观察 speed_limit 和 crosswalk这两类容易和小目标问题混在一起。3.3 ONNX 导出与 ncnn 转换嵌入式侧我一般用 ncnn它是一个轻量推理框架没有繁重的运行时依赖很适合裁剪过的 Linux 环境。转换链路是先产 ONNX再转 ncnn最后做可选量化。这里给出一套完整的命令流程。# 第一步导出 ONNX python export.py --weights runs/train/exp/weights/best.pt --include onnx --img 640 # 第二步简化计算图去掉多余的 reshape 和 transpose python -m onnxsim best.onnx best_sim.onnx # 第三步转换为 ncnn 格式 onnx2ncnn best_sim.onnx model.param model.bin # 第四步优化 ncnn 模型融合算子、调整内存布局 ncnnoptimize model.param model.bin model_opt.param model_opt.bin 0每一步都有明确的检查方式。导出 ONNX 后先用 Netron 看一眼结构确认输出层的输出名能与后续代码对应。onnxsim 这一步不能跳YOLO 的原始计算图里有大量冗余的转置操作简化后 ncnn 转换更流畅。onnx2ncnn 执行完会打印每一层的转换状态如果有 Unsupported 层要先回 ONNX 阶段解决不要在 ncnn 阶段硬改参数文件。ncnnoptimize 的最后一个参数 0 表示 FP321 表示 FP16卷积层多的模型选 0 更稳。3.4 量化校准与 INT8 精度损失控制算力吃紧的时候INT8 量化是有效的提速手段。ncnn 提供量化工具需要先准备校准图片再生成校准表文件最后用工具量化模型。校准图片建议从真实赛道采集覆盖不同距离的红绿灯、限速标志以及不同角度的斑马线。数量不追求多500 张左右就够了但必须是模型在赛道上真正会遇到的画面。# 生成校准表 ncnn2table model_opt.param model_opt.bin calib_list.txt calib.table mean[0,0,0] norm[0.003921,0.003921,0.003921] shape640,640,3 pixel0 thread4 methodkl # 用校准表完成 INT8 量化 ncnn2int8 model_opt.param model_opt.bin model_opt_int8.param model_opt_int8.bin calib.table校准时的mean和norm必须与训练时的预处理一致。YOLOv5 默认归一化方式是除以 255所以写成norm[0.003921,0.003921,0.003921]。INT8 量化后红绿灯这类大面积色块损失不大反倒是路面上的字符和锥桶这类小目标容易出现漏检。量化结束后不能只看总体 mAP要单独跑一段录制好的赛道视频逐帧确认每个元素的检测框有没有断裂。4. 控制策略与实车调参中的关键细节4.1 三层控制状态机感知输出的只是检测框车该怎么动还需要控制层决定。状态机是控制层最常用的组织方式把赛道事件拆成几个离散状态每个状态对应一组控制行为。状态触发条件控制行为normal无特殊元素车道线清晰按设定速度循迹行驶approach检测到限速标志或停止线目标速度降档接近停止线stop红灯或停止线前刹车并保持静止run绿灯亮起或停车计时结束恢复速度并继续循迹avoid锥桶或施工绕行标志出现降低车速并切换偏移量状态切换需要明确的条件和超时保护。stop状态不能只要检测不到红灯就立刻退出要配合计时器和连续帧确认否则前车遮挡或检测抖动会让小车在路口犹豫。状态机的代码结构要清晰方便在车场调试时快速改阈值。4.2 转向 PID 与速度 PID 分离调参运动控制里转向和速度两个环的响应特性不同必须分开处理。转向环的目标是让车体横向偏差收敛速度环的目标是让车速按状态机的期望值变化。PID 参数初值可以参考下表再按实车表现微调。控制环PID调整优先级转向环1.2 以下先调00.05 以下先加先 P 后 D速度环0.8 左右0.01 以下0先 P 后 I调转向环时先只给 P 值看车在直道和缓弯上的表现。P 太小车会外切P 太大车会出现横向摆动。之后加很小的 D 值用来抑制摆动。I 项在转向环里基本去掉因为赛道不存在固定累积偏差。速度环的 I 项只在停车状态才有意义用来抵抗下坡时的溜车。实车调参的节奏是每改一个参数跑完整一圈记录姿态和停车位置不要连续改多个参数。4.3 刹车距离与执行延迟计算停车精度是国二方案里最能拉开差距的环节。刹车距离公式很简单s v * t_response v^2 / (2a)。v是当前车速t_response是从图像采集到控制命令生效的总延迟a是减速度。总延迟包含推理耗时、串口或总线传输耗时、舵机响应时间三部分实测通常占 0.1 到 0.2 秒。以车速 1.5 m/s、总延迟 0.12 秒、减速度 2 m/s² 计算刹车距离约 0.74 米。这意味着限速标志或红绿灯检测必须在 0.9 米以外就给出信号否则就算检测到也来不及停车。很多队伍在识别上表现不错但停车每次都过线问题就出在检测距离和刹车距离没有匹配。控制层要根据当前车速动态计算刹车点不要用一个固定距离触发刹车。4.4 遮挡与抖动处理检测框在连续帧里出现抖动是常态直接作用到转向值会让车头摆动。常见处理方式是对检测框的中心横坐标做一阶低通滤波让控制量变化更连贯。smooth_x 0.7 * smooth_x 0.3 * raw_xsmooth_x是滤波后的横向位置raw_x是当前帧检测框中心的横向坐标。0.7 和 0.3 是平滑系数系数越大越跟随原始值越小越平缓。这个系数不能过大否则高速转向时会迟滞导致车已经压线才给出修正。红绿灯和限速标志这类状态型元素不能直接套用滤波改用连续 3 帧一致再切换状态避免单帧误检造成急刹车。检测丢失时不要立刻沿用上一帧结果要结合车速推算当前应处位置否则静止物体检测丢失会表现为莫名其妙的加速或减速。5. 复现一份参赛工程目录规范与离线回测5.1 工程目录与源码组织方式一份可复现的参赛工程目录结构能直接体现调试思路。源码、数据、脚本和资料分开各自独立同时用 README 把目录间的依赖关系写清楚。常见的工程布局如下。smart_traffic/ ├── src/ # 嵌入式侧源码 │ ├── camera/ # 图像采集与预处理 │ ├── detect/ # ncnn 推理封装 │ ├── control/ # PID 与状态机 │ └── plan/ # 行为决策 ├── data/ │ ├── raw/ # 原始采集视频和图片 │ ├── label/ # 标注文件 │ └── calib/ # 量化校准图 ├── weights/ │ ├── fp32/ # FP32 ncnn 模型 │ └── int8/ # INT8 量化模型 ├── scripts/ # 训练和转换脚本 ├── notes/ # 调参记录和问题清单 └── README.mdsrc下的四个目录对应感知和控制的四个环节接口要清晰不要把推理结果直接写在主循环里。notes目录容易被忽略但实车调试时它是效率工具。每次调参后记录环境光照、车速、PID 参数和停车误差比事后翻聊天记录要可靠得多。5.2 离线回测用录制数据代替实车每次跑实车都要花时间布置场地、充电和复位效率很低。我会在实车调试时同步录制视频和控制日志回到电脑上用录制数据做离线回测。python scripts/offline_eval.py \ --video data/raw/lap01.mp4 \ --model weights/fp32/model_opt.param \ --weights weights/fp32/model_opt.bin \ --output logs/lap01_eval.csv回测脚本逐帧跑模型输出每帧的检测框、置信度和状态机状态。检查时要重点看三件事标志牌从出现到被检测的帧数是否足够、停车状态是否在预期位置触发、红绿灯切换状态时有没有抖动。离线回测发现的问题要在电脑上先处理完再上实车验证这样每次实车都能集中在真正需要现场调的部分。5.3 从国二往前走量化对比与数据迭代国二方案的能力上限取决于优化深度。一个值得投入的方向是 FP32 与 INT8 模型的对比评估。同样一段视频分别跑 FP32 和 INT8 模型对比检测框中心和置信度差异能直接体现量化损失对控制层的影响。如果发现 INT8 在某个距离上漏检就回到校准集补充该距离的图片重新生成校准表。另一个方向是把每天实车的新数据录制下来挑选其中有代表性的画面补充进训练集。赛道光照、标志牌角度、摄像头安装位置都会随时间变化数据集不更新会让模型逐渐退化。把新数据和老数据混合后重新训练再走一次导出和量化流程整个链路就形成了迭代闭环。下一次调参时建议先从刹车距离曲线看起它通常能比跑圈时间更快暴露感知与控制的匹配问题。本文还有配套的精品资源点击获取
返回列表