當前位置: 華文星空 > 汽車

如何基於ROS學習雷射SLAM?

2021-10-24汽車

lio-sam,緊耦合的雷達和IMU雷射slam方法

imageProjection部份:

主要的功能為點雲去畸變,需要點雲中每個點包含有time這個標簽。

首先imuQueue將每一個imu原始資訊變換到雷達系下,依次入列。

imuRotX,imuRotY,imuRotZ,以及imuTime這幾個佇列裏面存放的是相鄰兩幀之間的imu角速度積分得到的旋轉角度,第一個為0。

這裏cloudInfo的初始值由OdomMsg提供。本來imu用來進行角度畸變去除,odom進行平移畸變去除。但是由於平移畸變太小,所以沒有用。

ProjectPointCloud(), 此函式的主要作用為利用去畸變得到的點雲做rangeMat的投影。根據點的實際位置算出其相應的行列座標。

cloudExtraction(), 此函式的主要作用為統計有效點的數量,利用之前的rangeMat,只取在其上有效的點。點的總數量為count。另外,該函式還根據不同的ring獲得了每一個ring的起始點雲索引。

最後,publishClouds()函式的作用為釋出提取的有效的點雲以及cloudInfo。

cloudInfo包含如下資訊:

  • imuRollInit, imuPitchInit,imuYawInit
  • imuAvailable
  • odomAvailable
  • initialGuess(6) 根據odomMsg得到
  • startRingIndex(vector) 16個元素 endRingIndex(vector)
  • pointColInd 每一個有效點的列索引(0-1800)
  • pointRange 每一個點的range
  • imuPreintegration部份

    transfusion這個物件主要的作用為視覺化軌跡和odom,作用不是很大,subLaserOdometry接受的話題為mapping部份的裏程計訊息,然後作為一個低頻的lidar odom入列。

    subImuOdometry接受的話題為預積分後的imu裏程計訊息,這個訊息作為一個高頻的訊息,首先入列。然後根據當前時刻和上一幀的雷達裏程計時刻之間的imu odom訊息。根據座標變換得到兩個時刻之間的座標增量。用該增量乘之前的雷達裏程計,釋出imu頻率的odom,以及path。

    IMUPreintegration物件是imu預積分的主要物件。該物件訂閱imu的原始訊息以及lio_sam/mapping/odometry_incremental。

    其中odometryHandler主要作用為接受低頻的mapping的odom訊息,加入imu預積分的因子圖中,然後最佳化imu預積分。註意,由於imu的訊息在另一個行程中不斷入列,所以在while迴圈結束後需要繼續進行一下imu預積分(當imu頻率不是很高的時候)。

    imuIntegratorImu_->resetIntegrationAndSetBias(prevBiasOdom);

    imuHandler的作用就是根據每次更新的bias以imu的頻率輸出。

    FeatureExtraction部份

    主要的功能為提取去畸變後的角點和平面點。

    calculateSmoothness()根據公式計算每一個點雲的光滑度,這裏註意,當點在建築物的邊緣上時,曲率很大,必然是角點。

    markOccludedPoints()主要的功能為濾除遮擋點,遮擋點定義如下,A點和B點是相鄰點,但是A點在B點後面很多,所以A點之前的5個點很容易被遮擋,因此他們被濾除。平行點。當雷射照射到一個和雷射入射角接近的平面時,很容易誤辨識角點,所以這些點被濾除。

    extractFeatures()首先空間區域被均勻分成六份,每個區域的點按照光滑度有小到大排列,每個區域至多取20個角點。另外,當取得一個角點時,為防止聚集,他周圍10個相鄰像素的點都會被濾除。

    publishFeatureCloud() 該函式的主要作用為釋出特征點雲。

    cloudInfo包含有cloud_corner和cloud_surface兩個點雲。

    mapOptimization部份

    主要的功能就在於構建因子圖實作全域最佳化,重點的函式是幀間匹配的LM演算法。

    laserCloudHandler()接受imageProjection節點中去畸變後的點雲,該點雲有三部份的訊息,去畸變的點雲的角點和平面點,imu的原始資訊,imu裏程計的資訊。

  • updateInitialGuess(),transformTobeMapped這個六維向量首先用imu的原始值填充RPY。
    如果odomAvailiable,transFinal這個齊次矩陣存放的是增量後的map系下的初值,然後賦值給到transformTobeMapped的其他項。
    如果imuAvailable,那麽重復上述操作,應該是防止上述的odom不可用。
  • extractSurroundingKeyFrames()。主要的函式是extractNearby()。該函式首先得到surroundingKeyPosesDS,這個是當前幀點雲附近的一些關鍵幀位置的降采樣。然後送入到extractCloud()這個函式中,該函式的主要作用為根據之前的附近關鍵位置,將其上的點雲資訊變換到map系下,生成Corner和Surf點雲:laserCloudCornerFromMap,laserCloudSurfFromMap,然後將他們註冊到laserCloudMapContainer。這個容器超過1000會自動重設,裏面存放的臨時的laserCloud的角點和平面點
  • downsampleCurrentScan(),這個函式的主要作用為當前幀的角點和平面點點雲降采樣。
  • scan2MapOptimization(),這個函式主要的作用就是LM最佳化了,在本函式中一共設定了30次的最佳化限制。
    1. cornerOptimization(),角點最佳化函式。首先將當前幀的一個角點變化到map系,然後尋找離他最近的五個角點,判斷這五個角點是否在一條直線上。如果是,保留三個變量,原始角點,距離變量,flag。
    2. surfOptimization(),平面點最佳化函式。首先選擇最近的五個平面點,判斷其是否可以組成平面,如果可以,則保留原始平面點,距離變量,flag。
    3. combineOptimizationCoeffs(),聯合最佳化函式。將上述的角點和平面點的相關資訊一起推入laserCloudOri和coeffSel兩個量中。
    4. LMOptimization(),LM最佳化過程,最繁瑣的一塊。使用的是張繼的LOAM的一套,推導很麻煩,反正一句話,最佳化了transformTobeMapped這個量,但說是LM,看起來是牛頓歐拉法。
    5. transformUpdate(),更新最佳化後得到的幀間變換。但註意這個也是更新transformTobeMapped,不同之處在於加權了IMU的原始資訊,為啥怎麽相信IMU呢?。
  • saveKeyFramesAndFactor(),主要的作用是保存關鍵幀,給gtsam的因子圖增加Odom,GPS,Loop的因子。
    1. addOdomFactor(),將相鄰兩幀之間的關鍵幀加入因子圖,增量用transformTobeMapped的值
    2. addGPSFactor(),如果沒有關鍵幀,或者首尾關鍵幀距離小於5m,不添加gps因子,位姿共變異數很小,沒必要加入GPS數據進行校正,每隔5m添加一個GPS裏程計。
    3. addLoopFactor(),閉環邊對應兩幀的索引,閉環邊的位姿變換。加入因子圖後,清空loopIndexQueue();
    4. 加入cloudKeyPoses3D以及cloudKeyPoses6D。poseCovariance保留的是位姿的共變異數,判斷是否需要加GPS因子用的。最後更新一下transformTobeMapped。cornerCloudKeyFrames和surfCloudKeyFrames壓入當前幀的角點和平面點資訊。
    5. updatePath(),把當前幀的位姿資訊壓入globalPath。
  • correctPoses(),當存在了回環後,需要及時更新cloudKeyPoses3D以及cloudKeyPoses6D的位姿資訊,然後globalPath也要更新一下。
  • publishOdometry(),釋出odom訊息以及lidar_link到odom的tf變換。increOdomAffine是最佳化過後的當前幀位姿odom在map系下的表示,之後在和imu加權一下。pubLaserOdometryIncremental.publish(laserOdomIncremental),釋出這一裏程計,給imu預積分使用
  • publishFrames(),釋出一些cloud和path之類。
  • loopClosureThread()回環執行緒

    回環執行緒需要用到icp,這是一個非常耗時的操作,因此回環需要精確確定,而且回環的間隔要較大,這裏不只是兩個節點要相隔一段時間,也需要兩個回環之間不要靠太近。

  • performLoopClosure()
    1. detectLoopClosureExternal,檢測外部回環的程式,這裏沒有用到
    2. detectLoopClosureDistance,判斷回環兩個節點之間的時間戳
    3. loopFindNearKeyframes(),提取key附近的點雲包括角點和平面點。之後liyongICP得到兩個關鍵幀之間的位姿變換關系,加入因子圖。loopIndexQueue壓入當前資訊,loopIndexContainer壓入防止多次將一個回環加入因子圖和展示。
  • visualizeLoopClosure(),在rviz展示回環。
  • visualizeGlobalMapThread()執行緒

    以一定的頻率釋出GlobalMap,和提供saveMap的服務saveMapService