路径规划 图解A 、Dijkstra、GBFS算法的异同(附C++ Python Matlab仿真)

在栅格地图中,常见的**邻域(neighbor)**模式如下所示,即

  • 8邻域
  • 24邻域
  • 48邻域

栅格的邻域表示了从当前位置出发下一次搜索的集合,例如八邻域法中,当前栅格只能和周围的八个栅格相连形成局部路径。

在这里插入图片描述

下面是一个图搜索问题的例子,可以直观理解什么是搜索问题。

例1:在如下的栅格地图中,设绿色栅格为起点,红色栅格为终点,灰色栅格为障碍,白色栅格为可行点,问如何设计一条由栅格组成的连接起点、终点的路径,并尽可能使路径最短?

接下来,围绕这个问题展开阐述。

在这里插入图片描述

2 贪婪最佳优先搜索

一个朴素的想法是:每一次搜索时就找那些与终点最近的节点,这里衡量最近可以用多种度量方式——曼哈顿距离、欧式距离等。这种方法像一头狼贪婪地望着食物,迫切寻求最近的路径,因此称为贪婪最佳优先搜索(Greedy Best First Search, GBFS)

假设采用八邻域法,在GBFS思想指导下,在起点的八邻域中就会选择最右侧的节点,如下所示。

在这里插入图片描述
循环地,直到如下所示的节点,因为邻域内有障碍,这些障碍节点不会被候选,所以此时离终点最近的就是下方的方格

在这里插入图片描述

依次类推直至终点

3 Dijkstra算法

Dijkstra算法走向了另一个极端,它完全不考虑扩展节点与终点的关系,而是定义了一个**路径耗散函数

g

(

n

)

g(n)

g(n)**,从起点开始,机器人每走一个栅格就会产生一定的代价或耗散,因为Dijkstra算法希望路径最短,所以每次首选那些使路径耗散最小的节点。

依照Dijkstra算法的观点,从起点开始,其八个邻域节点都会被依次探索,因为它们离起点最近,接着再探索这些节点的子节点。

在这里插入图片描述
因此Dijkstra算法会遍历大量的节点,一圈圈地逼近终点

在这里插入图片描述

4 启发式A*搜索

A*算法是非常有效且常用的路径规划算法之一,其是结合Dijsktra算法与GBFS各自优势的启发式搜索算法,其搜索代价评估函数为

f

(

n

)

=

g

(

n

)

h

(

n

)

f(n)=g(n)+h(n)

f(n)=g(n)+h(n)

其中

g

(

n

)

g(n)

g(n)代表路径耗散,是Dijsktra算法分量;

h

(

n

)

h(n)

h(n)代表下一个搜索节点与终点的距离,启发式地引导机器人朝着终点拓展,是GBFS算法分量。

在这里插入图片描述
兼具两个算法特点的A*算法既保持完备性,又在一定条件下体现出最优性,被广泛应用于路径规划中。

5 A*、Dijkstra、GBFS算法的异同

特别地

g

(

n

)

=

0

g\left( n \right) =0

g(n)=0时,启发函数影响占据主导,A*算法退化为GBFS算法——完全不考虑状态空间本身的固有属性,不择手段地追求对目标的趋近,此时算法搜索效率将得到提升,但最优性无法保证;

h

(

n

)

=

0

h(n)=0

h(n)=0时,路径耗散函数影响占据主导,A*算法退化为Dijsktra算法——无先验信息搜索,此时算法搜索效率下降,但最优性上升。

三个算法的直观比较如下所示

在这里插入图片描述

6 算法仿真与实现

6.1 算法流程

在这里插入图片描述

6.2 ROS C++实现

核心代码如下

std::tuple<bool, std::vector<Node>> AStar::plan(const unsigned char\* costs, const Node& start,
                                                  const Node& goal, std::vector<Node> &expand) {
    // open list
    std::priority_queue<Node, std::vector<Node>, compare_cost> open_list;
    open_list.push(start);

    // closed list
    std::unordered_set<Node, NodeIdAsHash, compare_coordinates> closed_list;

    // expand list
    expand.clear();
    expand.push\_back(start);

    // get all possible motions
    const std::vector<Node> motion = getMotion();

    // main loop
    while (!open_list.empty()) {
      // pop current node from open list
      Node current = open_list.top();
      open_list.pop();
      current.id = this->grid2Index(current.x, current.y);
      
      // current node do not exist in closed list
      if (closed_list.find(current) != closed_list.end())
        continue;

      // goal found
      if (current==goal) {
        closed_list.insert(current);
        return {true, this->\_convertClosedListToPath(closed_list, start, goal)};
      }

      // explore neighbor of current node
      for (const auto& m : motion) {
        Node new_point = current + m;

        // current node do not exist in closed list
        if (closed_list.find(new_point) != closed_list.end())
          continue;

        // explore a new node
        new_point.id = this->grid2Index(new_point.x, new_point.y);
        new_point.pid = current.id;

        // if using dijkstra implementation, do not consider heuristics cost
        if(!this->is_dijkstra_)


现在能在网上找到很多很多的学习资源,有免费的也有收费的,当我拿到1套比较全的学习资源之前,我并没着急去看第1节,我而是去审视这套资源是否值得学习,有时候也会去问一些学长的意见,如果可以之后,我会对这套学习资源做1个学习计划,我的学习计划主要包括规划图和学习进度表。



分享给大家这份我薅到的免费视频资料,质量还不错,大家可以跟着学习

![](https://img-blog.csdnimg.cn/img_convert/21b2604bd33c4b6713f686ddd3fe5aff.png)



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用Dijkstra算法求解路径规划问题的Python代码。 ```python import heapq def dijkstra(graph, start, end): # 初始化距离和前驱字典 distances = {vertex: float('infinity') for vertex in graph} distances[start] = 0 previous_vertices = {vertex: None for vertex in graph} # 创建一个优先队列,将起点放进去 vertices = [(0, start)] heapq.heapify(vertices) while vertices: # 从优先队列中取出距离最小的节点 current_distance, current_vertex = heapq.heappop(vertices) # 如果当前节点已经到达终点,则返回路径 if current_vertex == end: path = [] while previous_vertices[current_vertex] is not None: path.append(current_vertex) current_vertex = previous_vertices[current_vertex] path.append(start) return path[::-1] # 遍历当前节点的邻居节点 for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight # 如果新的距离比原来的距离更短,则更新距离和前驱字典 if distance < distances[neighbor]: distances[neighbor] = distance previous_vertices[neighbor] = current_vertex heapq.heappush(vertices, (distance, neighbor)) # 如果无法到达终点,则返回None return None ``` 其中,`graph` 是一个字典,表示的邻接表。例如,对于如下的: ``` A --5-- B --3-- C | | | 2 4 6 | | | D --7-- E --1-- F ``` 邻接表可以表示为: ```python graph = { 'A': {'B': 5, 'D': 2}, 'B': {'A': 5, 'C': 3, 'E': 4}, 'C': {'B': 3, 'F': 6}, 'D': {'A': 2, 'E': 7}, 'E': {'B': 4, 'D': 7, 'F': 1}, 'F': {'C': 6, 'E': 1} } ``` `start` 和 `end` 分别是起点和终点的名称。例如,如果要从节点 A 到节点 F,可以调用函数: ```python path = dijkstra(graph, 'A', 'F') ``` 函数返回的是一个列表,表示从起点到终点的路径,例如 `[A, B, E, F]`。如果无法到达终点,则返回 `None`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值