ARTICLE DETAIL

资讯详情

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

Autoware 1.14与YOLO-V3携手:自动驾驶感知系统搭建全攻略

Autoware 1.14与YOLO-V3携手:自动驾驶感知系统搭建全攻略 在现在的自动驾驶与智能车项目里要跑通一套完整的感知链路大家普遍会听到各种新名词。但我今天想聊聊一个从工程落地角度看仍然特别耐打的组合Autoware 1.14 摄像头 YOLO-V3。很多朋友刚接触这个组合时第一反应是“这都老掉牙了怎么不上YOLOv8或者新框架”。但真正做过本地化部署、传感器融合、甚至实车调试的人会明白Autoware 1.14 基于 ROS1它的生态极其稳定社区里各种疑难杂症的解决方案一搜一大堆这比追逐最新版本带来的“依赖崩盘”划算得多。更重要的是YOLO-V3 的权重和部署逻辑非常透明尤其是在嵌入式或普通 GPU 上跑深度推理时它的计算开销和帧率稳定性能给你非常清晰的心理预期特别适合用来搭建第一套能实际跑起来的多传感器融合 Demo。这篇文章我打算从选型逻辑、环境搭建、模型部署、坐标变换到联合标定完整走一遍我在实际项目中把 YOLO-V3 接进 Autoware 1.14 的流程。内容里会夹杂大量的“我踩过的坑”和“直接抄作业”的配置目标就是让一个刚起步的开发者能在自己的 Ubuntu 18.04 电脑上把摄像头画面里的车辆、行人框稳稳当当地投到 RViz 的地图上。1. 方案选型为什么 Autoware 1.14 配 YOLO-V3 还是一把好手先别急着抬杠我先把场景说清楚。我这里谈的是学习研究、课题验证和中小型智能车的感知原型开发。1.1 算力与稳定性的最佳平衡点很多人在网上搜“YOLO 目标检测”会看到各种版本的对比。YOLOv5 和 YOLOv8 确实强但它们的部署往往依赖 PyTorch 环境后续转到 C 后端要过一遍 LibTorch 或 ONNX Runtime。而 YOLO-V3 在 OpenCV 的 DNN 模块里是“原生支持”的这意味着你可以绕开庞大的训练框架直接加载yolov3.weights文件就能推理。配合 Autoware 1.14 的节点结构推理过程可以被封装成一个独立的 ROS 节点通过话题Topic和 Autoware 的主逻辑交互。在实车或者只有一块 1050/1060 显卡的工控机上这样的组合能把 CPU 和 GPU 负载控制得非常稳定很少会出现因为某一个帧丢失导致整个感知链路崩溃的情况。1.2 ROS1 生态下的得天独厚Autoware 1.14 锁定在 ROS Melodic 发行版这是一个纯 ROS1 环境。相比 ROS2 的 DDS 通信ROS1 的话题通信机制虽然在实时性上限制多一些但对于教育科研和低速园区车来说调试起来极其方便。你甚至不需要完全理解复杂的 QoS 策略只需要rostopic echo就能看到目标检测框的数据在流动。再加上现在热词里高频出现的“相机雷达联合标定工具”Autoware 1.14 自带的calibration_camera_lidar包就是专门为此设计的。如果你后续想接激光雷达YOLO 的 2D 检测框通过标定好的矩阵投影到点云上整个管线是非常顺滑的。1.3 我对当前“热词”环境的一点判断我看到有人还在纠结“macs仅5mb的目标检测模型”或者“多模态目标检测”这些领域确实代表了未来方向。但在自动驾驶的车辆检测Vehicle Detection这个具体场景下YOLO-V3 的召回率特别是在黄昏或光照变化时配合高帧率摄像头依然能满足绝大多数课题需求。而且只有把经典的Darknet53主干网络学明白了你才能深刻理解后来那些轻量化模型比如 YOLO-Fastest到底优化了什么参数。先跑通整体框架再去追求性能极限这是我多次实战后最深的体会。2. 环境搭建与摄像头驱动接入别让采集端卡住整个项目因为很多朋友是在Ubuntu 18.04上装 Autoware我默认大家已经按照官方文档编译好了 Autoware 1.14如果这一步没完成先不要往下进行因为这个过程对网络和依赖库的耐心要求极高也是劝退很多人的第一座大山。2.1 摄像头选型与 V4L2 驱动细节在智能车或者机器人平台上最常见的摄像头就是普通 USB 摄像头比如网上一堆的免驱摄像头和树莓派 CSI 摄像头OV5647。我这里强烈推荐在调试初期首选 USB 摄像头理由很简单即插即用驱动好找。你需要在 Ubuntu 下确认摄像头设备号。输入ls /dev/video*一般会出现/dev/video0和/dev/video1这里通常一个是采集节点一个是元数据节点。如果你调用了错误的节点画面会出现灰屏或者死机。为了采集画面Autoware 的感知模块需要标准的 ROS 图像消息。我用的是 Autoware 1.14 中自带的cv_camera或者国内常用的usb_cam。这里有个关键参数要特别注意在usb_cam.launch里务必对相机做如下配置以保证 YOLO 输入清晰launch node nameusb_cam pkgusb_cam typeusb_cam_node outputscreen param namevideo_device value/dev/video0 / param nameimage_width value1280 / param nameimage_height value720 / param namepixel_format valueyuyv / param namecamera_frame_id valuecamera_link / param nameio_method valuemmap/ /node /launch注意分辨率不要直接调到 1920x1080除非你的 USB 带宽完全够否则 YOLO 推理节点会疯狂丢帧。2.2 海康/宇视等网络摄像头的取流接入如果你的项目里用的是网络摄像头IPC比如热词里提到的海康威视或者宇视流程会稍有不同。这些摄像头通常利用 RTSP 协议输出视频流。不需要额外安装 SDN 或私有的 SDK直接用ffmpeg或gstreamer把 RTSP 流转成 ROS 话题就行。这里分享一个我常用的最稳定方案用ffplay的兄弟工具v4l2loopback将一个 RTSP 流伪装成本地摄像头或者更推荐用gscam直接在 ROS 的 launch 里指定 RTSP 地址launch node pkggscam typegscam namegscam_raw param namecamera_name valuehikrobot_cam / param namecamera_info_url valuepackage://gscam/examples/calibration.yaml / param namegscam_config valuertspsrc locationrtsp://admin:password192.168.1.64:554/Streaming/Channels/101 latency100 ! decodebin ! videoconvert ! video/x-raw, formatBGR ! appsink / remap fromcamera/image_raw tocamera/image_raw / remap fromcamera/camera_info tocamera/camera_info / /node /launch这样处理最大的好处是你在业务层完全感受不到网络摄像头和本地 USB 摄像头的区别后面的 YOLO 推理节点只要订阅同一个话题名就行。我额外提醒一句RTSP 的延时受网络环境影响巨大在实车本地测试时尽量使用千兆交换别把手机热点当主力网络设备。3. YOLO-V3 权重迁移与模型部署把检测框变成 ROS 消息在 Autoware 1.14 里官方其实内置了一个vision_darknet_detect包可以直接读取 YOLO 的 cfg 和 weights。但我们为了灵活性经常单独写一个节点不仅为了输出检测框还要把置信度、类别信息全部重新组合。3.1 权重文件的获取与 Micro 变换yolov3.weights官方是编译好的 COCO 数据集权重80 类。如果你的智能车只关心“人person”、“自行车bicycle”、“汽车car”等少数几个类别建议你要么直接动态过滤话题数据要么用 Darknet 源码跑一遍自己的数据集。我们一般部署时把.cfg和.weights文件放到$(find your_pkg)/config/下。YOLO-V3 在 OpenCV DNN 模块里的前向推理函数需要注意关于图像尺寸的输出矫正// 创建网络 cv::dnn::Net net cv::dnn::readNetFromDarknet(cfg_path, weights_path); net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU); // 无GPU时用CPU cv::Mat blob cv::dnn::blobFromImage(frame, 1/255.0, cv::Size(416, 416), cv::Scalar(0,0,0), true, false); net.setInput(blob); std::vectorcv::Mat outs; std::vectorcv::String outNames net.getUnconnectedOutLayersNames(); net.forward(outs, outNames);核心的 YOLO 框解析逻辑我在这里也一并给出你需要提取出 center_x, center_y, width, height。// 解析 YOLO 层输出 float* data (float*)outs[i].data; for (int j 0; j outs[i].rows; j, data outs[i].cols) { float confidence data[4]; if (confidence confThreshold) continue; // 找出最大分数对应的类别 // 计算框坐标 // 代码略注意原始坐标是归一化值这里建议乘上原图的 width 和 height }3.2 将目标框封装成 Autoware 可识别的消息类型Autoware 1.14 里的目标列表消息类型是autoware_msgs::DetectedObjectArray。你要把检测到的每个框都填充到这个结构里这一步是后续做传感器融合和可视化绕不开的关键环节。在实践中我建议直接把camera_link坐标系的框填充进消息并打上检测得分标签autoware_msgs::DetectedObject object_msg; object_msg.label car; // 或 person object_msg.score confidence; object_msg.color.r 1.0; object_msg.color.b 1.0; // 关键在于把 bbox 的像素坐标转成相机坐标系下的相对方位角简单视觉传感器可简化这里我多说一句关于“为什么”的逻辑。如果你只是做被动视觉测距那框只要在图像上显示就好但如果你要融合雷达就必须要知道目标在空间里的真实方向。在 YOLO 只给 2D 框的情况下我们就做一个假设目标中心点的像素坐标通过相机内参可以转换为相机坐标系下的水平角atan((u - cx)/fx)。如果后续你用激光雷达聚类出来多个候选目标这些候选目标也会被投影到图像平面再和 2D 检测框做 IOU 匹配。这样纯视觉的 YOLO 目标检测就能为融合节点提供强有力的 Class 和置信度约束。4. 相机与雷达联合标定这两套坐标系换算过来别搞混说到“联合标定”很多人第一反应就是矩阵运算很头痛。在 Autoware 1.14 中提供的calibration_camera_lidarGUI 工具让这件事变得形象了很多。但它也有一个致命的逻辑陷阱我在这里特别强调。4.1 标定流程的逐步拆解第一步你需要把棋盘格打印出来至少要 8x6 的角点纸张必须贴在硬纸板上不能有褶皱。 第二步打开标定 GUI。它会同时显示激光雷达的点云俯视图和相机的图像你需要在点云内框选棋盘格的大致区域然后点击“捕捉”。 第三步也是最重要的细节必须进行多次采集并且要在不同距离2米、5米、8米和不同角度偏左、偏右、上仰、下俯。因为 YOLO 检测中远景车辆的像素映射对平移矩阵的误差极其敏感单一组正面标定数据根本不够用。标定最后会输出一个calibration.yaml文件里面包含相机内参矩阵、畸变系数以及从相机到激光雷达的变换矩阵。这里有个 Autoware 1.14 常见的坑输出的矩阵是 Lidar 到 Camera 的变换矩阵但你在做点云投影的节点里面其实需要的是 Camera 到 Lidar 的逆矩阵。这正好解释了为什么很多新手在 RViz 里看到点云和图像完全对不上就是因为取反了方向。4.2 从像素到空间的投影实操当检测到一张图里有一辆车的 bbox 时我们如何确定它在世界坐标系或者以车辆底盘为原点的 body frame里的检测框最土但有效的办法是取 bbox 底部中心点在图像上的像素坐标 (u, v)。通过相机内参和畸变系数利用cv::undistortPoints得到归一化坐标。假定该点在地平面高度 Z0通过相机的光心高度外参中的平移量 z反解出它在相机坐标系下的 X, Y, Z 坐标。这一步其实叫做“基于地面假设的单目测距”。这个方案在标定完成后实测能在 20 米内将车辆定位误差控制在 5%-8% 左右。对于园区车或者低速智能车来说这个精度已经足够配合雷达做数据关联了。我个人是不建议在前期就因为追求精准测距而上双目或深度摄像头因为算力消耗和被检测物体纹理影响会成为新的头疼问题。5. 实操过程与核心环节实现从画框到融合的全链路聊完了理论我们直接把代码和 launch 文件结合起来看怎么把它们串成一串。5.1 我在实际项目里的启动顺序我会把整套系统分成几个独立的终端启动方便排查问题。这里用 tmux 开会更高效。终端1启动摄像头 启动标定转换source devel/setup.bash roslaunch my_cam_driver usb_cam.launch终端2启动 YOLO 推理节点roslaunch yolov3_autoware yolo_detect.launch这里注意如果你没有接入显示屏要确保图像可视化开关在 launch 里是 false否则会白白浪费 CPU 去渲染 GUI。终端3启动 Autoware 核心的 runtime manager 和 RVizroslaunch runtime_manager runtime_manager.launch rviz通过 Rviz 加载 Autoware 1.14 提供的官方 rviz 配置在autoware.rviz文件中你会看到目标融合后的可视化效果。在这里我习惯把视觉框绿色和雷达距离轮廓红色同时打开框重叠度越高说明标定和检测做得越到位。5.2 YOLO 推理参数选择的经验值很多朋友对confThreshold置信度阈值和nmsThreshold非极大值抑制阈值没有概念所以老是出现“想框车却把树影也框住了”的误检。我直接给你我调过几百遍的配方confThreshold日常跑在自己录的数据集上我一般设在 0.4。如果是在复杂施工场地很多目标可能被遮挡就降到 0.25。如果是为了出演示效果那就提到 0.6画面会非常干净几乎没有误检框。nmsThreshold这个阈值是控制重框的。设在 0.4-0.5 之间很合适。如果你把这个值设成 1.0算法会把好几个重叠框叠加输出在你的 RViz 里看着会非常乱。在 ROS 的话题里监听detection/image_detector/objects你会看到类似这样的数据流header: seq: 228 stamp: secs: 1730 nsecs: 830000000 frame_id: camera_link objects: - label: car score: 0.87 x: 235.0 y: 312.0 ...这里我强烈建议你在y轴上做一点手脚。因为 Autoware 的一些旧版本可视化插件对 Y 值的理解习惯不同如果你发现 RViz 里的框始终在车底以下说明图像的 Y 轴标记和地图坐标系中的 Y 轴标记得到了相反数直接对框坐标取负就能快速解决。6. 常见问题与排查技巧实录把我掉进去的坑给你填平最后这一部分咱们直接进入避雷环节也是我整个开发过程中觉得最值钱的私有经验。6.1 YOLO 节点一直在转圈CPU 满载但就是不出来框这种情况十个里头有八个是权重文件路径写错了或者 cfg 文件里定义的类别数和权重里不一致。检查一下.weights有没有下载完整一般 240MB 左右。另一个常见原因是 OpenCV DNN 的readNetFromDarknet对网络路径的兼容性差你如果用~或$HOME这种符号去拼路径有极大概率读取失败。永远使用绝对路径或者通过rospack find去定位包的绝对路径。6.2 出框了但摄像头画面和激光雷达点云完全错位这是最经典的标定问题。首先确认标定文件里的camera_info话题时间戳和图像时间戳是否对齐。Autoware 1.14 里面有个很奇怪的地方如果你用timestamp_topic设置了sensor_msgs/Image它会默认使用右图像的触发时间导致按左图像时间查找标定矩阵时会得到“未同步”的异常。解决办法是在启动前写一个简单的时间对齐节点将Image和CameraInfo用ApproximateTime策略同步。6.3 在树莓派或者 ARM 平台上跑不动YOLOv3 416 分辨率输入在树莓派 4B 上放到 CPU 推理帧率可能在 0.5-1.5 FPS 之间基本不具备实时性。这时候我的建议是不要死磕深度网络可以考虑把输入尺寸从 416 降到 320同时把DNN_TARGET_CPU换成DNN_TARGET_OPENCL如果树莓派上装了 OpenCL 驱动。或者干脆考虑用热词搜索里提到的 5MB 级别的轻量模型比如 YOLO-Fastest。不过在 x86 工控机上就算只有 4 核 CPU跑出 8-10 FPS 还是能做到的。6.4 “框”在 RViz 里抖动得很厉害YOLO 的单帧检测天然存在位置抖动因为网络的输出坐标是逐像素预测的。要优化这个现象我一般不推荐做卡尔曼滤波因为卡尔曼滤波对非线性的车辆运动建模太粗鲁。我会给检测框加一个滑动平均窗口保存前后帧的 bbox 位置输出时取平均值。注意这个操作不能放在 YOLO 的检测节点里否则你会发现错检比例暴增。正确的做法应该是放在下游的点云融合或决策规划节点中接收到感测目标后在程序里维护一个 ID 和 bbox 的滚动队列。6.5 关于camera_frame_id的默认值我的血泪教训是ROS 坐标系的名称一定要规范不要用默认的camera作为 frame_id最好使用camera_link并且在 TF 数树里把这个camera_link设置为车辆 base_link 的 child。否则当你跑pcl_ros的点云到图像转换时会因为找不到 TF 变换而直接抛出tf2::TransformException这种错误在日志里出现得非常隐晦但会导致整个感知节点静默关闭。7. 写在最后一点真心实意的扩展建议项目做到这步一套“摄像头 YOLO-V3 Autoware 1.14”的感知原型就已经跑通了。这绝对是值得竖起大拇指的成绩因为它意味着你已经能把图像里的语义信息抽离出来并且能同步到和雷达相关的空间参考系里了。我个人在实际操作中的体会是不要急着把 YOLO-V3 换成当下最火的模型而是在现在这个已经稳定的框架里先解决工程问题。比如试着让检测到的车辆产生速度追踪或者做一个最简单的 AEB自动紧急制动策略当车距小于阈值时对底盘发出控制指令。你会发现跑通深度学习检测只是切蛋糕的第一步后端的融合、滤波以及决策逻辑才是真正的重头戏。后续你可以尝试把这个节点从 OpenCV DNN 迁移到 TensorRT 或者 ONNX Runtime在线程池里加异步推理。用不了多久你会发现自己对机器人操作系统的并发机制、消息同步机制的理解会有质的飞跃。最后再分享一个特别小的技巧当你把视频流跑起来后先别急着接激光雷达用单个摄像头打开 YOLO 检测看看效果。在很多纯视觉课题里一个输出稳定、帧率可靠的 YOLO-V3 节点已经足以撑起一篇高质量的本科或研究生毕设了。先学会让车“看懂”这个世界再去考虑让它“摸”到这个世界这条路子一定不会错。
返回列表