1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ROS 八叉樹地圖構(gòu)建 - 使用 octomap_server 建圖過程總結(jié)!

        共 11100字,需瀏覽 23分鐘

         ·

        2020-08-13 00:58


        登龍

        這是我的第 146 篇原創(chuàng)


        之前的構(gòu)建語義地圖工作,最開始用的是 octomap_server:

        https://github.com/OctoMap/octomap_mapping

        后面換成了 semantic_slam octomap_generator:

        https://github.com/floatlazer/semantic_slam)

        不過還是整理下之前的學(xué)習(xí)筆記。

        一、增量構(gòu)建八叉樹地圖步驟

        為了能夠讓 octomap_server 建圖包實現(xiàn)增量式的地圖構(gòu)建,需要以下 2 個步驟:

        1.1 配置 launch 啟動參數(shù)

        這 3 個參數(shù)是建圖必備:

        • 地圖分辨率 resolution:用來初始化地圖對象
        • 全局坐標(biāo)系 frame_id:構(gòu)建的全局地圖的坐標(biāo)系
        • 輸入點云話題 /cloud_in:作為建圖的數(shù)據(jù)輸入,建圖包是把一幀一幀的點云疊加到全局坐標(biāo)系實現(xiàn)建圖
        <launch>
          <node pkg="octomap_server" type="octomap_server_node" name="octomap_server">
            
            <param name="resolution" value="0.10" />

            
            <param name="frame_id" type="string" value="map" />

            
            <remap from="/cloud_in" to="/fusion_cloud" />
          node>
        launch>

        以下是所有可以配置的參數(shù):

        • frame_id (string, default: /map)
          • Static global frame in which the map will be published. A transform from sensor data to this frame needs to be available when dynamically building maps.
        • resolution (float, default: 0.05)
          • Resolution in meter for the map when starting with an empty map. Otherwise the loaded file's resolution is used
        • height_map (bool, default: true)
          • Whether visualization should encode height with different colors
        • color/[r/g/b/a] (float)
          • Color for visualizing occupied cells when ~heigh_map=False, in range [0:1]
        • sensor_model/max_range (float, default: -1 (unlimited))
          • 動態(tài)構(gòu)建地圖時用于插入點云數(shù)據(jù)的最大范圍(以米為單位),將范圍限制在有用的范圍內(nèi)(例如 5m)可以防止虛假的錯誤點。
        • sensor_model/[hit|miss] (float, default: 0.7 / 0.4)
          • 動態(tài)構(gòu)建地圖時傳感器模型的命中率和未命中率
        • sensor_model/[min|max] (float, default: 0.12 / 0.97)
          • 動態(tài)構(gòu)建地圖時的最小和最大 clamp 概率
        • latch (bool, default: True for a static map, false if no initial map is given)
          • 不管主題是鎖定發(fā)布還是每次更改僅發(fā)布一次,為了在構(gòu)建地圖(頻繁更新)時獲得最佳性能,請將其設(shè)置為 false,如果設(shè)置為 true,在每個地圖上更改都會創(chuàng)建所有主題和可視化。
        • base_frame_id(string, default: base_footprint)
          • The robot's base frame in which ground plane detection is performed (if enabled)
        • filter_ground(bool, default: false)
          • 動態(tài)構(gòu)建地圖時是否應(yīng)從掃描數(shù)據(jù)中檢測并忽略地平面,這會將清除地面所有內(nèi)容,但不會將地面作為障礙物插入到地圖中。如果啟用此功能,則可以使用 ground_filter 對其進(jìn)行進(jìn)一步配置
        • ground_filter/distance (float, default: 0.04)
          • 將點(在 z 方向上)分割為接地平面的距離閾值,小于該閾值被認(rèn)為是平面
        • ground_filter/angle (float, default: 0.15)
          • 被檢測平面相對于水平面的角度閾值,將其檢測為地面
        • ground_filter/plane_distance (float, default: 0.07)
          • 對于要檢測為平面的平面,從 z = 0 到距離閾值(來自 PCL 的平面方程的第 4 個系數(shù))
        • pointcloud_[min|max]_z (float, default: -/+ infinity)
          • 要在回調(diào)中插入的點的最小和最大高度,在運(yùn)行任何插入或接地平面濾波之前,將丟棄此間隔之外的任何點。您可以以此為基礎(chǔ)根據(jù)高度進(jìn)行粗略過濾,但是如果啟用了 ground_filter,則此間隔需要包括接地平面。
        • occupancy_[min|max]_z (float, default: -/+ infinity)
          • 最終 map 中要考慮的最小和最大占用單元格高度,發(fā)送可視化效果和碰撞 map 時,這會忽略區(qū)間之外的所有已占用體素,但不會影響實際的 octomap 表示。
        • filter_speckles(bool)
          • 是否濾除斑

        1.2 要求 TF 變換

        有了全局坐標(biāo)系和每一幀的點云,但是建圖包怎么知道把每一幀點云插入到哪個位置呢?

        因為隨著機(jī)器人的不斷移動,會不斷產(chǎn)生新的點云幀,每個點云幀在全局坐標(biāo)系中插入的時候都有一個確定的位置,否則構(gòu)建的地圖就不對了,因此需要給建圖包提供一個當(dāng)前幀點云到全局坐標(biāo)系的位姿,這樣建圖包才能根據(jù)這個位姿把當(dāng)前獲得的點云插入到正確的位置上。

        在 ROS 中可以很方便的使用 TF 來表示這個變換,我們只需要在啟動建圖包的時候,在系統(tǒng)的 TF 樹中提供「cloud frame -> world frame」的變換就可以了:

        cloud frame -> world frame (static world frame, changeable with parameter frame_id)

        注意:

        • cloud frame:就是輸入點云話題中 head.frame_id,比如 Robosense 雷達(dá)的 frame_id = rslidar
        • world frame:這是全局坐標(biāo)系的 frame_id,在啟動 launch 中需要手動給定,比如我給的是 map

        如果你給 world frame id 指定的是輸入點云的 frame_id,比如 fusion_cloud.head.frame_id == wolrd_frame_id == rslidar,則只會顯示當(dāng)前幀的八叉樹,而不會增量構(gòu)建地圖,這點要注意了,可以自己測試看看。

        那么為了增量式建圖,還需要在系統(tǒng)的 TF 樹中提供「rslidar -> world」的變換,這個變換可以通過其他的 SLAM 等獲得,比如我測試時候的一個 TF 樹如下:

        我找了下源代碼 OctomapServer.cpp 中尋找 TF 的部分:

         tf::StampedTransform sensorToWorldTf;
          try {
            m_tfListener.lookupTransform(m_worldFrameId, cloud->header.frame_id, cloud->header.stamp, sensorToWorldTf);
          } catch(tf::TransformException& ex){
            ROS_ERROR_STREAM( "Transform error of sensor data: " << ex.what() << ", quitting callback");
            return;
          }

        總體來說這個建圖包使用起來還是挺簡單的,最重要的就是要寫清楚輸入點云話題和 TF 變換。

        小 Tips:沒有 TF 怎么辦?

        我剛開始建圖的時候,我同學(xué)錄制的 TF 樹中并沒有「world -> rslidar」的變換,只有「world -> base_link」,所以為了能夠測試增量式建圖,因為我的點云幀的 frame_id 是 rslidar,因此我就手動發(fā)布了一個靜態(tài)的「base_link -> rslidar」的變換:

        rosrun tf2_ros static_transform_publisher 0 0 0 0 0 0 base_link rslidar

        這樣系統(tǒng)中就有「rslidar -> world」的變換了,但是我發(fā)的位姿都是 0,所以對建圖測試沒有影響,為了方便啟動,放在 launch 中:

        
             

        如果你也遇到這個問題,可以試試發(fā)個靜態(tài) TF 做做測試,關(guān)于靜態(tài) TF 詳細(xì)技術(shù)可以參考之前的文章:ROS 機(jī)器人技術(shù) - 靜態(tài) TF 坐標(biāo)幀

        二、ColorOctomap 啟用方法

        為了顯示 RGB 顏色,我分析了下源碼,第一步修改頭文件,打開注釋切換地圖類型:OctomapServer.h

        // switch color here - easier maintenance, only maintain OctomapServer. 
        // Two targets are defined in the cmake, octomap_server_color and octomap_server. One has this defined, and the other doesn't
        // 打開這個注釋
        #define COLOR_OCTOMAP_SERVER

        #ifdef COLOR_OCTOMAP_SERVER
          typedef pcl::PointXYZRGB PCLPoint;
          typedef pcl::PointCloud  PCLPointCloud;
           typedef octomap::ColorOcTree OcTreeT;
        #else
           typedef pcl::PointXYZ PCLPoint;
           typedef pcl::PointCloud  PCLPointCloud;
           typedef octomap::OcTree OcTreeT;
        #endif

        CMakeList.txt 文件中有 COLOR_OCTOMAP_SERVER 的編譯選項:

        target_compile_definitions(${PROJECT_NAME}_color PUBLIC COLOR_OCTOMAP_SERVER)

        OctomapServer.cpp 中有 colored_map 的參數(shù):

        m_useHeightMap = true;
        m_useColoredMap = false;
          
        m_nh_private.param("height_map", m_useHeightMap, m_useHeightMap);
        m_nh_private.param("colored_map", m_useColoredMap, m_useColoredMap);

        地圖默認(rèn)是按照高度設(shè)置顏色,如果要設(shè)置為帶顏色的地圖,就要禁用 HeightMap,并啟用 ColoredMap:

        if (m_useHeightMap && m_useColoredMap) {
            ROS_WARN_STREAM("You enabled both height map and RGB color registration. This is contradictory. Defaulting to height map.");
            m_useColoredMap = false;
          }

        第二步、需要在 octomap_server 的 launch 文件中禁用 height_map,并啟用 colored_map :

        <param name="height_map" value="false" />
        <param name="colored_map" value="true" />

        2 個核心的八叉樹生成函數(shù) insertCloudCallbackinsertScan 中有對顏色的操作:

        #ifdef COLOR_OCTOMAP_SERVER
          unsigned char* colors = new unsigned char[3];
        #endif

        // NB: Only read and interpret color if it's an occupied node
        #ifdef COLOR_OCTOMAP_SERVER 
                m_octree->averageNodeColor(it->x, it->y, it->z, /*r=*/it->r, /*g=*/it->g, /*b=*/it->b);
        #endif

        三、保存和顯示地圖

        啟動 octomap_server 節(jié)點后,可以使用它提供的地圖保存服務(wù),保存壓縮的二進(jìn)制存儲格式地圖:

        octomap_saver mapfile.bt

        保存一個完整的概率八叉樹地圖:

        octomap_saver -f mapfile.ot

        安裝八叉樹可視化程序 octovis 來查看地圖:

        sudo apt-get install octovis

        安裝后重啟終端,使用以下命令顯示一個八叉樹地圖:

        octovis xxx.ot[bt]

        四、源碼閱讀筆記

        在開組會匯報的時候,整理了以下這個建圖包的關(guān)鍵流程,只有 2 個關(guān)鍵的函數(shù)也不是很復(fù)雜,我給代碼加了注釋,在文末可以下載。

        第一步是訂閱點云的回調(diào):

        第二步是插入單幀點云構(gòu)建八叉樹,這里就不詳細(xì)介紹過程了,因為涉及到八叉樹庫 octomap 的更新原理:

        放一張我們學(xué)院后面的一條小路的建圖結(jié)果,分辨率是 15cm:

        以下是我建圖過程的 launch:

        <launch>
          <node pkg="octomap_server" type="octomap_server_node" name="octomap_server">
            
            <param name = "resolution" value = "0.15" />

            
            
            <param name = "frame_id" type = "string" value = "camera_init" />

            
            <param name = "sensor_model/max_range" value = "15.0" />

            
            

            
         
            
            
         

            
            
            

            

            <param name = "height_map" value = "false" />
            <param name = "colored_map" value = "true" />
         
            
            <param name = "outrem_radius" type = "double" value = "1.0" />
            <param name = "outrem_neighbors" type = "int" value = "10" />

            
            <param name = "latch" value = "false" /> 

            
            
            
            <remap from = "/cloud_in" to = "/fusion_cloud" />
         
          node>
        launch>

        我做的項目代碼在這里 AI - Notes: semantic_map:

        https://github.com/DLonng/AI-Notes/tree/master/SemanticMap/semantic_map_ws

        推薦閱讀:

        ROS 八叉樹地圖構(gòu)建 - 安裝 octomap 和 octomap_server 建圖包!


        廈大同學(xué),與你分享編程,AI 算法等技術(shù)干貨!精品文章創(chuàng)作不易,謝謝關(guān)注,歡迎在看。

        點擊閱讀原文,查看更多精彩文章!

        瀏覽 123
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            人妻无码一区二区 | 91国语对白精品露脸 | 成人毛片免费观看无需播放器 | 可爱男生龟责榨精到哭污小说 | 成年黄网站18禁免费观看在线 | 午夜操 | 精品三区| 国产AV无码成人精品毛片 | 老牛久久 | 羽月希被黑人吃奶dsd585 |