運動規劃實戰案例 | 基于四叉樹分解的路徑規劃(附ROS C++/Python仿真)

目錄

  • 1 為什么需要四叉樹?
  • 2 基于四叉樹的路徑規劃
    • 2.1 分層抽象
    • 2.2 路圖搜索
    • 2.3 動態剪枝
  • 3 算法仿真
    • 3.1 ROS C++算法仿真
    • 3.2 Python算法仿真

1 為什么需要四叉樹?

路徑規劃的本質是在給定環境中尋找從起點到終點的最優或可行路徑,其核心挑戰在于如何高效處理環境信息。傳統柵格法將環境均勻劃分為等大小的網格,雖直觀但面臨“維度災難”——環境規模擴大時,計算量呈指數級增長。例如,一個100×100的二維柵格地圖需維護10000個節點,而三維環境下這一數字將飆升至百萬級別。拓撲圖路徑規劃算法的核心思想在于將復雜的高維連續空間抽象為低維的離散圖結構。基于障礙邊界的可視圖法(運動規劃實戰案例 | 基于可視圖的路徑規劃算法(附ROS C++/Python仿真))以及維諾圖法(路徑規劃 | 詳解維諾圖Voronoi算法(附ROS C++/Python/Matlab仿真))都屬于這類基于拓撲圖的路徑規劃。

本文介紹的四叉樹(Quadtree)這一數據結構,源于計算機圖形學中對二維空間的層次化分割思想:通過遞歸地將空間劃分為四個象限(即“四叉”),僅在需要時對特定區域進行細化,從而實現對空間信息的自適應管理。例如,在開闊區域使用粗粒度劃分以節省內存,在障礙物密集區域則進行多級細分以提升路徑精度。這種按需分配的特性,使得四叉樹在面對非均勻分布的環境時,能夠顯著降低數據存儲與處理的冗余度

在這里插入圖片描述

接下來,將詳細介紹基于四叉樹路徑規劃的算法原理

2 基于四叉樹的路徑規劃

基于四叉樹的路徑規劃(Quartree-based Path Planning)分為三個核心模塊:分層抽象、路圖搜索與動態剪枝

2.1 分層抽象

四叉樹的構建始于將整個環境空間視為一個根節點,隨后遞歸執行分割-判斷過程:若當前節點對應的區域完全自由或完全被障礙物占據,則停止分割;若區域同時包含自由空間與障礙物,則將其均等分為四個子節點。這一過程持續至達到預設分割深度或滿足精度要求,最終形成一棵層次化的樹結構。例如,在機器人導航場景中,四叉樹會在走廊等簡單區域保持頂層粗劃分,而在辦公室桌椅排列的復雜區域自動生成多層細粒度節點。這種分層抽象的特性,為路徑規劃算法提供了天然的優化通道,因為四叉樹可通過節點狀態快速排除無效區域:若某個父節點被標記為完全障礙,其所有子節點無需進一步探查;若父節點完全自由,則可直接將其作為整體加入開放列表。這種“剪枝”機制大幅減少了狀態擴展次數。

在這里插入圖片描述

2.2 路圖搜索

首先,四叉樹路圖利用已有的樹節點作為路圖頂點。具體而言,選擇滿足以下條件的四叉樹節點作為路圖節點:

  • 葉子節點中的自由節點,保證路徑可達性
  • 非葉子節點中的自由父節點,用于跨層路徑跳躍

兩個四叉樹節點被判定為相鄰需滿足幾何邊界接觸條件:

  • 水平相鄰節點需滿足縱向坐標范圍存在重疊且橫向邊界間距在容差內(下圖紅框)
  • 垂直相鄰節點需滿足橫向坐標范圍存在重疊且縱向邊界間距在容差內(下圖藍框)

每個四叉樹節點的中心點作為路徑搜索的潛在航路點,相鄰節點間建立帶權無向邊,邊的權重通常取兩節點中心點的歐氏距離。最終形成的路圖本質上是一個由自由空間節點及其連接關系構成的圖結構,其中節點密度在障礙物邊界區域顯著增加,確保路徑能夠精確繞行復雜障礙。

在這里插入圖片描述

路徑搜索過程依托構建完成的路圖展開,采用Dijkstra算法即可。

2.3 動態剪枝

當環境中出現臨時障礙物(如突然出現的行人或車輛)時,傳統方法往往需要全局重新規劃,而四叉樹只需更新受影響區域的局部節點。具體而言,系統僅需回溯至包含障礙物變化的父節點層級,重新評估其子節點狀態,并選擇性觸發局部重構。這種增量式更新策略使得路徑規劃系統能夠以非常低的代價響應環境變化

3 算法仿真

3.1 ROS C++算法仿真

核心代碼如下所示

bool QuartreePathPlanner::plan(const Point3d& start, const Point3d& goal, Points3d& path, Points3d& expand)
{double m_start_x, m_start_y, m_goal_x, m_goal_y;if ((!validityCheck(start.x(), start.y(), m_start_x, m_start_y)) ||(!validityCheck(goal.x(), goal.y(), m_goal_x, m_goal_y))){return false;}// construct quartree only onceif (!is_quartree_valid_){const size_t grids_num = quar_grids_.size();roadmap_.resize(grids_num);valid_edges_.reserve(grids_num * 4);for (size_t i = 0; i < grids_num; ++i){const auto& current = quar_grids_[i];for (size_t j = i + 1; j < grids_num; ++j){const auto& neighbor = quar_grids_[j];if ((std::abs(current.min_x() - neighbor.max_x()) <= 1.0 ||std::abs(current.max_x() - neighbor.min_x()) <= 1.0)){if (current.min_y() < neighbor.max_y() && current.max_y() > neighbor.min_y()){valid_edges_.emplace_back(current.center(), neighbor.center());const double dist = (current.center() - neighbor.center()).length();roadmap_[i].emplace_back(j, dist);roadmap_[j].emplace_back(i, dist);}}else if ((std::abs(current.min_y() - neighbor.max_y()) <= 1.0 ||std::abs(current.max_y() - neighbor.min_y()) <= 1.0)){if (current.min_x() < neighbor.max_x() && current.max_x() > neighbor.min_x()){valid_edges_.emplace_back(current.center(), neighbor.center());const double dist = (current.center() - neighbor.center()).length();roadmap_[i].emplace_back(j, dist);roadmap_[j].emplace_back(i, dist);}}}}is_quartree_valid_ = true;}...// search on quartree mapstd::vector<int> q_path;if (_searchOnRoadMap(roadmap_, start_idx, goal_idx, q_path)){path.clear();path.emplace_back(start);if (q_path.size() > 2){for (size_t i = 1; i < q_path.size() - 1; ++i){const auto& pt = vertices_[q_path[i]];// convert to world framedouble wx, wy;costmap_->mapToWorld(pt.x(), pt.y(), wx, wy);path.emplace_back(wx, wy);}}path.emplace_back(goal);return true;}else{return false;}
}

在這里插入圖片描述

3.2 Python算法仿真

核心代碼如下所示

def partition(self, grid: np.ndarray, x: int, y: int, size: int, square_size_threshold: int = 5) -> List[Square]:"""Recursively divides the grid into four parts. If a part contains obstacles it further divied into four more parts.Parameters:grid (np.ndarray): 2D array representing the grid.x, y (int): Top-left coordinates of the current partition.size (int): Size of the current partition.Returns:List of Square objects representing free spaces in the grid."""if size < square_size_threshold:bottom_left = Point3d(x, y)top_right = Point3d(x + size, y + size)if self.isFree(grid, bottom_left, top_right):return [Square(bottom_left, top_right)]else:return []else:# Check if the area is homogeneous and free spaceif self.isFree(grid, Point3d(x, y), Point3d(x + size, y + size)):return [Square(Point3d(x, y), Point3d(x + size, y + size))]else:# Divide the area into quadrants and partition recursivelynew_size = size // 2quad1 = self.partition(grid, x, y, new_size)quad2 = self.partition(grid, x, y + new_size, new_size)quad3 = self.partition(grid, x + new_size, y, new_size)quad4 = self.partition(grid, x + new_size, y + new_size, new_size)return quad1 + quad2 + quad3 + quad4

在這里插入圖片描述

完整工程代碼請聯系下方博主名片獲取


🔥 更多精彩專欄

  • 《ROS從入門到精通》
  • 《Pytorch深度學習實戰》
  • 《機器學習強基計劃》
  • 《運動規劃實戰精講》

👇源碼獲取 · 技術交流 · 抱團學習 · 咨詢分享 請聯系👇

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/75019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75019.shtml
英文地址,請注明出處:http://en.pswp.cn/web/75019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

docker快捷打包腳本(ai版)

直接進入主題&#xff1a; 用這個腳本前提是你本地可以拉鏡像倉庫的鏡像&#xff0c;并且在 本地有了&#xff0c;然后將所有的鏡像tag寫在一個文件中&#xff0c;和下面docker_tags.txt 對應&#xff0c;文件叫什么&#xff0c;腳本里對應改什么&#xff0c;給小白說的 #!/bi…

WinMerge下載及使用教程(附安裝包)

文章目錄 一、WinMerge安裝步驟1.WinMerge下載&#xff1a;2.解壓&#xff1a;3.啟動&#xff1a; 二、WinMerge使用步驟1.添加文件或文件夾2.查看差異3.格式選擇 WinMerge v2.16.36 是一款免費開源的文件與文件夾比較、合并工具&#xff0c;能幫您快速找出差異&#xff0c;提高…

Jmeter性能測試之生成測試報告

結構 測試計劃 測試計劃是頂級的層級?錄的結構&#xff0c; 那么在這樣的?錄結構中&#xff0c;??可以包含很多線程組 線程組 線程組我們可以簡單的理解為postman測試?具??的collection&#xff0c;那么在整體線程組??&#xff0c;可以添加很多的測試 ?例 簡單控…

CSS中的inline-flex與flex的區別

在CSS中&#xff0c;flex 和 inline-flex 都是用于實現彈性布局&#xff08;Flexbox&#xff09;的顯示屬性&#xff0c;但它們在布局行為上有所不同。 flex 屬性會使元素表現為塊級彈性容器&#xff0c;這意味著元素會在頁面上占據一整行的空間&#xff0c;無論其內部內容的大…

Linux的那些基礎常用命令匯總

目錄 前言&#xff1a; 用戶命令&#xff1a; 管理后臺作業命令&#xff1a; 文件目錄操作命令&#xff1a; 運維高頻使用命令&#xff1a; 磁盤管理以及文件系統命令: 用戶、組操作命令&#xff1a; 權限控制命令&#xff1a; 網絡配置命令&#xff1a; 軟件管理命令…

高效深度學習lecture03

lecture_03 **剪枝&#xff1a;**pruning basically turns a dense neural network into a sparse neural network. you can remove those redundant synapses, and also you can remove those redundant neurons. 剪枝的本質上是將稠密的神經網絡轉變成稀疏的神經網絡&#…

Nextjs15 實戰 - React Notes 項目初始化

current branch 對應如下文檔 redis ioredis 本專欄內容均可在Github&#xff1a;notes_01 找到 一、效果 完整項目使用技術棧&#xff1a; Nextjs15 MySQL Redis Auth Prisma i18n strapi Docker vercel 二、修改根布局和其他頁面 修改 app/page.tsx&#xff1a…

Flutter PopupMenuButton 深度解析:從入門到架構級實戰

在移動應用交互設計中&#xff0c;上下文菜單如同隱形的魔法師&#xff0c;在有限屏幕空間中優雅地擴展操作維度。作為Flutter框架中的核心交互組件&#xff0c;PopupMenuButton絕非簡單的菜單觸發器&#xff0c;其背后蘊含著Material Design的交互哲學、聲明式UI的架構智慧以及…

C++——清明

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory> #include <ctime>using namespace std;class Weapon; // 前置聲明class Hero{ pr…

es --- 集群數據遷移

目錄 1、需求2、工具elasticdump2.1 mac安裝問題解決 2.2 elasticdump文檔 3、遷移 1、需求 遷移部分新集群沒有的索引和數據 2、工具elasticdump Elasticdump 的工作原理是將輸入發送到輸出 。兩者都可以是 elasticsearch URL 或 File 2.1 mac安裝 前置&#xff1a;已經安裝…

鴻蒙開發_ARKTS快速入門_語法說明_組件聲明_組件手冊查看---純血鴻蒙HarmonyOS5.0工作筆記010

然后我們來看如何使用組件 可以看到組件的組成 可以看到我們使用的組件 然后看一下組件的語法.組件中可以使用子組件. 然后組件中可以有參數,來修改組件的樣式等 可以看到{},這種方式可以設置組件參數,當然在下面. 的方式也可以的 然后再來

【GEE學習筆記】報錯解決:Sentinel-2 數據集分為 L1C(大氣頂層)和 L2A(地表反射率),如何選擇波段進行去云處理?

【GEE學習筆記】報錯解決&#xff1a;Sentinel-2 數據集分為 L1C&#xff08;大氣頂層&#xff09;和 L2A&#xff08;地表反射率&#xff09;&#xff0c;如何選擇波段進行去云處理&#xff1f; 【GEE學習筆記】報錯解決&#xff1a;Sentinel-2 數據集分為 L1C&#xff08;大…

OpenVLA-OFT——微調VLA時加快推理的三大關鍵設計:支持動作分塊的并行解碼、連續動作表示以及L1回歸(含輸入靈活化及對指令遵循的加強)

前言 25年3.26日&#xff0c;這是一個值得紀念的日子&#xff0c;這一天&#xff0c;我司「七月在線」的定位正式升級為了&#xff1a;具身智能的場景落地與定制開發商 &#xff0c;后續則從定制開發 逐步過渡到 標準產品化 比如25年q2起&#xff0c;在定制開發之外&#xff0…

IDEA 使用Maven打包時內存溢出

IDEA 使用Maven打包時內存溢出 解決辦法&#xff1a; File -> settings -> Build,Excetion,Deployment-> Compiler 中添加配置“-Djps.track.ap.dependenciesfalse” 如圖&#xff1a;

隨機產生4位隨機碼(java)

Random類&#xff1a; 用于生成隨機數 import java.util.Random; 導入必要的類 generateVerificationCode()方法&#xff1a; 這是一個靜態方法&#xff0c;可以直接通過類名調用 返回一個6位數字的字符串&#xff0c;首位不為0 生成首位數字&#xff1a; random.nextInt…

C#調用C++動態庫時出現`System.DllNotFoundException`錯誤的解決思路

文章目錄 1. DLL文件路徑問題2. 依賴的運行時庫缺失3. 平臺不匹配&#xff08;x86/x64&#xff09;4. 導出函數名稱不匹配5. DLL文件損壞或權限問題6. 運行時庫沖突&#xff08;MT/MD不匹配&#xff09;7. 使用DLLImport時的常見錯誤總結步驟 在C#中調用C動態庫時出現System.Dl…

免費Deepseek-v3接口實現Browser-Use Web UI:瀏覽器自動化本地模擬抓取數據實錄

源碼 https://github.com/browser-use/web-ui 我們按照官方教程&#xff0c;修訂幾個環節&#xff0c;更快地部署 步驟 1&#xff1a;克隆存儲庫 git clone https://github.com/browser-use/web-ui.git cd web-ui Step 2: Set Up Python Environment 第 2 步&#xff1a;設置…

ES 參數調優

1、refresh_interval 控制索引刷新的時間間隔。增大這個值可以減少I/O操作&#xff0c;從而提升寫入性能&#xff0c;但會延遲新文檔的可見性 查看 GET /content_erp_nlp_help_202503191453/_settings?include_defaultstrue 動態修改&#xff1a;refresh_interval 是一個動態…

【Easylive】視頻刪除方法詳解:重點分析異步線程池使用

【Easylive】項目常見問題解答&#xff08;自用&持續更新中…&#xff09; 匯總版 方法整體功能 這個deleteVideo方法是一個綜合性的視頻刪除操作&#xff0c;主要完成以下功能&#xff1a; 權限驗證&#xff1a;檢查視頻是否存在及用戶是否有權限刪除核心數據刪除&…

《比特信使的七重試煉:從數據丟失到CA認證的守護史詩》

點擊下面圖片帶您領略全新的嵌入式學習路線 &#x1f525;爆款熱榜 88萬閱讀 1.6萬收藏 第一章&#xff1a;初現危機——數據丟失的陰云 比特城的清晨總是被數據流的光芒點亮&#xff0c;但這一天&#xff0c;工程師艾琳的實驗室卻籠罩在陰霾中。她剛剛嘗試通過古老的“疾風…