OpenDrive解析小结

前言

  接触并使用高精地图和 OpenDRIVE 已有一年的时间,简要写写 Shaun 对 OpenDRIVE 的一些认知。

基础篇

OpenDRIVE 目前最新的版本的 1.6,下面主要结合 1.4,1.5 和1.6 版本一起看。

  在 OpenDRIVE 中主要有两种坐标系统,一种是常见的 X/Y/Z 空间坐标系统,另一种是 S/T/H 坐标系统。其中 X/Y/Z 坐标系统常与地理信息的各种坐标系统一起使用,S/T/H 坐标系统是针对 OpenDRIVE 中道路参考线设定的一种局部坐标系统,在 OpenDRIVE 中称前者为 “inertial co-ordinates”,后者为 “track co-ordinates”(1.6 中直接为 Reference Line System)。除此之外,还有个局部坐标系 U/V/Z,该坐标系统系统是相对于 S/T/H 坐标系统平移旋转而来的。

对于旋转,以逆时针为正,heading 是指绕 z/h 轴旋转,pitch 是指绕 y/t 轴旋转,roll 是指绕 x/s 轴旋转。

对于曲率,逆时针延申的曲线曲率为正,顺时针延申的曲线曲率为负。

在 OpenDRIVE 中对于道路和车道的描述,有以下几个重要的概念:

  • Reference Line。用来指示一条道路的骨架,是 S/T/H 坐标系统的依据,道路中各车道线需要参考这条线。
  • Lanes。用来描述各车道以及各车道所属 Lane Section。
  • Lane Offset。其意义在 OpenDRIVE 标准看起来很清除,但实际用起来非常模糊,offset 到底是只能偏移一个车道,或半个车道或多个车道,所属哪个 Lane Section,其意义不明,故下文解析篇将直接忽略该属性。
  • Lane Section。可以简单理解为子道路,一个 lane section 中包含多条车道,一条道路包含多个 lane section。一个 lane section 中车道数是一个常数,所以对于存在 m 变 n 车道的一条道路,至少要划分为两个 lane section。
  • Superelevation、Crossfall 和 Shape。用来表示路面倾斜程度。Superelevation 是整个路面侧向太高,即路面倾斜程度,Crossfall 在 1.6 中已被废弃,原因为 1.6 完善了 Shape,可以完全取代 CrossFall,甚至能做的更好,Shape 主要用来描述路面两侧车道的倾斜程度,通过三次曲线和线性插值可以精确到车道各点倾斜程度。
  • Road Linkage。道路之间的连接关系,通过前继(predecessor)和后继(successor)建立道路之间连接关系,若一条路存在多个前继或后继,则其对应前继或后继应该为 Junction ,即目前的标准中暂不支持道路多前后继,1.5 中只支持车道多前后继,道路多前后继依然不支持。
  • Junction。交汇处,通俗意义上的路口,主要包含 incomingRoad 和 connectingRoad。
  • Junction Group。可以简单理解为交通环岛。
  • Neighbors。相邻关系,和 Road Linkage 类似,一个是前后连接关系,一个侧面相邻关系。
  • Surface。车道或道路表面材质,有 OpenCRG 则优先使用,没有则由应用程序自定义字符串。
  • ....... 等等。还有一些冷门的元素暂时没用到,就不介绍了。

下面就是真正的解析内容了。

解析篇

  一些简单的就不介绍了,就介绍解析时需要注意的一些重点元素。

Road Geometry

  geometry 信息可以说是 OpenDRIVE 中最重要的信息,没有之一。OpenDRIVE 中最重要的元素为 Road,而 Road 中最重要的是 Reference Line,而 geometry 正是用来描述 Reference Line 几何线条形状的信息。

  首先 geometry 标签中共有 5 个属性,分别为 s (该段 geometry 沿参考线起始位置),x(该段 geometry 在 inertial system 下起始横坐标),y(该段 geometry 在 inertial system 下起始纵坐标),hdg(该段 geometry 在 inertial system 下起始弧度),length(该段 geometry 长度)。其次,geometry 共有 5 种线型,分别为 straight lines(直线),spirals(螺线),arcs(圆弧线),cubic polynomials(三次曲线),parametric cubic polynomials(参数化三次曲线),这 5 种线型分别由 geometry 下 5 种标签控制。解析 geometry 的要点在于:先不用管 geometry 标签中的属性,直接解析对应线型标签,需要满足两点:1、起始点坐标一定为 (0, 0);2、起始点斜率,即导数也一定为 0。依据这两点正确解析完线型之后,再根据 hdg 旋转线型,根据 (x, y) 将线型平移到正确位置。 下面就具体看看这 5 种线型:

  1. line,直线。没有任何属性,直接根据 geometry 中 (x, y) 和 hdg 就可得到直线方程。
  2. spiral,螺线。有两个属性 curvStart(起始曲率),curvEnd(结束曲率)。螺线解析的代码已经由 OpenDRIVE 官方直接给出了,里面涉及到的数值计算方法就不详解了,直接看官方提供 API 的输入输出,输入有两个:s(从原点开始,螺线延展的长度),cDot(螺线的曲率关于 s 的一阶导数);输出有 3 个:x(横坐标),y(纵坐标),t(该点的切线弧度)。解析螺线最大的问题应该就是如何得到这两个输入参数,由螺线的性质可以得到,螺线的曲率一定随着螺线的长度均匀变化的,换句话说,对于一条已知螺线,cDot 一定是常数。则 \(cDot = (curvEnd - curvStart) / length\),其中 length 为 geometry 中的长度属性,下一步需要求出 s,由于已知螺线在原点处的曲率一定为 0,则 (curv - 0) / (s - 0) = cDot,即 s = curv / cDot。由此可得到螺线的各点坐标和切向方向,但由于解析线型需要满足上面说的两点,所以需要将螺线坐标以起始点进行平移和旋转,以满足起始点为原点,起始点切线弧度为 0,最后再将完成平移和旋转后的点根据 geometry 的属性进行旋转和平移以得到真正的坐标点。
  3. arc,圆弧线。只有一个属性 curvature(曲率),可根据曲率直接得到圆的半径,在根据曲率的正负可得到该曲线是以顺时针延申还是逆时针延申,再根据解析线型需要满足的两点和 geometry 的属性可得到真正的 inertial system 中的点。
  4. poly3,三次曲线,在 1.6 中已被废弃。精度要求低一点可直接插值计算,要求高一点则需要利用 length ,数值计算和二分法直接求出最大的 u,然后插值。
  5. paramPoly3,参数化三次曲线。最有名的两个参数化三次曲线就是 Bezier 曲线和 Hermite 曲线,为满足解析线型需要满足的两点,一定有 \(a_u=0, a_v=0,b_v=0\),需要注意的是一般参数化曲线的参数取值范围为 \([0,1]\),即该标签最后一个属性 pRange="normalized",若碰到特殊情况 pRange="arcLength",则需要将 \(a_u,b_u,\dots\) 等属性转化为参数取值范围为 \([0,1]\) 时对应的属性。

最重要的元素 Geometry 的解析就是这样了,下面谈谈 Shaun 对基于三次曲线的一些元素的理解。


  比较重要的基于三次曲线的元素主要有 elevation(控制路面的高度),superelevation(道路侧面抬高弧度),crossfall(路面两侧弧度,已被废弃),shape(路面两侧形状,特殊,下文详细介绍),laneOffset(车道偏移量),border 和 width(特殊,下文详细介绍),这些元素所使用的三次曲线一般都基于道路参考线(特殊除外),即该三次曲线的横坐标一般为 s,纵坐标即三次曲线的值则为各元素的信息,这些三次曲线一般是分段描述的,即道路参考线上两个关键点的 s 之间必会生成对应的一段三次曲线,每一段三次曲线的横坐标取值范围都为 \([0,poly3Length]\),其中 ploy3Length 为该段三次曲线的长度。这些三次曲线段全部合起来则构成沿道路参考线的一条三次曲线,根据 s 计算三次曲线的取值得到对应的信息。

LaneOffset

  laneOffset 用来指示的是所有车道沿参考线法线方向的偏移量,所有车道包括中心车道(centerLane),由于中心车道没有宽度,所以也可以叫道路中心线,这和道路参考线是两个概念,若 laneOffset 都为 0,则道路中心线和道路参考线重合。

Shape

  路面两侧车道的高度,该元素虽然也是使用三次曲线进行描述的,但是该三次曲线的横坐标为 S/T/H 坐标中的 t,不是 s,不同的 t 得到不同的高度,该元素下可能存在多段三次曲线,这些三次曲线段是独立的,只是描述其属性 s 所在位置横截面的 shape,而没有完全指定 s 的横截面的 shape,则由两临近 s 的 三次曲线计算相同的 t 对应的高度然后线型插值得到(1.6 标准中插值的公式 Shaun 觉得有问题)。

border 和 width

  之所以把这个两个元素放在一起写,是因为这两个元素描述的本质上是一个东西,都是车道边界所在的位置。同时,Shaun 还是想吐槽一下,作为一个既定的标准,完全不应该把这两个元素同时放出来,只需要放出一个即可,既然为标准就应该做到完全统一,至于具体用哪个是应用程序的事,但是出来的东西必须得唯一。border 是指车道边界到道路中心线在道路参考线法线上的投影,有正负之分,一般左边车道为正,右边车道为负,而 width 是指车道的宽度,这两者完全可以相互转换。虽然描述这两者的三次曲线是基于道路参考线 s 的,但是这个 s 是相对于 laneSection 标签中 s 属性的,即其真正沿道路参考线的 s' 应该为 s' = s + laneSection.s。


  至于Junction 的解析好像没什么需要注意的,就不写了,至于 1.5 中的 Virtual Junction,引入新的道路前后继描述方式,也新加了一个 virtual connection,解析时到也没有需要注意的,唯一需要注意是在应用程序中该如何利用这些信息。


  对于 Signal 和 Object,Shaun 觉得标准中强制规定 s > 0 同样是一件非常不合理的事情,既然能超出道路长度,只准正向超出,不能反向超出,这有点不讲道理。 Signal 和 Object 同样需要注意在应用程序中的用法,至于解析方面,需要注意的应该就是 Object 中 outline 下面的 cornerRoad 和 cornerLocal。

cornerRoad 和 cornerLocal

  这两个元素描述的本质上也是一个东西,都是面域对象多边形边界上的轮廓点,虽然 1.5 中引入了复杂多边形的概念,即有内轮廓和外轮廓,但 cornerRoad 和 cornerLocal 还是一样的解析。cornerRoad 是直接相对于道路参考线的坐标,即将 X/Y/Z 坐标直接转换为 S/T/H 坐标得到的,所以直接解析转换就可得到该点的真正坐标。而 cornerLocal 的解析则相对要麻烦些,首先根据 object 标签中 s 和 t 属性计算得到 Object 的位置,以道路参考线上 s 所在的位置建立 S/T/H 坐标系统,将该坐标系统平移到 Object 所在位置,即该 S/T/H 系统以Object 的位置为原点,将 cornerLocal 上 u,v,z 属性带入该坐标系统计算出真正的坐标。由于 Object 中的 roll,pitch,hdg 属性,所以还需要对坐标以 Object 的位置为中心进行相应旋转才能得到真正 X/Y/Z 坐标系统中坐标。


好了,以上就是 Shaun 觉得在解析 OpenDRIVE 时需要注意的一些地方了。

后记

  整个地图行业本来就存在很强的壁垒,国内更是如此,而高精地图作为专为自动驾驶服务的地图,国内估计更是少有人接触过。

  OpenDRIVE 虽作为一种高精地图标准,但离那种被广泛认可关注的标准还有很长一段距离,虽然它发展了十几年,但奈何整个行业才算是起步阶段,所以之前其一直发展的十分缓慢,之前用 OpenDRIVE 较多的应该是交通仿真领域,这个领域同样存在很强的壁垒,要在这种领域得到整个行业的认可是一件非常困难的事,因为其本来就存在一套自己的格式,而想要应用别人的标准,就势必需要逐渐抛弃自己的格式,这对企业来说需要下很大的决心。

  就 Shaun 目前所知,行业内虽然有许多企业使用 OpenDRIVE 标准,但基本都是自己魔改后的标准,原因在于 OpenDRIVE 标准还没做到真正成为标准的地步,虽然其一些基本元素具备,但很有很多元素是完全缺失或不完善的,更重要的是,其可视化程序竟然不开源,在整个计算机领域内,还从没见过一种标准没有其开源实现的东西,没有相应的源码,只靠文字来理解难免会产生歧义,各大厂商自然就会选择实现自己的 OpenDRIVE,很难统一。历史上一些经典的论文和算法,都有其相应的开源实现,没有开源实现的论文和算法基本都淹没在了历史长河之中。所以没有开源实现,在计算机领域内很难真正推广开,就很难成为真正的标准。综上,OpenDRIVE 的发展任重而道远啊!希望现在在 ASAM 手中能发展的更快更完善些吧。