46.在ROS中實(shí)現(xiàn)global planner(2)

前文45.在ROS中實(shí)現(xiàn)global planner(1)
實(shí)現(xiàn)了一個(gè)global planner的模板闪萄,并且可以工作,本文將實(shí)現(xiàn)astar算法,為后續(xù)完成一個(gè)astar global planner做準(zhǔn)備

1. AStar簡介

1.1 AStar

Astar算法是一種圖形搜索算法,常用于尋路颖榜。Astar算法原理網(wǎng)上可以找到很多庐氮,簡單的說就是,從起點(diǎn)開始垢乙,向外發(fā)散渣慕,再去其中每個(gè)點(diǎn)到終端的估計(jì)距離最短的,繼續(xù)循環(huán)上次步驟裂逐,直到到達(dá)目標(biāo)點(diǎn)歹鱼。

1.2 啟發(fā)函數(shù)

估算距離(f)=距離起點(diǎn)距離(G)+距離終點(diǎn)的距離(H)

顯然G是已知的替劈,

  • 第一次從起點(diǎn)開始绿语,G當(dāng)然是0,
  • 向外發(fā)散也就是上下左右睡陪,距離起點(diǎn)當(dāng)然是1,也就是其父節(jié)點(diǎn)的G+1

H 是距離目標(biāo)點(diǎn)的距離掺涛,我們就是要規(guī)劃路徑庭敦,怎么找到距離目標(biāo)有多遠(yuǎn),其實(shí)這個(gè)距離是估計(jì)理想距離薪缆,當(dāng)沒有障礙物的時(shí)的距離秧廉,也就是直線距離

這里的直線距離又有兩種方式表示

  • 曼哈頓距離
    x+y
  • 歐式距離
    \sqrt{x^2 + y^2}

顯然網(wǎng)格計(jì)算適合使用曼哈頓距離的,其計(jì)算消耗要小很多

2. 實(shí)現(xiàn)過程

2.1 數(shù)據(jù)結(jié)構(gòu)

上面簡單提到實(shí)現(xiàn)過程拣帽,下面我們先定義數(shù)據(jù)結(jié)構(gòu)疼电, 我們需要保存當(dāng)前已經(jīng)搜索的節(jié)點(diǎn),同時(shí)需要找到最小的f值减拭,然后在該節(jié)點(diǎn)進(jìn)行繼續(xù)搜索和添加

  • 節(jié)點(diǎn)定義

class Grid {
 public:
  Point parent_point_;
  Point point_;
  float g_;
  float h_;  // f = g + h
};

節(jié)點(diǎn)定義比較簡單蔽豺,也就是當(dāng)前點(diǎn)坐標(biāo),父節(jié)點(diǎn)坐標(biāo)拧粪,g茫虽,h值

  • open list
    需要保存當(dāng)前已經(jīng)搜索點(diǎn)的列表,由于下次搜索有需要搜有f最小值既们,我們定義一個(gè)有限隊(duì)列濒析,這樣我們?nèi)op就可以得到最小f的節(jié)點(diǎn)
struct greater {
bool operator()(const Grid& g1, const Grid& g2) const {
    float f1 = g1.h_ + g1.g_;
    float f2 = g2.h_ + g2.g_;

    return f1 > f2 || (f1 == f2 && g1.g_ < g2.g_);
}
};
std::priority_queue<Grid, std::vector<Grid>, greater> open_list_;

2.2 鄰域

鄰域定義較簡單,定義為相對(duì)該點(diǎn)的偏移即可

  std::vector<Point> neighbors_;

  // 四鄰域
  neighbors_.emplace_back(-1, 0);
  neighbors_.emplace_back(1, 0);
  neighbors_.emplace_back(0, -1);
  neighbors_.emplace_back(0, 1);

  // 八領(lǐng)域再加上下面
  neighbors_.emplace_back(-1, -1);
  neighbors_.emplace_back(1, 1);
  neighbors_.emplace_back(1, -1);
  neighbors_.emplace_back(-1, 1);

2.3 搜索實(shí)現(xiàn)

2.3.1 搜索過程

簡單概括就是搜索過程就是不斷最小的f值的節(jié)點(diǎn)的鄰域啥纸,直到到達(dá)終點(diǎn)

偽代碼如下

open_list.push(start);

while(!open_list_.empty()) {
    // 取最前面的也就是最小的f節(jié)點(diǎn)
    Grid grid = open_list.top();
    open_list.pop();

    // 直到當(dāng)前搜索點(diǎn) 為終點(diǎn)号杏,終止循環(huán)
    if (grid.point == end.point) {
      return true;
    }

    // 循環(huán)這個(gè)節(jié)點(diǎn)的鄰居V節(jié)點(diǎn), 分別計(jì)算g h斯棒, 同時(shí)把這些節(jié)點(diǎn)添加到open_list
    for (neighbor:neighbors) {
        Grid current;
        current.g_ = grid.g_ + 1
        current.h_ = calc_h(grid, neighbor, end); // 計(jì)算鄰域的h
        current.parent_point_ = grid.point;  // 更新父節(jié)點(diǎn)

        if (!(current in open_list)) {
            // 如果該點(diǎn)已經(jīng)不在open list中則添加
            open_list.push(current);
        else {
            // 如果該點(diǎn)已經(jīng)存在open list中 則根據(jù)V計(jì)算結(jié)果確認(rèn)是否需要更新
            float f = current.g_ + current.h_;
            open_list[current.point].g_ = current.g_ ;
            open_list[current.point].h_ = current.h_ ;
            open_list[current.point].parent_point_ = grid.point;  // 更新父節(jié)點(diǎn)
        }
    }
}

2.3.2 得到路徑

grid結(jié)構(gòu)可以看出來盾致,其實(shí)相當(dāng)于一個(gè)鏈表結(jié)構(gòu),找到路徑后荣暮,只需要從end循環(huán)即可得到路徑

bool GetPathFromGrid(const Point& start_point, const Point& end_point, std::vector<Point>& path) {
  path.clear();

  path.push_back(end_point);

  int start_index;
  bool ret = Point2Index(start_point, start_index);
  if (!ret) {
    return false;
  }

  int index;
  Point point = end_point;
  ret = Point2Index(point, index);
  if (!ret) {
    return false;
  }

  while (index != start_index) {
    point = all_grid_[index].parent_point_;
    path.push_back(point);

    Point2Index(point, index);
  }

  return true;
}

3. 測試驗(yàn)證

3.1 輸入

為了方便我們直接讀取png圖庭惜,這樣我們直接編輯圖就可以直接用于測試,

   // 使用opencv直接讀取png圖片
   cv::Mat mat = cv::imread("../map/map_demo.png", cv::IMREAD_GRAYSCALE);
    // 為了保持習(xí)慣 我們反轉(zhuǎn)下, 值255認(rèn)為障礙物(讀取的圖片255是白色)
   cv::threshold(mat, mat, 128, 255, CV_THRESH_BINARY_INV);

3.2 顯示

為了方便我們觀察過程穗酥,我們?cè)O(shè)計(jì)一個(gè)函數(shù)用于顯示規(guī)劃和過程护赊,為了簡便我們使用opencv窗口

void Display(const cv::Mat& map_data,    // 傳入grid map
             cv::Point begin,           // 起點(diǎn)
             cv::Point end,                // 終點(diǎn)
             const std::vector<cv::Point>& path,  // 輸出的路徑
             const std::vector<cv::Point>& close_list  // 已經(jīng)完成搜索的點(diǎn)
             );

4. 測試

  • 輸入地圖


    image.png
  • 測試結(jié)果


    61a441eaef0c4759aa68f90467b164d0.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惠遏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子骏啰,更是在濱河造成了極大的恐慌节吮,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件判耕,死亡現(xiàn)場離奇詭異透绩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)壁熄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門帚豪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人草丧,你說我怎么就攤上這事狸臣。” “怎么了方仿?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長统翩。 經(jīng)常有香客問我仙蚜,道長,這世上最難降的妖魔是什么厂汗? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任委粉,我火速辦了婚禮,結(jié)果婚禮上娶桦,老公的妹妹穿的比我還像新娘贾节。我一直安慰自己,他們只是感情好衷畦,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布栗涂。 她就那樣靜靜地躺著,像睡著了一般祈争。 火紅的嫁衣襯著肌膚如雪斤程。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天菩混,我揣著相機(jī)與錄音忿墅,去河邊找鬼。 笑死沮峡,一個(gè)胖子當(dāng)著我的面吹牛疚脐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邢疙,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼棍弄,長吁一口氣:“原來是場噩夢啊……” “哼望薄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起照卦,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤式矫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后役耕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體采转,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年瞬痘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了故慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡框全,死狀恐怖察绷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情津辩,我是刑警寧澤拆撼,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站喘沿,受9級(jí)特大地震影響闸度,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚜印,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一莺禁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窄赋,春花似錦哟冬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至错敢,卻和暖如春红符,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伐债。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工预侯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人峰锁。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓萎馅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親虹蒋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子糜芳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容