跳到正文

Wiki

small_gicp_relocalization(先驗點雲地圖重定位)

約 19 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

1.small_gicp_relocalization(先驗點雲地圖重定位)

1.1.實車先看:地圖、起點和雲臺零位

這個節點在已有地圖導航模式 slam:=False 下,把當前配準點雲與先驗PCD地圖對齊,輸出 map → odom 的位置、朝向修正。它不直接控制車輪或雲臺,也不是重新建立地形障礙的節點;slam:=True 的整套啟動不執行它。

實車上遇到的問題 優先核對 用直白的話解釋
啟動後定位不對或找不到地圖 prior_pcd_file、地圖來源與座標 要提供當前場地的三維PCD;Nav2二維地圖與PCD還必須使用對應的位置和朝向
車停在地圖中某個位置,卻一開始就對不上 init_pose 本引數直接給 map→odom 一個初始猜測,不是一律填寫“底盤在地圖中的位置”
RViz點了初始位置,朝向卻偏了一個雲臺角 robot_base_frame 當前訊息被當作 gimbal_yaw 的地圖位姿;箭頭應對應雲臺yaw層朝向,不能一律當底盤車頭
同一地圖,換個雲臺零位啟動後整體方向不同 base_frame、lidar_frame 與PCD建圖時的參考 原始碼啟動時用當時的底盤←雷達變換處理整份地圖;雷達隨yaw轉,建圖和當前零位是否對應必須核實
定位跳到相似牆面、柱子或另一條走廊 初值、max_dist_sq 和現場可見結構 匹配距離放太寬可能接受錯誤對應,但初值、重複結構或座標錯誤也不能只靠收緊距離解決
定位計算慢、細節不足 兩個 leaf_size、num_neighbors、num_threads 先確認點雲正確且足夠,再權衡細節和計算量;更密的點不保證更準確

當前沒有實物,也沒有本節點的有效重定位測試。下文分別說明“程式碼如何解釋這些值”和“實車是否適用”,不把原始碼流程當作已經驗證的定位效果。

1.2.引數

1.2.1.ros__parameters(ROS節點引數)

1.2.1.1.參數列

前12項對應當前實物 YAML;prior_pcd_file 雖被註釋,卻由 launch另行傳入;input_cloud_topic 沒寫在這份 YAML中,仍使用原始碼預設值。這兩項也列出,便於完整理解輸入來源。

small_gicp_relocalization:
  ros__parameters:
    use_sim_time: False
    num_threads: 4
    num_neighbors: 20
    global_leaf_size: 0.1
    registered_leaf_size: 0.05
    max_dist_sq: 3.0
    map_frame: "map"
    odom_frame: "odom"
    base_frame: "base_footprint"
    robot_base_frame: "gimbal_yaw"
    lidar_frame: "front_mid360"
    init_pose: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]   # [x, y, z, roll, pitch, yaw]
    # The prior_pcd_file does not need to be specified since it going to be set by defaults in launch.
    # prior_pcd_file: ""
引數名 當前值 單位 實車處理建議 作用 調大效果 調小效果 生效條件/備註
use_sim_time False;模擬 True 不適用,布林 上實物前必須核對並正確配置 控制節點與TF快取的ROS時鐘 不適用 不適用 地圖初始化查TF使用節點當前時間;匹配與釋出定時器用真即時間,True不會使其按模擬速率執行
num_threads 4 執行緒數,計數 通常保持當前值,不作為優先除錯項 給鄰域估計、建樹與匹配計算設定並行執行緒 CPU資源足夠時可能更快,也可能與Point-LIO等爭搶資源 並行度降低,計算可能更慢 應為正數;不是匹配頻率;降取樣呼叫未傳此值,當前庫預設4執行緒
num_neighbors 20 鄰點數量,計數 實物執行時重點觀察,有問題再針對性調整 用每點附近的鄰點描述區域性牆面、地面等形狀 描述範圍通常更大,計算增加,可能混入牆角兩側等不同結構 描述更區域性、更快,但可能對稀疏點和噪聲更敏感 同時用於地圖和即時點雲;不是20幀或20個匹配候選;當前庫鄰點不足5時不能形成正常區域性估計
global_leaf_size 0.1 m,三維體素邊長 實物執行時重點觀察,有問題再針對性調整 啟動時將先驗PCD降取樣後用於匹配 地圖點通常更少,負擔下降,細節減少 地圖點通常更多,啟動和匹配負擔增加 不修改PCD檔案或二維地圖解析度;應為正數;對目標地圖只在啟動時處理
registered_leaf_size 0.05 m,三維體素邊長 實物執行時重點觀察,有問題再針對性調整 每輪匹配前將累計輸入點雲降取樣 輸入點通常更少,計算減少,細小結構可能減少 輸入點通常更多,負擔上升;噪聲、動態點也可能保留更多 不修改Point-LIO降取樣設定;應為正數;沒有另行剔除人、敵車等動態點
max_dist_sq 3.0 m²,對應點距離的平方 實物執行時重點觀察,有問題再針對性調整 拒絕當前猜測下距離太遠的對應點對 允許更遠的點配對,也增加相似結構誤配可能 配對更嚴格,初值較差時可能剩餘點對不足 當前距離門檻約√3=1.73 m;不是3 m、定位精度或允許的總位置誤差
map_frame "map" 不適用,座標系名稱 上實物前必須核對並正確配置 指定輸出TF的父系,約定為目標地圖參考系 不適用 不適用 改名稱不自動轉換PCD座標;需與二維地圖和全域性定位約定一致
odom_frame "odom" 不適用,座標系名稱 上實物前必須核對並正確配置 指定輸出TF的子系,約定為輸入配準點雲參考系 不適用 不適用 當前輸入應為odom座標;節點不按該名稱轉換輸入點,也不校驗訊息frame_id與它一致
base_frame "base_footprint" 不適用,座標系名稱 上實物前必須核對並正確配置 啟動時查詢它←雷達的變換,用於處理先驗PCD 不適用 不適用 當前是底盤參考層;只取一次成功查詢,不隨隨後雲臺轉動重轉地圖;適用前提與PCD來源有關
robot_base_frame "gimbal_yaw" 不適用,座標系名稱 上實物前必須核對並正確配置 指定initialpose訊息所代表的機器人部位,並參與換算 不適用 不適用 僅手動初始位姿回撥使用;不是每輪匹配的目標系,也不修改輸入點座標;此處是實際yaw層
lidar_frame "front_mid360" 不適用,座標系名稱 上實物前必須核對並正確配置 與base_frame一起確定啟動時處理PCD的變換 不適用 不適用 僅地圖載入過程用它查TF;不能由此認定即時輸入是雷達自身系;MID360隨yaw、不隨pitch轉
init_pose [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 前3項m,後3項rad 上實物前必須核對並正確配置 初始化匹配變換,即當前約定下map←odom的猜測 不適用,應按參考系逐項設定 不適用,應按參考系逐項設定 順序x/y/z/roll/pitch/yaw,旋轉按Rz×Ry×Rx;全零為單位變換,不保證機器人位於地圖原點
prior_pcd_file YAML未配置;由launch的 prior_pcd_file 提供 不適用,檔案路徑 上實物前必須核對並正確配置 載入當前場地的三維先驗地圖 不適用 不適用 整套啟動後面的引數字典傳入路徑;當前預設實物路徑不存在,模擬預設PCD存在;不能用空路徑代替
input_cloud_topic "registered_scan",原始碼預設;YAML未配置 不適用,話題名稱 上實物前必須核對並正確配置 接收用於匹配的配準點雲 不適用 不適用 當前應來自loam_interface、座標為odom;不是sensor_scan、terrain_map或原始雷達區域性點雲;型別PointCloud2

本塊沒有當前完全不使用的自定義引數:robot_base_frame 只在收到手動初始位姿時參與,init_pose 只在啟動時設初值,它們不是持續調節項。話題、座標系和路徑不能按數值大小調參。

1.2.1.2.引數詳解
1.2.1.2.1.輸入與輸出:匹配的是哪兩份點雲
方向 資料 程式碼實際用途
讀取檔案 prior_pcd_file 載入PCD,啟動時變換、降取樣,建立固定目標地圖
訂閱 registered_scan,可由input_cloud_topic更名 複製XYZ座標並累加多幀,作為本輪匹配點雲;不用反射強度或點內時間
訂閱 initialpose,PoseWithCovarianceStamped 用人工給定的位姿重設匹配初值;話題名寫死為相對名
廣播 map → odom 釋出點雲匹配得到的參考系修正;不釋出獨立位姿或匹配點雲話題

即時點雲已經由Point-LIO與介面節點配準到 odom,本節點直接累加座標,不再逐幀轉雷達系,也不額外按雲臺yaw旋轉這些點。雲臺旋轉時,靜態環境應仍在共同的odom座標下對齊;這個結論依賴上游位姿、安裝外參和時間介面正確,目前沒有獨立yaw驗證。

回撥只儲存最近輸入的frame_id與時間戳,沒有檢查多幀是否同系,也沒有在frame_id變化時清空累計點。PCD沒有ROS訊息那樣的frame_id,本節點按自己的來源假設處理;檔名和座標系字串不能證明地圖已經對應。

每500 ms真即時間嘗試匹配一次,有點才處理;每輪降取樣、估計區域性形狀、搜尋地圖對應點,最多做10次最佳化迭代。匹配報告收斂才更新結果,未收斂則沿用舊結果,但本輪累計點仍會清空。收斂表示演算法停止條件滿足,不證明匹配到了場地中正確的位置;原始碼沒有再按匹配誤差、有效對應比例等檢查可信度。

1.2.1.2.2.prior_pcd_file:先確認用的是自己的場地地圖

整套啟動的預設路徑在安裝後的 pb2025_nav_bringup 共享目錄:

啟動方式 預設PCD路徑規則 當前預設檔案檢查
實物 pcd/reality/<world>.pcd;world預設 rmul_2024 rmul_2024.pcd 不存在
模擬 pcd/simulation/<world>.pcd;world預設 rmuc_2025 rmuc_2025.pcd 存在

相應實物預設二維地圖 map/reality/rmul_2024.yaml 也不存在;模擬預設二維地圖存在。這只是當前預設檔案檢查,沒有讀取執行節點引數,也不排除使用者另傳world、PCD或二維地圖路徑。上實物前需要準備當前場地的對應地圖,不能把模擬PCD存在當成實物地圖已準備。

localization_launch.py 在引數檔案之後,額外傳入 {"prior_pcd_file": prior_pcd_file},因此註釋掉這一行不表示節點不使用先驗PCD。它與Point-LIO是否啟用 prior_pcd_en 是不同功能:Point-LIO可不載入先驗,重定位節點仍需要先驗PCD。

檔案載入失敗只記錄錯誤並返回,建構函式仍繼續準備匹配目標,沒有明確阻止空目標進入後續匹配;不能把“節點起來了”視為地圖載入成功。原始碼不會在執行時重新讀取PCD,也不會替你核對它與Nav2二維地圖的位置、朝向、米制尺度或場地版本是否一致。

1.2.1.2.3.base_frame 與 lidar_frame:啟動時會轉動整份地圖

PCD讀入後,原始碼查詢 base_footprint ← front_mid360,再把這個矩陣左乘到整份地圖的每個點。它按節點當前時間查詢,失敗後每秒重試,成功一次就繼續;沒有查詢次數上限,也沒有在後續雲臺轉動時更新目標地圖。

這對應原始碼的一個來源假設:PCD基準是初始 lidar_odom,用初始底盤與雷達關係把地圖轉換到所需參考中。但當前Point-LIO實際儲存的是 camera_init 下的配準世界點,且其位姿原點涉及內部IMU;不是每一幀的雷達自身座標。把這類PCD當初始雷達系直接套機械變換,是否與實際建圖基準一致,必須複核,不能僅照README的命名認定轉換正確。

雷達在雲臺上,這一步特別依賴零位。 同一份PCD若建圖時與重新啟動時雲臺相對yaw不同,當前 base←lidar 會含不同角度;按原始碼計算,目標地圖可能被不同矩陣轉動,而獨立載入的二維地圖不會自動跟著調整。是否實際造成錯位,需要結合PCD生成時的起點、雲臺零位、底盤方向與地圖原點判斷,目前沒有測試結論。

該查詢與 loam_interface 的一次性基準轉換意圖相關,但兩節點分別查詢,不保證取到同一時刻的雲臺角。這裡的機械關係始終保留:MID360掛在 gimbal_yaw,只有實際yaw會帶動它,實際pitch位於後續層;兩個odom關節固定。重力參考、內部IMU→雷達關係或地圖來源錯誤,不能通過增大匹配距離掩蓋。

包內README還寫過“未設定時使用空變換”,當前實現沒有對應的單位變換旁路:若PCD能讀取但frame為空或TF缺失,會進入重試。應以當前原始碼為準,本輪不修改節點或地圖轉換。

1.2.1.2.4.init_pose 與 robot_base_frame:兩種初始位姿不是同一個物件

YAML的 init_pose 直接寫入匹配矩陣。 在當前輸入為odom、目標為map的約定下,它是 map←odom 初值,即“odom原點在map中的位置和方向”。

[0,0,0,0,0,0] 表示先猜兩系完全重合;這隻有在起始參考關係吻合時才合適,不表示演算法已知道機器人在地圖中的真實位置。位置單位m,角度rad;偏航90°應為約1.5708,而不是填90。旋轉按yaw、pitch、roll組成 Rz×Ry×Rx。

例如:若odom起點恰好與所描述的機器人原點重合且朝向一致,那麼機器人起始地圖位姿可能就是map←odom;若odom原點與雲臺存在高度或安裝偏移,或機器人已在odom內移動,就不能直接照抄機器人位置。當前底盤、雲臺、雷達原點不同,需按實際參考關係計算。

話題 initialpose 則被當作 robot_base_frame=gimbal_yaw 在地圖中的位姿。 回撥再查詢最新 gimbal_yaw←输入扫描系,當前掃描系應為odom,兩者相乘得到map←odom:

map←odom = 人工给定的 map←gimbal_yaw × TF中的 gimbal_yaw←odom

所以RViz箭頭若被你理解成底盤車頭,而當前雲臺相對底盤左轉90°,就可能少算一個雲臺角。位置也對應雲臺原點:若人工訊息給z=0,原始碼把它當作雲臺原點位於map的z=0,而不是“底盤地面高度為0”;高度應按這份地圖的基準核對。只改 robot_base_frame 的名字也需要重新核對整條關係,不能把“機器人”三個字自動等同於底盤。本引數僅該回呼叫,不在每次點雲匹配時扣機械角。

回撥沒有按訊息header.frame_id轉換位姿、沒有使用其協方差,也沒有按訊息時間查TF,而是取最新變換;收到首幀掃描前,掃描frame_id還為空,查詢可能失敗。手動設初值只改當前和下一輪匹配猜測,不會重轉PCD,也不清空已累計點。雲臺快速轉動時,人工位姿對應的朝向與最新TF是否同一時刻也要核對。

1.2.1.2.5.max_dist_sq:1.73 m是配對門檻,不是定位誤差指標

當前構建使用的small_gicp程式碼直接判斷“對應點距離平方是否大於 max_dist_sq”;超出就拒絕。源點先按當前猜測變換到地圖,再找最近地圖點,才檢查這項,因此在米制點雲中單位為m²:

max_dist_sq = 3.0 m² → 最大对应点距离约 sqrt(3) = 1.73 m
希望门槛为0.5 m → 平方值为0.25 m²

第二行僅解釋單位換算,不是建議修改當前值。它不限制機器人總移動距離,不表示允許定位偏差1.73 m,更不是掃描量程。錯誤初值下,源點仍可能碰巧靠近另一面牆並通過門檻。

實車中,放寬可留下更多點對,但重複柱子、相似走廊和動態物體也可能參與誤配;收緊會減少遠距離錯配,卻可能讓真實初值偏差稍大時無足夠點對。先確認地圖、初值和參考系,再結合正確匹配/誤匹配情況調整,不能單獨把“更小”理解成“更準”。

該單位按當前構建快取庫原始碼核實,庫提交為 fa0cfc983417c044b6036f71dfa448038bb9c820。CMake引用master,重新獲取依賴後應複核版本,不把當前快取行為當成所有版本的固定承諾。

1.2.1.2.6.兩個leaf_size、num_neighbors 與 num_threads(點雲精簡、鄰點數量與計算執行緒)

global_leaf_size=0.1 m 處理先驗地圖;registered_leaf_size=0.05 m 處理每輪累計即時點雲。兩者不要求相同,也不等於地形分析格子、Nav2地圖解析度或定位精度。地圖處理不會改原PCD,即時處理不會改變Point-LIO本身的輸出。

調小通常保留更多細節,代價是計算量增加;原始資料沒有的細節不會因調小而出現。遠處點稀疏、牆角或小柱子能否穩定描述,需看實際資料;人員、敵車等動態點在本節點沒有專門篩除,即時點更多也可能帶來更多幹擾。

num_neighbors=20 指每點用於描述區域性形狀的鄰點數,地圖與即時點都用它。它不是20個匹配候選或20幀累計。範圍太大可能混入牆角兩面、坡面與障礙等不同結構,太小又可能受噪聲影響;當前庫實際找到的鄰點不足5時,會設為無效區域性特徵的預設值,因此稀疏區域與降取樣尺度要一起看。

num_threads=4 控制鄰域估計、建樹及匹配的平行計算。降取樣呼叫沒有傳這個引數,當前庫該函式預設4執行緒;把引數改大,不等於所有步驟都跟著增加執行緒。它不是節點頻率,也不保證執行緒翻倍就快一倍,先沿用當前值。

1.2.1.2.7.map_frame、odom_frame、use_sim_time 與輸出邊界(地圖、里程計參考系與時間基準)

地圖匹配結果是“目標地圖←輸入累計點雲”的變換;輸出直接命名為 map→odom。要使這個名字正確,必須先保證目標PCD和輸入實際座標符合約定;本節點沒有另行變換到這兩個名稱指定的系。

輸出約20 Hz真即時間重複當前結果,點雲匹配則約2 Hz真即時間嘗試一次;20 Hz不表示每次都得到新定位。TF時間取最後收到的掃描時間加0.1秒,固定在原始碼中,不是本塊引數;也沒有“已成功匹配過”的輸出保護,啟動初值同樣可被髮布。這裡只記錄輸出介面,仍不展開此前擱置的導航走停或TF時效故障排查。

use_sim_time 應與輸入、機械TF和啟動模式一致。True影響節點當前時間與TF快取,不會讓兩個wall timer隨模擬倍速自動調整,也不會修復此前Point-LIO點時間單位或內部位姿轉換問題。

1.2.1.2.8.啟動來源與當前驗證範圍
啟動方式 引數與地圖來源 當前區別
整套reality導航,slam=False 實物nav2_params.yaml,經localization_launch傳入;PCD由launch引數字典另傳 本表值;預設world對應的實物地圖檔案缺失,需準備當前場地地圖
整套simulation導航,slam=False 模擬nav2_params.yaml,同樣另傳PCD 除use_sim_time=True外,本塊12項相同;預設模擬地圖存在
整套slam=True 進入slam_launch,不進入localization_launch 本節點不執行,不能用建圖輸出說明本塊已驗證
包內獨立launch 自己寫的引數字典,不讀取整套YAML num_neighbors=10,兩種leaf_size均0.25,max_dist_sq=1.0,輸入cloud_registered,frame與PCD預設空;不能直接當整套入口

13項自定義引數均在構造時宣告和讀取,沒有動態引數更新回撥;init_pose 用於啟動,人工初值走 initialpose 訊息。13項之外的ROS標準 use_sim_time 由節點時鐘處理,不能混為演算法引數動態更新。

  • 原始碼能確認: 引數讀取、地圖一次性轉換、累積配準點雲、平方距離門檻、啟動初值與人工初值的區別、匹配收斂後的更新規則和輸出介面。
  • 模擬已觀察: 2026-10-08僅驗證獨立Point-LIO靜止和約20 cm往返;未驗證本節點、先驗地圖匹配、獨立雲臺yaw、人工初值或全域性定位。
  • 必須實物測量/檔案來源核實: PCD與二維地圖的共同基準、建圖與啟動雲臺零位、雷達/內部IMU/底盤外參、地圖米制尺度及實際起點、可見結構與動態干擾、正確位置下的匹配穩定性。當前重力方向和點時間問題繼續保留待核實。

1.3.開發問題

1.3.1.關掉small_gicp

原模板 對應靜態版本
localization_launch.py localization_static_launch.py
rm_navigation_reality_launch.py rm_navigation_reality_static_launch.py
rm_navigation_simulation_launch.py rm_navigation_simulation_static_launch.py

主要調整是關閉 small_gicp、增加靜態 map → odom;導航節點繼續複用原來的 navigation_launch.py

1.3.2.日誌某些報錯

日誌原文 含義
GICP did not converge. 本次點雲配準沒有收斂
No accumulated points to process. 沒收到可處理的即時點雲
TF lookup failed... 初始化需要的 TF 查詢失敗
Couldn't read PCD file... 先驗 PCD 讀取失敗
1.3.2.1.GICP did not converge.

點雲對不上,要自己跑一邊slam建出來PCD,然後再使用這個PCD進行匹配。

1.3.2.2.No accumulated points to process.

這條提示表示 small_gicp 的即時點雲快取為空,發生在匹配之前。現在先查資料有沒有送到,暫時不用調匹配引數或初始位姿。

它預設訂閱的是 /registered_scan,資料鏈是:

MID360 → Point-LIO → /cloud_registered
                         ↓ loam_interface
                   /registered_scan → small_gicp