OpenDrive格式高精度地图详细解析及其使用(1.栅格地图、OpenDrive坐标系以及参考线介绍)
臨近年底,回想自己今年做的事情,越想越慚愧,搖搖擺擺持續(xù)內(nèi)耗導(dǎo)致學(xué)習(xí)效率一直不高,如果說有感覺到學(xué)會了的東西那可能只有老師要求做的高精度地圖這方面的事情了,接手高精度地圖這方面已經(jīng)快一年多了,從去年的這個時候?qū)Ω呔鹊貓D一無所知,到現(xiàn)在可以說是稍有了解,其中走了許多彎路,想著能不能寫一篇文章出來總結(jié)一下自己的心路歷程,順便把自己學(xué)到的知識分享給大家。
雖然本文題目叫OpenDrive高精度地圖詳細(xì)解析及其使用,但是我會把我接觸高精度地圖從頭到尾學(xué)習(xí)到的東西都寫上,因?yàn)楸救藢W(xué)藝不精,其中難免會有許多問題,所以還是希望各位小伙伴兼聽則明,帶著批判性的去看去學(xué)習(xí)。
一.柵格地圖
柵格地圖是我接觸的第一個所謂的高精度地圖,因?yàn)楫?dāng)時剛剛?cè)腴T,啥也不懂,到網(wǎng)上搜索大多數(shù)的地圖出來的就是柵格地圖,但是柵格地圖其實(shí)本質(zhì)上并不屬于高精度地圖,我們目前所理解的高精度地圖能達(dá)到的許多功能柵格地圖完全做不到,最簡單的一點(diǎn),柵格地圖只能實(shí)現(xiàn)靜態(tài)障礙物的避障,對于機(jī)器人可能是夠了,但是對于自動駕駛車輛來說是完全不夠的,車輛需要按照道路結(jié)構(gòu)去走,從而做出相應(yīng)的規(guī)劃。話雖如此,如果你想做的功能很簡單,那么柵格地圖也不是不可以。
接下來我會簡單敘述一下如何生成柵格地圖,注意,我們這里的前提是離線建圖,動態(tài)SLAM建圖需要你另尋出路。我們采用激光SLAM的方法生成柵格地圖,生成柵格地圖我們首先需要生成點(diǎn)云地圖,啥是點(diǎn)云地圖,可以看下面的圖片,你可以簡單理解為通過激光SLAM算法拼接一幀一幀的激光點(diǎn)云幀生成的一個點(diǎn)云圖(詳細(xì)名詞定義請搜索引擎)
激光SLAM生成的點(diǎn)云地圖格式大多是PCD格式的,顯示PCD格式的點(diǎn)云文件可以使用CloudCompare,軟件除了偶爾卡死意外真的很好用。
得到點(diǎn)云地圖的方法就是通過激光SLAM自己去建圖,可以去看我之前寫的那篇文章(這里注意一下,lego_loam在沒有imu的情況下Z軸偏移情況很嚴(yán)重,如果你只有一個激光雷達(dá),那么我建議你使用hdl_graph_slam或是其他SLAM算法)。
得到這個點(diǎn)云地圖以后,我們就可以寫代碼來獲得柵格地圖了,那么如何通過點(diǎn)云生成的柵格地圖就是一個問題,我們知道點(diǎn)云地圖是由一個個密密麻麻的點(diǎn)構(gòu)成的,每個點(diǎn)都有其三維坐標(biāo),柵格地圖就是用一個個柵格組成的網(wǎng)格來代表地圖,柵格里可以存儲不同的數(shù)值,代表這個柵格的不同含義。比如我們表示這個格子被占用(有靜態(tài)障礙物),就可以把表示這個格子的像素點(diǎn)標(biāo)注為黑色,沒有障礙物則為白色。我們首先給定一個柵格地圖的分辨率,比如說我們規(guī)定柵格上的一個格子代表0.5 * 0.5米的面積,那么在點(diǎn)云地圖上,將點(diǎn)云中的每個點(diǎn)按照0.5 * 0.5的格子去做二維投射(各位可以在腦子中想象一下這個過程,就不詳細(xì)展開來講了)隨后我們根據(jù)投射到每個格子中的點(diǎn)的個數(shù)和其高度Z值來判定這個格子是否顯示為占用,大致過程就是這樣,如果想深入學(xué)習(xí)關(guān)于柵格地圖的相關(guān)知識可以去找更具體的文章,這里只是簡單介紹一下。
我做這部分的工作的代碼剛開始是自己寫的,后來在找SLAM算法的時候發(fā)現(xiàn)koide3大神(hdl_graph_slam的作者)開源了一個相同功能的代碼,功能和效果都非常好,我把網(wǎng)址分享給大家,大家可以自己去下載。完成此步驟我們就可以獲得一個柵格地圖啦:
接下來我們就可以在這個柵格地圖上執(zhí)行路徑規(guī)劃算法了,比如A*,這方面的文章很多,我們目前項(xiàng)目所使用的代碼也是在CSDN的基礎(chǔ)上改出來的,大家可以根據(jù)A*框架結(jié)合自己的需求去寫。
到此為止柵格地圖差不多就告一段落了,總之,如果做的是自動駕駛尋路方面的項(xiàng)目,強(qiáng)烈建議不要使用柵格地圖,因?yàn)槠渥陨淼南拗?#xff0c;導(dǎo)致你很難通過它給予下游模塊(如軌跡規(guī)劃和決策控制)很好的支持,這里大致了解一下就可以了。
二.OpenDrive格式的高精度地圖
其實(shí)今年年初的時候我們并沒有意識到柵格地圖的劣根性,因?yàn)槲覀儗?shí)驗(yàn)室之前沒有做過類似的項(xiàng)目,而且委托的甲方更不懂,直到今年4月份的時候我們自己意識到問題才決定另尋出路。
我們的OpenDrive地圖時甲方委托專業(yè)的制圖公司來提供的,因此我們并沒有去手動標(biāo)注一張地圖,但是大致路線是有的:還是生成一張點(diǎn)云地圖(需要結(jié)合RTK,因?yàn)槟阈枰O(shè)置投影關(guān)系),用RoadRunner軟件去進(jìn)行投影關(guān)系的設(shè)置和道路元素的標(biāo)注,可以知乎關(guān)注@王方浩,他寫過一篇文章就是關(guān)于用RoadRunner來制作Opendrive格式的高精度地圖,過一陣子我也會自己踐行一下技術(shù)路線,然后把怎么做更新上來。
OpenDrive是一種比較成熟的開源的描述道路結(jié)構(gòu)的格式,其自身格式為xml文件(.xodr),用文字和公式的形式來表達(dá)一系列道路的形狀和連接情況。接下來,我會首先介紹OpenDrive的結(jié)構(gòu)(我并不會把OpenDrive中的所有元素都介紹給你,因?yàn)榇_實(shí)很多元素用的很少,如果一股腦的都寫上不如叫你去看OpenDrive的官方文檔。對了,官方文檔的地址在這:https://www.asam.net/index.php?eID=dumpFile&t=f&f=3768&token=66f6524fbfcdb16cfb89aae7b6ad6c82cfc2c7f2)。隨后告訴你如何解析OpenDrive的結(jié)構(gòu)到內(nèi)存中形成相應(yīng)的數(shù)據(jù)結(jié)構(gòu),最后研究如何在OpenDrive的數(shù)據(jù)結(jié)構(gòu)中實(shí)現(xiàn)routing的功能。
在介紹總體結(jié)構(gòu)之前,我先要向你講述Opendrive的坐標(biāo)系,OpenDrive地圖中主要包含三個坐標(biāo)系,分別為xy慣性坐標(biāo)系,st參考線坐標(biāo)系和uv局部坐標(biāo)系,其中我將著重于前兩個坐標(biāo)系,因?yàn)榈谌齻€確實(shí)用處沒有那么大。三者關(guān)系如圖所示:
慣性坐標(biāo)系的X軸通常指向東,Y軸指向北,作為最穩(wěn)定的坐標(biāo)系,在執(zhí)行routing等功能時我們使用的都是慣性xy坐標(biāo),弧度關(guān)系為X軸為0逆時針為正(-pi, pi),Y軸為pi/2。接下來我們有很多地方會使用到慣性坐標(biāo)系。
st坐標(biāo)系是我個人認(rèn)為最重要的坐標(biāo)系,又名參考線坐標(biāo)系,參考線我會在下面重點(diǎn)講解,目前你可以將其理解為道路走勢的一種抽象,看上面的藍(lán)線就是一條參考線,將其想象為一條道路,那么st坐標(biāo)系的走勢就是從參考線開始到參考線結(jié)束一直沿著參考線的切線方向進(jìn)行的,st坐標(biāo)系是針對于參考線來說的,只有同一條參考線為基準(zhǔn)下才能比較兩個點(diǎn)的st坐標(biāo)。大致如下圖所示:
可以看到,st坐標(biāo)系一直隨著參考線的變化在變化,且一直沿著切線方向,由此我們可以推斷出:在st坐標(biāo)系中S的取值范圍為[0, 參考線長度length],而t即為基于參考線的偏移,所有處于參考線上的點(diǎn)t值均為0,這里請自己思考一下,下面我們講參考線的時候還會再敘述。
uv坐標(biāo)系目前看來只有在參數(shù)多項(xiàng)式那里使用了,你目前只需要知道它是由參考線坐標(biāo)系通過確定原點(diǎn)并提供偏向角來確定的,此外無他。
接下來正式是OpenDrive的總體結(jié)構(gòu),下面我用一張圖來表述:
這是我在csdn的一篇文章中找來的圖,我們可以看到可以將OpenDrive格式的文件結(jié)構(gòu)分為三大類:Header類,Roads類,Junction類。
首先第一類是Header,這個大類元素中最重要的一個元素就是geoReference,這個元素規(guī)定了整個Opendrive地圖的投影方式,因?yàn)槲覀兊牡厍蚴菣E球體,所以需要將其進(jìn)行相應(yīng)的投影成為笛卡爾坐標(biāo)系的坐標(biāo),我不是GIS專業(yè)的,所以原理我并沒有深入了解。當(dāng)你在用OpenDrive地圖時,你可以使用georeference中給出的proj字符串,通過pyproj(一個python的庫,可以處理很多GIS方面的問題)設(shè)定對應(yīng)關(guān)系,來完成諸如WGS84向opendrive慣性坐標(biāo)的轉(zhuǎn)換。(具體的對應(yīng)關(guān)系以及proj的投影問題可以去proj的官網(wǎng)或者CSDN學(xué)習(xí)下,pyproj里面的CRS支持直接輸入proj字符串進(jìn)行解析,不需要你弄懂他的構(gòu)造)。下圖中是我標(biāo)出的proj字符串位置:
第二類是Roads類,這是我們要最著重講的環(huán)節(jié),Roads類中包含著所有地圖中描述了的道路,每一條道路被一對road標(biāo)簽表示。讓我們根據(jù)實(shí)例先看一眼road在OpenDrive是如何表述的
這是我在OpenDrive中挑選的一個road元素,可以看到拿這個圖片結(jié)合上面的結(jié)構(gòu)圖片對比一下,我框選出來的road中比較重要的元素包括link、planView、lanes等,接下來我們會一一進(jìn)行講解。
首先要介紹的是road自身的屬性
可以看到上面的屬性包括name即道路的名字,這個屬性并非必須,length是道路的總長度,還記得我們上面說過的st坐標(biāo)系取值么,其中的[0,length]就是這個length。id是一種專屬于道路的唯一屬性,OpenDrive文件中不允許出現(xiàn)兩個ID相同的道路。junction是標(biāo)明該道路是否屬于一個junction(交叉口,這個元素我們后面會講,你目前可以將他理解為一個道路關(guān)系的集合,專門用來處理復(fù)雜道路連接情況的)如果該道路屬于一個junction,那么junction屬性的值就是所屬junction的id。
接下來就是road中包含的諸多屬性,在最開始我們要介紹的就是參考線,是我認(rèn)為整個road中最重要的元素,首先我想希望讀者您在腦海中構(gòu)想出一條道路,不考慮該道路上的車道和寬度,將其抽象為一條線,這大致就是參考線的雛形了,在這里,我先給出一張圖,
這張圖表示了一個道路的組成,我希望讀者重點(diǎn)觀察參考線和道路、車道之間的關(guān)系,你要知道的一點(diǎn)是,絕大部分情況下,參考線代表了道路的大體走勢。
接下來的問題是,我們該如何用公式和數(shù)字表示參考線呢?請記住下面的話:**一條道路只能有一條參考線,而一條參考線可以有多條幾何線構(gòu)成。**是的,我們使用一種叫做幾何線(geometry)的元素來表示參考線。為什么要用多條幾何線來表示參考線呢,因?yàn)槲覀儫o法保證一條道路的走勢是完全一致的,設(shè)想一條前半段為直線后半段為曲線的道路,如果想方便的用方程對其進(jìn)行表示,分段表示是最好的選擇,而這種分段,就是幾何線表示參考線的遠(yuǎn)離所在。
我們來看一下參考線和幾何線在opendrive中是被如何表示的:
你可以仔細(xì)看一下上圖中的元素,猜想一下其中元素的含義,我可以先告訴你,這一條道路由兩條直線幾何線和一條弧線幾何線構(gòu)成,我用matplotlib把這條道路用點(diǎn)畫出來就是下面的效果
這是一整條道路,最右面紅色的點(diǎn)代表的就是參考線(為什么你后面就知道了),現(xiàn)在你應(yīng)該可以大致看出端倪了,在下面我們會對這條道路做詳細(xì)分析。
為了更好理解我們要做的事情,接下來我們了解幾種比較常用的幾何線;
首先是直線,直線是最常用的元素,在OpenDrive中用line來表示。直線有四個屬性,首先是S值,S值表示該段幾何線在參考線中的起始位置,觀察上面我給出的那條參考線并結(jié)合OpenDrive代碼,你可以發(fā)現(xiàn)表示參考線的第一條幾何線就是直線,所以第一條直線的S值就是0。其次是x, y值,xy值給出參考線起始位置在慣性坐標(biāo)系下的位置。然后是heading,該值給出起始朝向,用弧度表示,上面給出的第一條line的弧度轉(zhuǎn)化成為角度大致是-71度,最后是length屬性,給出幾何線的長度。結(jié)合上述屬性,我們可以確定這樣一條參考線。我畫出了大致的示意,希望能對你有幫助
下面要介紹的參考線是弧線,也可以理解為弧度一致的曲線,在OpenDrive中使用arc來表示,弧線的屬性除了直線所有的一切以外還包括一個curvature弧度,因?yàn)榛【€本身就是弧度恒定的曲線,這樣通過上述屬性我們就可以確定一個弧線了,還是給出大致的示意圖,希望能夠?qū)δ阌袔椭?#xff0c;注意觀察,此時弧線的起始S值與上一條直線的length一致(一定要完全掌握S值的概念和st坐標(biāo)系,要不然后面會出問題)弧度是一致的,我畫工有點(diǎn)菜,湊活看。
再介紹一個螺旋線,用spiral表示,螺旋線特點(diǎn)是他是弧度線性變化的曲線,所以在包含所有直線的屬性以外,還包含一curvStart和curvEnd屬性,為線性變化的起始點(diǎn)和終止點(diǎn)。我手中的OpenDrive實(shí)例是沒有spiral元素的,所以只能給你官方的圖實(shí)例,看出弧度線性變化的效果了么?
下面還有一個參數(shù)三次多項(xiàng)式,放在過兩天再更吧,今天已經(jīng)寫了很多了。
(2021.11.20更新)
接下來我們講解最后一個幾何線,即參數(shù)三次多項(xiàng)式,本來應(yīng)該還有一個三次多項(xiàng)式的,但是已經(jīng)被OpenDrive官方取消了,以參數(shù)三次多項(xiàng)式代替,但是我們還是要首先介紹一下三次多項(xiàng)式,以便更好的理解參數(shù)三次多項(xiàng)式。我們先給出參數(shù)三次多項(xiàng)式的方程:
三次多項(xiàng)式我們會用到一個前文提到的很少用到的坐標(biāo)系,那就是uv坐標(biāo)系,前面說過,uv坐標(biāo)系是根據(jù)st坐標(biāo)系給出偏移生成的一個坐標(biāo)系,那么是如何給定參數(shù)確定的這種偏移呢,答案是通過上面給出的a、b參數(shù),參數(shù)b負(fù)責(zé)給出相對于st坐標(biāo)系的航向角/偏向角,角度為arctan(b),參數(shù)a負(fù)責(zé)給出當(dāng)u = 0時,沿v坐標(biāo)軸的偏移量。那么聰明的你此刻一定意識到了,當(dāng)uv坐標(biāo)系與st坐標(biāo)系重合時,a = b = 0。當(dāng)我們想將uv坐標(biāo)轉(zhuǎn)換為xy坐標(biāo)時,使用下述公式:
參數(shù)三次多項(xiàng)式就暫時講這么多,接下來就是參數(shù)三次多項(xiàng)式,參數(shù)多項(xiàng)式稍稍有些復(fù)雜,我并不知道我是否能夠講好,如果你沒看懂可以去看看官方文檔或者其他人寫的。參數(shù)三次多項(xiàng)式有很多屬性:aU、bU、cU、dU、aV、bV、cV、dV、pRange,下面結(jié)合公式:
可以看出參數(shù)三次多項(xiàng)式與三次多項(xiàng)式不同,將uv坐標(biāo)系的兩個值uv分開,并引入公共參數(shù)p,注意這里的p并不是給的屬性pRange,p是需要你自己去算的插值,而這個p的取值范圍就是(0,pRange),那么我們計算p呢,下面給出我的算法:
dis / length * pRange
其中dis就是你希望在這條線上每隔多少取一個點(diǎn),length就是這條參考線的實(shí)際長度,這個算法實(shí)際上很簡單,你一定能看懂,這樣迭代dis就可以獲得一系列的p,通過這些p就可以獲得一系列的u、v,再通過上面給出的式子就可以獲得x、y,語言很抽象,下面看圖:
重點(diǎn)看第三幅圖,上面有各個參數(shù)的幾何意義,希望看到這你能夠大致理解參數(shù)三次多項(xiàng)式的結(jié)構(gòu)和格式。
總結(jié)
以上是生活随笔為你收集整理的OpenDrive格式高精度地图详细解析及其使用(1.栅格地图、OpenDrive坐标系以及参考线介绍)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VSCode批量代码比较
- 下一篇: 【数论入门】快速幂