0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一個利用GT-SAM的緊耦合激光雷達慣導(dǎo)里程計的框架

3D視覺工坊 ? 來源:古月居 ? 作者:月照銀海似蛟龍 ? 2022-10-31 09:25 ? 次閱讀

前言

LIO-SAM的全稱是:Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping,從全稱上可以看出,該算法是一個緊耦合的雷達慣導(dǎo)里程計(Tightly-coupled Lidar Inertial Odometry),借助的手段就是利用GT-SAM庫中的方法。

LIO-SAM 提出了一個利用GT-SAM的緊耦合激光雷達慣導(dǎo)里程計的框架。實現(xiàn)了高精度、實時的移動機器人的軌跡估計和建圖。在之前的博客講解了imu如何進行預(yù)積分,最終以imu的頻率發(fā)布了imu的預(yù)測位姿里程計。

fbb2dc46-58aa-11ed-a3b6-dac502259ad0.png

本篇博客主要講解,最終是如何進行位姿融合輸出的

fbcbbef0-58aa-11ed-a3b6-dac502259ad0.png

Eigen::Affine3f

其中功能的核心在于 位姿間的變換,所以要了解 Eigen::Affine3f 部分的內(nèi)容,Affine3f 是eighen庫的仿射變換矩陣

實際上就是:平移向量+旋轉(zhuǎn)變換組合而成,可以同時實現(xiàn)旋轉(zhuǎn),縮放,平移等空間變換。

Eigen庫中,仿射變換矩陣的大致用法為:

創(chuàng)建Eigen::Affine3f 對象a。

創(chuàng)建類型為Eigen::Translation3f 對象b,用來存儲平移向量;

創(chuàng)建類型為Eigen::Quaternionf 四元數(shù)對象c,用來存儲旋轉(zhuǎn)變換;

最后通過以下方式生成最終Affine3f變換矩陣:a=b*c.toRotationMatrix();

一個向量通過仿射變換時的方法是result_vector=test_affine*test_vector;

仿射變換包括:平移、旋轉(zhuǎn)、放縮、剪切、反射

平移(translation)和旋轉(zhuǎn)(rotation)顧名思義,兩者的組合稱之為歐式變換(Euclidean transformation)或剛體變換(rigid transformation);

放縮(scaling)可進一步分為uniform scaling和non-uniform scaling,前者每個坐標軸放縮系數(shù)相同(各向同性),后者不同;

如果放縮系數(shù)為負,則會疊加上反射(reflection)——reflection可以看成是特殊的scaling;

剛體變換+uniform scaling 稱之為,相似變換(similarity transformation),即平移+旋轉(zhuǎn)+各向同性的放縮;

位姿融合輸出

在imu預(yù)積分的節(jié)點中,在main函數(shù)里面 還有一個類的實例對象,那就是

TransformFusion TF

其主要功能是做位姿融合輸出,最終輸出imu的預(yù)測結(jié)果,與上節(jié)中的imu預(yù)測結(jié)果的區(qū)別就是:

該對象的融合輸出是基于全局位姿的基礎(chǔ)上再進行imu的預(yù)測輸出。全局位姿就是 經(jīng)過回環(huán)檢測后的lidar位姿。

fbe75688-58aa-11ed-a3b6-dac502259ad0.png

建圖優(yōu)化會輸出兩種激光雷達的位姿:

lidar 增量位姿

lidar 全局位姿

其中l(wèi)idar 增量位姿就是 通過 lidar的匹配功能,優(yōu)化出的幀間的相對位姿,通過相對位姿的累積,形成世界坐標系下的位姿

lidar全局位姿 則是在 幀間位姿的基礎(chǔ)上,通過 回環(huán)檢測,再次進行優(yōu)化的 世界坐標系下的位姿,所以對于增量位姿,全局位姿更加精準

在前面提到的發(fā)布的imu的預(yù)測位姿是在lidar的增量位姿上基礎(chǔ)上預(yù)測的,那么為了更加準確,本部分功能就預(yù)測結(jié)果,計算到基于全局位姿的基礎(chǔ)上面。首先看構(gòu)造函數(shù)

  TransformFusion()  {    if(lidarFrame != baselinkFrame)    {      try      {          tfListener.waitForTransform(lidarFrame, baselinkFrame, ros::Time(0), ros::Duration(3.0));        tfListener.lookupTransform(lidarFrame, baselinkFrame, ros::Time(0), lidar2Baselink);      }      catch (tf::TransformException ex)      {        ROS_ERROR("%s",ex.what());      }    }

判斷l(xiāng)idar幀和baselink幀是不是同一個坐標系,通常baselink指車體系,如果不是,查詢 一下 lidar 和baselink 之間的 tf變換 ros::Time(0) 表示最新的,等待兩個坐標系有了變換,更新兩個的變換 lidar2Baselink

    subLaserOdometry = nh.subscribe("lio_sam/mapping/odometry", 5, &TransformFusion::lidarOdometryHandler, this, ros::TransportHints().tcpNoDelay());    subImuOdometry  = nh.subscribe(odomTopic+"_incremental",  2000, &TransformFusion::imuOdometryHandler,  this, ros::TransportHints().tcpNoDelay());

訂閱地圖優(yōu)化的節(jié)點的全局位姿 和預(yù)積分節(jié)點的 增量位姿

    pubImuOdometry  = nh.advertise(odomTopic, 2000);    pubImuPath    = nh.advertise  ("lio_sam/imu/path", 1);

發(fā)布兩個信息 odomTopic ImuPath,然后看第一個回調(diào)函數(shù)lidarOdometryHandler

  void lidarOdometryHandler(const nav_msgs::ConstPtr& odomMsg)  {    std::lock_guard lock(mtx);    lidarOdomAffine = odom2affine(*odomMsg);    lidarOdomTime = odomMsg->header.stamp.toSec();  }

將全局位姿保存下來,將ros的odom格式轉(zhuǎn)換成 Eigen::Affine3f 的形式,將最新幀的時間保存下來,第二個回調(diào)函數(shù)是imuOdometryHandler,imu預(yù)積分之后所發(fā)布的imu頻率的預(yù)測位姿

  void imuOdometryHandler(const nav_msgs::ConstPtr& odomMsg)  {

    static tf::TransformBroadcaster tfMap2Odom;    static tf::Transform map_to_odom = tf::createQuaternionFromRPY(0, 0, 0), tf::Vector3(0, 0, 0));

建圖的話 可以認為 map坐標系和odom坐標系 是重合的(初始化時刻)

tfMap2Odom.sendTransform(tf::StampedTransform(map_to_odom, odomMsg->header.stamp, mapFrame, odometryFrame));

發(fā)布靜態(tài)tf,odom系和map系 他們是重合的

imuOdomQueue.push_back(*odomMsg);

imu得到的里程計結(jié)果送入到這個隊列中

    if (lidarOdomTime == -1)      return;

如果沒有收到lidar位姿 就returen

    while (!imuOdomQueue.empty())    {      if (imuOdomQueue.front().header.stamp.toSec() <= lidarOdomTime)        imuOdomQueue.pop_front();      else        break;    }

彈出時間戳 小于 最新 lidar位姿時刻之前的imu里程計數(shù)據(jù)

    Eigen::Affine3f imuOdomAffineFront = odom2affine(imuOdomQueue.front());    Eigen::Affine3f imuOdomAffineBack = odom2affine(imuOdomQueue.back());    Eigen::Affine3f imuOdomAffineIncre = imuOdomAffineFront.inverse() * imuOdomAffineBack;

計算最新隊列里imu里程計的增量

Eigen::Affine3f imuOdomAffineLast = lidarOdomAffine * imuOdomAffineIncre;

增量補償?shù)絣idar的位姿上去,就得到了最新的預(yù)測的位姿

    float x, y, z, roll, pitch, yaw;    pcl::getTranslationAndEulerAngles(imuOdomAffineLast, x, y, z, roll, pitch, yaw);

分解成平移 + 歐拉角的形式

    nav_msgs::Odometry laserOdometry = imuOdomQueue.back();    laserOdometry.pose.pose.position.x = x;    laserOdometry.pose.pose.position.y = y;    laserOdometry.pose.pose.position.z = z;    laserOdometry.pose.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(roll, pitch, yaw);    pubImuOdometry.publish(laserOdometry);

發(fā)送全局一致位姿的 最新位姿

    static tf::TransformBroadcaster tfOdom2BaseLink;    tf::Transform tCur;    tf::poseMsgToTF(laserOdometry.pose.pose, tCur);    if(lidarFrame != baselinkFrame)      tCur = tCur * lidar2Baselink;

更新tf

    tf::StampedTransform odom_2_baselink = tf::StampedTransform(tCur, odomMsg->header.stamp, odometryFrame, baselinkFrame);    tfOdom2BaseLink.sendTransform(odom_2_baselink);

更新odom到baselink的tf

    static nav_msgs::Path imuPath;    static double last_path_time = -1;    double imuTime = imuOdomQueue.back().header.stamp.toSec();    // 控制一下更新頻率,不超過10hz    if (imuTime - last_path_time > 0.1)    {      last_path_time = imuTime;      geometry_msgs::PoseStamped pose_stamped;      pose_stamped.header.stamp = imuOdomQueue.back().header.stamp;      pose_stamped.header.frame_id = odometryFrame;      pose_stamped.pose = laserOdometry.pose.pose;      // 將最新的位姿送入軌跡中      imuPath.poses.push_back(pose_stamped);      // 把lidar時間戳之前的軌跡全部擦除      while(!imuPath.poses.empty() && imuPath.poses.front().header.stamp.toSec() < lidarOdomTime - 1.0)        imuPath.poses.erase(imuPath.poses.begin());      // 發(fā)布軌跡,這個軌跡實踐上是可視化imu預(yù)積分節(jié)點輸出的預(yù)測值      if (pubImuPath.getNumSubscribers() != 0)      {        imuPath.header.stamp = imuOdomQueue.back().header.stamp;        imuPath.header.frame_id = odometryFrame;        pubImuPath.publish(imuPath);      }    }  }

發(fā)布imu里程計的軌跡,控制一下更新頻率,不超過10hz,將最新的位姿送入軌跡中,把lidar時間戳之前的軌跡全部擦除,發(fā)布軌跡,這個軌跡實踐上是可視化imu預(yù)積分節(jié)點輸出的預(yù)測值

result

fbfb02c8-58aa-11ed-a3b6-dac502259ad0.png

其中粉色的部分就是imu的位姿融合輸出path。







審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 移動機器人
    +關(guān)注

    關(guān)注

    2

    文章

    762

    瀏覽量

    33573
  • SLAM
    +關(guān)注

    關(guān)注

    23

    文章

    424

    瀏覽量

    31833
  • 激光雷達
    +關(guān)注

    關(guān)注

    968

    文章

    3972

    瀏覽量

    189930
  • 回調(diào)函數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    87

    瀏覽量

    11563

原文標題:3d激光SLAM:LIO-SAM框架-位姿融合輸出

文章出處:【微信號:3D視覺工坊,微信公眾號:3D視覺工坊】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    #硬聲創(chuàng)作季 LIO-SAM耦合激光雷達-慣性里程計

    激光SAM計算機視覺
    Mr_haohao
    發(fā)布于 :2022年10月12日 15:21:47

    激光雷達分類以及應(yīng)用

    激光雷達實際上是種工作在光學(xué)波段(特殊波段)的雷達,它的優(yōu)點非常明顯:1、具有極高的分辨率:激光雷達工作于光學(xué)波段,頻率比微波高2~3數(shù)
    發(fā)表于 09-19 15:51

    常見激光雷達種類

    單線激光雷達特點:結(jié)構(gòu)簡單、掃描速度快、分辨率高、可靠性高、成本低。單線激光雷達實際上就是高同頻激光脈沖掃描儀,加上
    發(fā)表于 09-25 11:30

    激光雷達

    想了解行業(yè)國內(nèi)做固態(tài)激光雷達的廠家,激光雷達里面是怎么樣的啊
    發(fā)表于 01-17 15:29

    如何理解SLAM用到的傳感器輪式里程計IMU、雷達、相機的工作原理與使用場景?精選資料分享

    視覺慣性里程計 綜述 VIO Visual Inertial Odometry msckf ROVIO ssf msf okvis ORB-VINS VINS-Mono gtsam目錄里程計
    發(fā)表于 07-27 07:21

    請問如何理解SLAM用到的傳感器輪式里程計IMU、雷達、相機的工作原理?

    請問如何理解SLAM用到的傳感器輪式里程計IMU、雷達、相機的工作原理?
    發(fā)表于 10-09 08:52

    計算機視覺方向簡介之視覺慣性里程計

    實現(xiàn)SLAM的算法,根據(jù)融合框架的不同又分為松耦合耦合。 其中VO(visual odometry)指僅視覺的里程計,T表示位置和姿態(tài)。
    的頭像 發(fā)表于 04-07 16:57 ?2599次閱讀
    計算機視覺方向簡介之視覺慣性<b class='flag-5'>里程計</b>

    利用GT-SAM耦合激光雷達導(dǎo)里程計框架

    從全稱上可以看出,該算法是耦合雷達導(dǎo)
    的頭像 發(fā)表于 09-14 10:11 ?1834次閱讀

    種快速的激光視覺導(dǎo)融合的slam系統(tǒng)

    建立在兩基于直接法的耦合的完整的激光視覺
    的頭像 發(fā)表于 11-09 09:55 ?1541次閱讀

    輪式移動機器人里程計分析

    方案(ORB SLAM)、基于激光雷達里程計方案(Hector SLAM)、基于IMU的里程計方案,以及多傳感器融合的方案。
    的頭像 發(fā)表于 04-19 10:17 ?1929次閱讀

    介紹種新的全景視覺里程計框架PVO

    論文提出了PVO,這是種新的全景視覺里程計框架,用于實現(xiàn)場景運動、幾何和全景分割信息的更全面建模。
    的頭像 發(fā)表于 05-09 16:51 ?1852次閱讀
    介紹<b class='flag-5'>一</b>種新的全景視覺<b class='flag-5'>里程計</b><b class='flag-5'>框架</b>PVO

    基于相機和激光雷達的視覺里程計和建圖系統(tǒng)

    提出種新型的視覺-LiDAR里程計和建圖系統(tǒng)SDV-LOAM,能夠綜合利用相機和激光雷達的信息,實現(xiàn)高效、高精度的姿態(tài)估計和實時建圖,且性能優(yōu)于現(xiàn)有的相機和
    發(fā)表于 05-15 16:17 ?758次閱讀
    基于相機和<b class='flag-5'>激光雷達</b>的視覺<b class='flag-5'>里程計</b>和建圖系統(tǒng)

    3d激光SLAMLIO-SAM框架介紹

    導(dǎo)里程計(Tightly-coupled Lidar Inertial Odometry),借助的手段就是利用GT-SAM庫中的方法。 L
    的頭像 發(fā)表于 11-22 15:04 ?1127次閱讀
    3d<b class='flag-5'>激光</b>SLAMLIO-<b class='flag-5'>SAM</b><b class='flag-5'>框架</b>介紹

    LIO-SAM框架是什么

    導(dǎo)里程計(Tightly-coupled Lidar Inertial Odometry),借助的手段就是利用GT-SAM庫中的方法。 L
    的頭像 發(fā)表于 11-24 17:08 ?1222次閱讀
    LIO-<b class='flag-5'>SAM</b><b class='flag-5'>框架</b>是什么

    激光雷達在SLAM算法中的應(yīng)用綜述

    SLAM算法運行的重要傳感器。基于激光雷達的SLAM算法,對激光雷達SLAM總體框架進行介紹,詳細闡述前端里程計、后端優(yōu)化、回環(huán)檢測、地圖構(gòu)建模塊的作用并總結(jié)所使用的算法;按由2D到
    的頭像 發(fā)表于 11-12 10:30 ?585次閱讀
    <b class='flag-5'>激光雷達</b>在SLAM算法中的應(yīng)用綜述