1. 高精地图定义
高精地图即为“两高一多”的地图,在自动驾驶中常常被称为HapMap,这是自动驾驶汽车中非常重要的一部分
- 高精度:精度可以达到厘米级别
- 高动态:高精地图实时性,为了应对各类突发状况,自动驾驶车辆需要高精地图的数据具有较好的实时性
- 多维度:地图中不仅包含有详细的车道模型、道路部件信息,还包含与交通安全相关的一些道路属性信息,例如GPS信号消失的区域、道路施工状态等
2. 自动驾驶地图框架
2.1 Apollo OpenDrive(百度)
- 道路边界是强约束,即自动驾驶的时候,道路边界是永远不能压的。车道线理论上也是不能压的,但是如果在紧急情况下可以压车道线,比如说可以越过虚黄线进行借道超车。
- 可以通过路口的边界,对感知进行过滤。如果感知识别到的静态物体不在地图的路口边界之内,就可以暂时忽略它。虚拟车道主要是用来路口的行驶引导。
- 高精地图会为红绿灯提供一个三维空间位置,其次也会提供红绿灯跟车道之间的关联关系,即告知当前所在车道,应该看哪个灯。道路标志主要包括人行横道,停止线以及一些路上的文字信息。
- 逻辑关系表述。当前,地图中各个元素之间的关系并没有嵌入到元素的表述中,而是使用overlap来表述两个元素之间的空间关系。如下图所示,Lane和Junction在空间上有重叠,它们之间就会有Overlap。
2.2 Lanelet2(Autoware)
- points由ID,3d坐标和属性组成,是唯一存储实际位置信息的元素,ID必须是唯一的。其他基本元素都是直接或者间接由points组成的。在Lanelet2中,Points本身并不是有意义的对象,Points仅与Lanelet2中的其他对象一起使用有意义。
- 线串是两个或者多个点通过线性插值生成的有序数组,用来描述地图元素的形状。线串可以是虚线,它可以通过高度离散化实现,来描述任何一维形式,并应用于地图上的任何可物理观察到的部分。与样条曲线相比,线串可以高效计算,并且可以用来描述尖角,最终转化为非线性微分方程的求解问题。
- 多边形与线串非常相似,但形成一个Area。隐式假定多边形的第一个点和最后一个点被连接以闭合形状。多边形很少用于传输地图信息(交通标志除外)。相反,它们通常用作将有关区域的自定义信息添加到地图(例如,感兴趣区域)的一种手段。
- Lanelets定义了发生定向运动时,地图车道的原子部分。原子表示沿当前lanelet行驶时,有效的交通规则不会改变,而且与其他Lanelet的拓扑关系也不会更改。
lanelet可以引用表示适用于该lanelet的交通规则的regulatory elements。多个lanelet可以引用同一regElem。必须始终始终可以直接从车道上确定车道的当前速度限制。可以通过引用SpeedLimit监管元素或标记小车的位置来完成。在这种情况下,假定道路类型的最大速度(例如,如果位置是德国城市,则为最大50公里/小时)。 - Areas是地图上没有方向或者是无法移动的部分区域,比如路标,停车位,绿化带等。他们由一条或者多条linestring组成的闭合的区域。Area也有相关联的regulatory elements。
- regElem是表达交通规则的通用方式,它们由适用的lanelet或Area引用。在应用的时候,regElem 会和一个或者多个Lanelets、Areas相关联。regElem是动态变化的,意味着它只是在某些条件下是有效的。
- 诸如限速,道路优先级规则、红绿灯等,交通规则有许多不同的类型,因此每个regElem的准确结构大都不一样。他们通常引用定义规则的元素(例如交通标志),并在必要时引用取消规则的元素(例如速度区末尾的标志)。
3.制图流程概述
高精地图是一种语义地图,概括地说,就是利用SLAM/SFM等算法融合多种传感器数据,构建高精度的三维点云地图,在点云地图上或者是图像上,对所用到的元素进行分类和提取、之后对不同元素分别进行矢量化并构建路网与车道关联关系,最后进行质量校验,形成一套地图引擎来存储并支撑其他模块的需求。
高精地图制作完成后,其数据量其实是非常小的。地图数据可以存储在云端,也可以直接直接在本地,大地图还有可以用数据库来存储。先暂且不论地图格式是Lanelet2还是OpenDrive以及其他,完整的理解高精地图的元素结构设计,以及数据存储和使用则为重中之重,后续的自定义格式要求可按自己的需求来适配。
小地图手工标注方法
对于3km以内的小地图而言,一般可以采取手工标注点云地图的方法来制图。目前我了解到的以下软件均可,比如
- RoadRunner
2020年最新版可直接标注点云PCD文件,添加语义,可直接导出标准Opendrive,缺点就是目前语义类别不太完善,导出格式只支持标准OpenDrive。在使用上,高校等科研单位申请免费,每所学校一个密钥。 - LGSVL Map Annotation(windows Unity 插件版,需要手动编译)
支持目前的主流地图格式,可导入导出如Apollo Opendrive/标准Opendrive/Autoware VectorMap/Lanelet2等,缺点是目前只能标注LGSVL提供的一些虚拟环境,使用上是完全开源的。目前2020.03的版本已经开始支持直接标注点云pcd。
在这里插入图片描述
Autocore MapToolBox
插件
AutoCore提供的开源工具,用于标注生成Autoware vector map矢量地图,更新速度快,目前可标注车道线,路沿,红绿灯,目前已全面支持Lanelet2 ,项目完全开源,本篇将着重于此。大家可以在issue里面多提bug,感谢作者moelang以及Autocore做出的极大贡献!
- Assure mapping tools
Github@hatem-darweesh开源的标注工具,格式支持齐全,包括Google Earth、KML、opendrive、Lanelet、Vector Map等,标注上自动Fix height、smooth line,并集成了一些自动化的提取算法和。功能相当齐全,就是性能较差,大地图加载进来很卡,需要配合GPU使用,另外有些功能也可能是目前我还没有研究透彻。
- 51VR、四维图新等高精地图地图服务提供商(收费)
一般是图商直接用自家的制图车进行采集数据制作,按次数收费,目前一般城区道路收费5k-1w/每公里。少数厂商会提供高精地图标注软件及相关仿真系统服务,成本较高,目前就试用情况来看也不是十分完善。
4.制图流程实践
构建点云底图
构建点云地图可以用一些主流的激光SLAM算法,结合多种传感器来完成,其中要保证户外场景的建图效果,IMU和GPS是必须的,下面有一些推荐的开源算法,按优先级排列
- LIO-SAM(紧耦合的激光惯导SLAM算法,速度快)
- LIO-MAPPING (紧耦合的激光惯导SLAM算法,第一套紧耦合的激光惯导)
- LEGO-LOAM(松耦合、轻量级,性能不错,配置简单)
- VLOAM(能找到非官方的代码)
- ALOAM(仅里程计,可用于学习)
自动标注
自动标注涉及到的算法相当多,流程大致如下:
- 点云地图提取路面信息GroundExtraction(强度图、密度图、高程图)
- 路面信息部分,激光点云提取路沿、车道线、各种路标、停止线、人行横道等,非路面部分提取路牌,红绿灯,路灯,灯杆等。(各种多层强度阈值过滤方法)
- 视觉语义分割方法,提取各道路元素(在自己标注的数据集上可能表现更好)。将视觉分割得到的像素点反投影转换到世界(通过内参->外参参转换,需要激光雷达相机联合标定),去补充激光提取出来的不完整的部分
- 对每一类的线段部分分别进行分段直线/曲线拟合,有序保留端点和均匀的采样点,按位置进行排序。将有序的线段再次分类,比如左车道线,右车道线,中心线(可根据直线截距或者斜率阈值过滤),计算同一条车道线的各段线段的方向,连接端点,完成矢量化。
- 对每一类的多边形部分,比如路标,进行轮廓计算,从点云轮廓中提取出矩形或者箭头端点,按逆时针/顺时针存储(有内外圈的区分)。
- 用Lanelet2等地图框架,根据之前的各种点云分类,添加语义及车道的关联关系,构建地图索引和数据存储,生成高精地图数据文件,后面的博客有介绍Lanelet2用法。
- 用地图编辑软件打开地图并手工修正相应的轮廓,或者补充缺失部分。
- 人工校验道路的每一段是否存在质量问题。
手工标注(Autoware)
对比下来发现采用Autoware的地图标注插件更好,Unity + MapToolBox进行标注,插件地址如下:https://github.com/autocore-ai/MapToolbox
,这里注意下载的Unity版本需2019.3+,在Windows环境下使用,最新版的priview6已经加入对road mark和crosswalk的支持。目前Autoware社区已经增加了对Lanelet2的支持。
手工标注(Apollo)
Apollo Opendrive高精地图的话一般存在下面四种思路。
- 可以根据上面Autoware开源的MapToolbox,这俩都是C#项目,前者可以改写后端,存储标准点的时候按照Apollo Opendrive的格式去存储,由于都是坐标序列描述,改写难度不大。
- LGSVL Map Annotation,目前支持直接导入PCD点云标注(2020.03版新功能不完善),也可导入已有的Apollo Opendrive/标准Opendrive/Lanelet2,可导出Apollo Opendrvie/Autoware Vector Map/Lanelet2/标准Opendrive等格式的地图。其问题主要在于性能较差,对硬件要求高。
- 利用RoadRunner标注点云PCD,导出标准Opendrive地图,采用LGSVL模拟器将标准Opendrive转换到Apollo Opendrive地图。此步骤已验证,示例标注的Apollo Opendrive地图如下
由于目前支撑Opendrive的开源lib库很少,虽然自己写也不是特别费劲,可以利用其他的开源地图框架,生成高精地图之后再转换为Apollo Opendrive格式。这里目前可选择的仅仅是Liblanelets/Lanlets2,按照Lanlets2的接口规范可以生成OSM地图,在用开源的JSOM编辑器编辑完OSM地图后,再转换成Apollo Opendrive地图
5. Lanelet2地图代码解析
地图格式官方推荐的是OSM格式(XML),开源可编辑。当然也可以是二进制文件,加载速度快,缺点是不可直接编辑。下面的地图文件是按XML形式来存储的,结构十分明朗。关于OSM规范,可以参考其WIKI,https://wiki.openstreetmap.org/wiki/Map_Features
。
地图里面的每一个3D点都会用一个node标签存储,包含其经纬度LaLon,id是其唯一标志。后续的way标签存储lineString形式的元素,通过id引用node节点存储的3D点。而和交规相关的relation标签则又引用这些way id。
我们在JOSM编辑器中打开可以看到地图的基本形状,此编辑器的使用方法可查看官网https://learnosm.org/en/josm/correcting-imagery-offset/
。下图是一个复杂的十字路口,地图上所有的黄色小框框都是一个3D/2D坐标点。这里红色的线是地图里面的stop_line,在软件界面右侧可以看到其属性是stop line
,并且有四个节点。地图上画出来了所有的车道线,路沿,人行横道,绿化带区域等,还有各个road user
(比如行人,车辆等)需要遵守的交通规则,以及车辆在十字路口可能的换道路线(现实中是没有的,属性定义为virtual)。
Lanelet2代码的安装可以参考官方文档https://github.com/JokerJohn/Lanelet2,其层级结构如下
我们常用的代码在lanelet_core、lanelet_io、lanelet_projection、lanelet_routing和lanelet_traffic_rules这几个模块中。项目采用gtest框架来测试,阅读起来比较容易。
这里我们首先需要知道如何去使用,首先是图元的基本定义方法(增删改查),还有交通规则的定义方法及其与车道和road user
的关联关系。之后是如何去构建、加载使用OSM地图,并且根据需求查询相关的车道等信息。最后是如何生成生成路由图,并利用路由图和实际需求进行合理的路径规划。