3. 高精地图基础

做自动驾驶感知这几年,我越来越觉得高精地图就像车的「第二双眼睛」。传感器能看到的范围有限,但地图可以告诉你前方200米外有个弯道,或者第三条车道即将汇入。今天我们就来聊聊高精地图的核心基础。

高精地图的图层结构

高精地图不是一张简单的图片。它是一层层叠加起来的「数字世界」。我习惯把它拆成三个核心图层:道路层、车道线层、交通标志层。

1. 道路层

这是最底层的骨架。它定义了道路的几何形状、坡度、曲率。说白了,就是告诉车「路在哪里」。我在项目中遇到过一个问题:某段高架桥和地面道路在GPS坐标上几乎重叠,但高度差了十几米。如果没有道路层的海拔信息,车就会以为自己在天上开。

  • 道路中心线:一条平滑的曲线,代表道路的走向
  • 道路边界:左右两侧的路沿或护栏位置
  • 道路连接:交叉口、匝道、环岛的拓扑关系

2. 车道线层

这一层比道路层更精细。它定义了每条车道的宽度、类型(直行、左转、右转)、以及车道之间的连接关系。你想想看,如果车道线层缺失,车连「我在哪条道上」都不知道,变道、转弯根本没法做。

关键属性:车道ID、前驱车道、后继车道、左侧车道、右侧车道、车道类型(普通/加速/减速/应急)

3. 交通标志层

这一层包含红绿灯、限速牌、停止线、人行横道等。嗯,这里要注意:交通标志的位置不是随便标个点就完事了。它必须和车道线层关联。比如「这个红绿灯控制的是哪几条车道?」「停止线对应哪个车道?」

我曾经踩过一个坑:某个路口的红绿灯和停止线距离标错了5米。结果车在距离路口10米的地方就停了,后面的车差点追尾。从那以后,我对图层间的关联关系格外敏感。

矢量地图与栅格地图

这两种地图格式,说白了就是「用点线面描述」和「用像素描述」的区别。

矢量地图

矢量地图用坐标点、线段、曲线来描绘道路。比如一条车道线,就是一系列经纬度坐标点连成的折线或样条曲线。它的优点是精度高、数据量小、容易编辑。

  • 每个点用 (x, y, z) 表示,精度可达厘米级
  • 支持拓扑关系:车道A连接到车道B
  • 适合做路径规划和决策

栅格地图

栅格地图就是把地图切成一个个小格子,每个格子存一个值。比如0表示可通行,1表示障碍物。它的优点是结构简单,适合做感知融合和占用网格。

  • 分辨率决定精度:10cm/格 vs 50cm/格,差别很大
  • 数据量大:一张1km²的地图,10cm分辨率就是1亿个格子
  • 不适合做拓扑分析,但适合做碰撞检测
对比项 矢量地图 栅格地图
存储方式 点、线、面 像素矩阵
精度 高(厘米级) 依赖分辨率
数据量 小 大
典型用途 路径规划、决策 感知融合、占用网格
我的建议:实际项目中,两者往往结合使用。矢量地图做全局规划,栅格地图做局部感知。我习惯把高精地图存成矢量格式,然后实时渲染成栅格给感知模块用。

OpenDRIVE标准简介

OpenDRIVE是目前最主流的高精地图标准。它用XML格式描述道路网络。我第一次接触它的时候,觉得XML嵌套太深了,看得头疼。但用久了你会发现,它的设计其实很巧妙。

核心概念

  • Road:一条道路,包含多个车道段
  • LaneSection:车道段,描述某一段道路上所有车道的横截面
  • Lane:单个车道,包含宽度、类型、边界线等
  • Junction:交叉口,连接多条道路

举个简单的例子,一条双向四车道的高速公路,在OpenDRIVE里是这样描述的:

<road name="高速A段" length="500.0" junction="-1">
  <lanes>
    <laneSection s="0.0">
      <left>
        <lane id="-1" type="driving">
          <width sOffset="0.0" a="3.5" b="0.0" c="0.0" d="0.0"/>
        </lane>
        <lane id="-2" type="driving">
          <width sOffset="0.0" a="3.5" b="0.0" c="0.0" d="0.0"/>
        </lane>
      </left>
      <center>
        <lane id="0" type="none">
          <width sOffset="0.0" a="0.15" b="0.0" c="0.0" d="0.0"/>
        </lane>
      </center>
      <right>
        <lane id="1" type="driving">
          <width sOffset="0.0" a="3.5" b="0.0" c="0.0" d="0.0"/>
        </lane>
        <lane id="2" type="driving">
          <width sOffset="0.0" a="3.5" b="0.0" c="0.0" d="0.0"/>
        </lane>
      </right>
    </laneSection>
  </lanes>
</road>
注意:OpenDRIVE中车道ID的符号是有含义的。负号表示中心线左侧,正号表示右侧。0号车道永远是中心线。这个约定我第一次用的时候搞反了,导致车道匹配全乱套。

知识体系总览

下面这张图是我自己梳理的高精地图知识结构,你可以把它当作学习路线图:

高精地图知识体系 图层结构 地图格式 OpenDRIVE标准 道路层 · 车道线层 · 交通标志层 矢量地图 · 栅格地图 Road · LaneSection · Lane · Junction BEV感知 + 高精地图融合 路径规划 · 行为决策 · 控制执行 图层结构是基础,地图格式是载体,OpenDRIVE是标准,三者缺一不可

这张图把今天讲的内容串起来了。图层结构是基础,地图格式是载体,OpenDRIVE是标准。三者缺一不可。我个人习惯先理解图层结构,再去看OpenDRIVE的具体实现,这样不容易迷失在XML的细节里。

避坑指南:我曾经在解析OpenDRIVE时,忽略了LaneSection的sOffset参数。结果车道宽度计算全错了。记住:sOffset是相对于当前车道段起点的偏移量,不是全局坐标。