跳到正文

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