机器人路径规划之Dijkstra算法

2023-05-16

在机器人路径规划之动态窗口法文中,介绍了一种局部路径规划方法——动态窗口法,本文将介绍一种全局路径规划方法——Dijkstra算法(狄克斯特拉算法)。Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。

基本原理

其基本原理是:每次新扩展一个距离最短的点,更新与其相邻的点的距离。

以下图为例,计算左上角节点到右下角节点的最短路径,箭头上的数值表示两个节点间的距离

示例

首先扩展第一个节点,计算其余节点与第一个节点的距离,如下图所示,用橙色标出已经扩展的节点,未扩展的节点仍用绿色标出,其中圆中的数值表示与第一个节点的距离, ∞ \infty 表示该节点没有直接到达此时已扩展节点的路径。

第一步

从未扩展的节点(绿色部分)中选择距离最小的节点进行拓展,并更新其余节点到第一个节点的距离,如下图

第二步

重复进行上面的步骤,直到所有节点都已扩展。

流程图

最后标出左上角节点到右下角节点的最短路径

示例结果

参考:https://wiki.mbalib.com/wiki/Dijkstra%E7%AE%97%E6%B3%95

程序实现

假定有如下的地图:

运行结果

黑色边框为障碍物,要求找到左下角x到右上角x的最短距离,而且每次只能向周围(上、下、左、右、左上、左下、右上、右下)八个点移动

接下来使用Dijkstra算法来解决这个问题,先看最终效果:

运行结果

节点类

为了解决这个问题,我们还需要定义一个节点类,包括自身位置、与开始位置的最短距离,以及在最短路径中前一个节点的索引

class Node:
    def __init__(self, x, y, cost, pind):
        self.x = x # 自身位置的x坐标
        self.y = y # 自身位置的y坐标
        self.cost = cost # 与开始位置的最短距离
        self.pind = pind # 在最短路径中位于当前节点的前一个节点的索引

    def __str__(self):
        return str(self.x) + "," + str(self.y) + "," + str(self.cost) + "," + str(self.pind)

初始化开始位置、目标位置、地图

sx = 10.0 # 开始位置的x坐标
sy = 10.0 # 开始位置的y坐标
gx = 50.0 # 目标位置的x坐标
gy = 50.0 # 目标位置的y坐标
grid_size = 1.0 # 网格大小
robot_size = 1.0 # 机器人大小

ox = [] # 障碍物的x坐标列表
oy = [] # 障碍物的y坐标列表

# 向地图中添加障碍物
for i in range(60):
    ox.append(i)
    oy.append(0.0)
for i in range(60):
    ox.append(60.0)
    oy.append(i)
for i in range(61):
    ox.append(i)
    oy.append(60.0)
for i in range(61):
    ox.append(0.0)
    oy.append(i)
for i in range(40):
    ox.append(20.0)
    oy.append(i)
for i in range(40):
    ox.append(40.0)
    oy.append(60.0 - i)
for i in range(15):
    ox.append(5.0 + i)
    oy.append(20)
for i in range(15):
    ox.append(40.0 + i)
    oy.append(40)

# 画出障碍物、开始位置、目标位置
plt.plot(ox, oy, ".k")
plt.plot(sx, sy, "xr")
plt.plot(gx, gy, "xb")
plt.grid(True)
plt.axis("equal")

nstart = Node(round(sx / grid_size), round(sy / grid_size), 0.0, -1)
ngoal = Node(round(gx / grid_size), round(gy / grid_size), 0.0, -1)
ox = [iox / grid_size for iox in ox]
oy = [ioy / grid_size for ioy in oy]

# 生成障碍物地图
obmap, minx, miny, maxx, maxy, xw, yw = calc_obstacle_map(ox, oy, grid_size, robot_size)
# 节点的可能移动情况
# x方向位移,y方向位移,移动距离
motion = [[ 1,  0, 1],
          [ 0,  1, 1],
          [-1,  0, 1],
          [ 0, -1, 1],
          [-1, -1, math.sqrt(2)],
          [-1,  1, math.sqrt(2)],
          [ 1, -1, math.sqrt(2)],
          [ 1,  1, math.sqrt(2)]]

Dijkstra算法的处理过程

初始化完成后,就是算法的循环过程:每次扩展一个距离最短的点,并更新与其相邻的点的距离

# 已扩展的节点,未扩展的节点
openset, closedset = dict(), dict()
# 将开始位置加入已扩展节点字典
openset[calc_index(nstart, xw, minx, miny)] = nstart

while True:
    # 找到未扩展节点中距离最小的节点
    c_id = min(openset, key=lambda o: openset[o].cost)
    current = openset[c_id]
    print("current", current)

    # 显示当前扩展的节点
    plt.plot(current.x * grid_size, current.y * grid_size, "xc")
    if len(closedset.keys()) % 10 == 0: # 显示10个节点后暂停一下
        plt.pause(0.001)
        # pass

    # 判断当前扩展的节点是不是目标节点
    if current.x == ngoal.x and current.y == ngoal.y:
        print("Find goal")
        ngoal.pind = current.pind
        ngoal.cost = current.cost
        break # 如果是则退出循环

    # 将当前扩展的节点从未扩展节点字典中剔除
    del openset[c_id]
    # 将当前扩展的节点添加到已扩展节点字典
    closedset[c_id] = current

    # 循环将当前扩展节点周围的节点加入到未扩展节点字典
    for i, _ in enumerate(motion):
        node = Node(current.x + motion[i][0], current.y + motion[i][1],
                    current.cost + motion[i][2], c_id)
        n_id = calc_index(node, xw, minx, miny)

        # 判断该节点是否在地图外或者处于障碍物上
        if not verify_node(node, obmap, minx, miny, maxx, maxy):
            # 是则进入下一轮循环
            continue

        # 如果该节点已经被扩展了,则进入下一轮循环
        if n_id in closedset:
            continue
        # 如果该节点已经在未扩展节点字典中,则更新它到开始位置的最短距离
        if n_id in openset:
            if openset[n_id].cost > node.cost:
                openset[n_id].cost = node.cost
                openset[n_id].pind = c_id
        # 否则加入到未扩展节点字典中
        else:
            openset[n_id] = node

计算最终路径

# 计算最终路径
rx, ry = [ngoal.x * grid_size], [ngoal.y * grid_size]
pind = ngoal.pind
# 从最终节点依次向前递推得到最短路径
while pind != -1:
    n = closedset[pind]
    rx.append(n.x * grid_size)
    ry.append(n.y * grid_size)
    pind = n.pind
plt.plot(rx, ry, "-r")
plt.show()

程序中用到的一些函数

# 判断节点是否在地图外或者处于障碍物上
def verify_node(node, obmap, minx, miny, maxx, maxy):
    if obmap[node.x][node.y]:
        return False
    if node.x < minx:
        return False
    elif node.y < miny:
        return False
    elif node.x > maxx:
        return False
    elif node.y > maxy:
        return False
    return True

def calc_obstacle_map(ox, oy, grid_size, vr):
    # 四舍五入取整
    minx = round(min(ox))
    miny = round(min(oy))
    maxx = round(max(ox))
    maxy = round(max(oy))
    xwidth = round(maxx - minx)
    ywidth = round(maxy - miny)

    # 障碍物地图生成
    # 有障碍物为True,否则为False
    obmap = [[False for i in range(ywidth)] for i in range(xwidth)]
    for ix in range(xwidth):
        x = ix + minx
        for iy in range(ywidth):
            y = iy + miny
            for iox, ioy in zip(ox, oy): # zip:将对象打包为一个个元组
                d = math.sqrt((iox - x)**2 + (ioy - y)**2)
                if d <= vr / grid_size:
                    obmap[ix][iy] = True
                    break
    return obmap, minx, miny, maxx, maxy, xwidth, ywidth

def calc_index(node, xwidth, xmin, ymin):
    # 返回节点在地图中的索引:y*xw+x
    return (node.y - ymin) * xwidth + (node.x - xmin)

程序参考:https://github.com/AtsushiSakai/PythonRobotics

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

机器人路径规划之Dijkstra算法 的相关文章

  • WEEK(7)作业——最短路专题(Floyd、Dijkstra、SPFA、负权环路)

    A TT的魔法猫 题目描述 众所周知 xff0c TT 有一只魔法猫 这一天 xff0c TT 正在专心致志地玩 猫和老鼠 游戏 xff0c 然而比赛还没开始 xff0c 聪明的魔法猫便告诉了 TT 比赛的最终结果 TT 非常诧异 xff0
  • Dijkstra算法——java实现

    面试时遇到Dijkstra算法 这个算法我是知道的 但是没具体写过 所以答题比较慢 抽时间实现了下这个算法 nbsp Dijkstra算法基本思路 该算法的基本思路是这样的 从起始点开始 将未访问过的相邻节点加入一个优先队列 类似于广度优先
  • 数据结构——迪杰斯特拉(Dijkstra)算法

    迪杰斯特拉算法又叫狄克斯特拉算法 是从一个顶点到其余各顶点的最短路径算法 解决的是有权图中最短路径问题 迪杰斯特拉算法主要特点是从起始点开始 采用贪心算法的策略 每次遍历到始点距离最近且未访问过的顶点的邻接节点 直到扩展到终点为止 以下是数
  • 【MATLAB】最短路径Dijkstra算法

    目录 1 Dijkstra算法 1 1使用范围 1 2算法思路 1 3实例 2 代码 2 1dijstra函数 2 2调用函数 1 Dijkstra算法 1 1使用范围 bullet 寻求从一固定顶点到其余各点的最短路径
  • Dijkstra算法-(迪杰斯特拉)算法的迭代实现与优先队列实现 图解算法过程

    Dijkstra算法 迪杰斯特拉 算法之迭代实现 Dijkstra算法 迪杰斯特拉 算法之优先队列实现 该算法的核心原理 很简单 如下图所示 先说说Dijkstra算法 迪杰斯特拉 算法之迭代实现 如下图为详细步骤 代码如下 两种实现方法都
  • 轻松学懂图(下)——Dijkstra和Bellman-Ford算法

    概述 在上一篇文章中讲述了Kruskal和Prim算法 用于得到最小生成树 今天将会介绍两种得到最短路径的算法 Dijlkstra和Bellman Ford算法 Dijkstra算法 算法的特点 属于单源最短路径算法 什么是单源呢 通俗的说
  • 最短路径之迪克斯特拉(Dijkstra)算法

    何谓最短路径 顾名思义就是在一个图中 一个顶点到另外一个顶点的最短距离拉 那么这里有一点要注意 就是在网图中 边的权值各不相同 最短路径指的是俩点之间的连线权值最小 在非网图 边的权值都默认为1 中最短路径指的是边数最少的 从一个顶点到其余
  • 图论 笔记

    关于存图 如果是有权值的边 可以用pair define pii pair
  • 最短路径A*算法原理及java代码实现(看不懂是我的失败)

    算法只要懂原理了 代码都是小问题 先看下面理论 尤其是红色标注的 要源码请留下邮箱 有测试用例 直接运行即可 A 算法 百度上的解释 A 1 A Star 算法是一种静态路网中求解最短路最有效的直接搜索方法 公式表示为 f n g n h
  • 如何从多路径 Dijkstra 重建路径?

    我目前正在编写一个用于图形的 PHP 库 我已经成功实现了单路径 Dijkstra 算法 但现在在路径重建阶段很难实现多路径版本 取下图 为了简单起见 该图只有从顶点 A 到 J 的路径 经过多个其他顶点 这些顶点的成本都是相等的 即每条路
  • “双图”中变化次数有限的最短路径

    假设我们在一组顶点上有两个有向正权图 第一个图代表铁路 第二个图代表公交车道 顶点是公交车站或火车站或两者 我们需要找到从 A 到 B 的最短路径 但我们不能改变交通工具类型超过 N 次 我试图修改 Dijkstra 算法 但它只适用于一些
  • Java:使用 Fibonacci 堆实现 Dijkstra 算法

    新来的 但已经作为客人潜伏了一段时间了 好的 所以我一直在尝试使用 Fibonacci 堆 在 Java 中 执行 Dijkstra 的最短路径算法 经过一番搜索 我偶然发现了两个代表斐波那契堆的现成实现 第一个实现做得相当漂亮 可以找到h
  • 当这个常规队列版本也是正确的时候,为什么 Dijkstra 算法需要优先级队列?

    我已阅读以下内容 但请查看下面我的代码 为什么Dijkstra算法使用堆 优先级队列 https stackoverflow com questions 12481256 why dijkstras algorithm uses heap
  • 在Python中找到英文维基百科中两篇文章之间的最短路径

    问题 在英文维基百科中查找两篇文章之间的最短路径 如果存在文章 C i 并且文章 A 中存在指向文章 C 1 的链接 文章 C 1 中存在指向文章 C 2 的链接 则文章 A 和 B 之间存在路径 在文章 C n 中是指向文章 B 的链接
  • Dijkstra最短路径算法

    以下是我们教授给我们的算法摘要 步骤 3 中提到的图中节点的父节点是什么 我有点困惑 因为我认为节点只有邻居而没有父节点 我的第二个问题是关于第 3 步 拾取堆栈中的第索引条记录 由于堆栈只允许您查看顶部 所以我不确定拾取第索引记录意味着什
  • 具有负权重的 Dijkstra 算法

    我们可以使用具有负权重的 Dijkstra 算法吗 STOP 在你认为 哈哈 你可以在两点之间无休止地跳跃并获得一条无限便宜的路径 之前 我更倾向于考虑单向路径 其应用是具有点的山区地形 显然 从高到低并不需要能量 事实上 它会产生能量 因
  • 数组中超过 640 000 个元素 - 内存问题 [Dijkstra]

    我有一个脚本将 803 803 644809 每个图表内有 1 000 000 个值 使用 500 500 一切正常 但现在它崩溃了 它尝试分配超过 64MB 的内存 我没有 解决办法是什么 以某种方式 分裂 它还是 result mysq
  • Dijkstra算法的时间复杂度是多少

    Dijkstra V E S O 1 for each vertex v V O V d v O 1 d source 0 O 1 while S V O V v non visited vertex with the smallest d
  • 使用斐波那契堆时 Dijkstra 是否更快?

    使用斐波那契堆时 Dijkstra 是否比使用二进制堆更快 我自己做了一些实现斐波那契堆的实验 并在 Dijkstra 中使用它 我还检查了 fibheap 库中现成的斐波那契堆 但没有一个实现能够更快地找到使用以下命令的最短路径 二进制堆
  • java有索引的最小优先级队列吗?

    我需要它来实现 Dijkstra 算法 并且我确实有自己的实现 但是使用 java 自己的类记录我的代码会更容易 不 Java标准库没有这样的数据结构 我想大多数人都用这个 http algs4 cs princeton edu 24pq

随机推荐

  • 在vscode终端安装vue构建工具vite

    首先确保已安装npm 第一步 xff1a 全局安装yarn 0 打开cmd xff08 windows 43 R xff09 1 输入安装命令 npm install g yarn 2 如果能看到版本号 xff0c 则安装成功 yarn v
  • cmake相关:sudo make install后的卸载

    sudo make install后的卸载 我们知道linux中一般的编译一个package的顺序是 span class token function git span clone package git span class token
  • 提取rosbag中的图像话题存为本地图像

    新建存放图片文件夹 首先运行ros master roscore 在目标文件夹目录下运行 rosrun image view extract images sec per frame 61 0 05 image 61 lt ROSIMAGE
  • matlab循环读取文件

    一般情况下 xff0c 假如我要读取一个名为a txt的文件 xff0c 只需要利用下面的语句 xff1a a span class token operator 61 span span class token function load
  • 使用OpenMVG获取相机位姿的方法

    在生成sfm data bin文件后 xff0c 在文件目录下执行 openMVG main ConvertSfM DataFormat binary span class token operator span i yoursfm dat
  • Ubuntu修改文件夹下面所有文件权限的方法

    ubuntu修改文件夹下所有文件的权限 命令为 xff1a sudo chmod span class token operator span R 777 filename filename为要修改的文件夹名字 R应该是表示递归修改file
  • 写出对js事件,事件流,事件对象的理解

    事件 JavaScript 使我们有能力创建动态页面 事件是可以被 JavaScript 侦测到的行为 网页中的每个元素都可以产生某些可以触发 JavaScript 函数的事件 比方说 xff0c 我们可以在用户点击某按钮时产生一个 onC
  • UDP实时图像传输

    写在前面 首先问个问题 xff0c 为什么要用UDP传输图像 xff0c 而不是TCP xff1f TCP是我们经常使用的通信协议 xff0c 从认识它的第一天起 xff0c 就应该知道 xff0c 它非常稳 xff0c 丢包率超低 但是一
  • 机器学习 | 使用k-近邻算法实现手写识别系统

    KNN概述 k 近邻算法就是通过计算不同特征值之间的距离来进行分类的算法 假设我们现在有一个样本集 xff0c 每个样本都有几个特征用来描述这个样本 xff0c 以及一个它所属分类的标签 当我们拿到一个没有标签的样本时 xff0c 该如何判
  • Windows下如何查看一个process内有哪些thread

    从https docs microsoft com en us sysinternals downloads pslist下载PsTools xff0c 解压后找到pslist exe并移动到C盘任一目录下 xff0c 使用说明都在Psto
  • 机器人路径规划之动态窗口法

    动态窗口法 Dynamic Window Approach 概述 DWA是一种基于速度的局部规划器 xff0c 可计算达到目标所需的机器人的最佳无碰撞速度 程序实现 DWA算法主要分三步 xff1a 计算动态窗口计算最优 v
  • cso(布谷鸟)算法优化神经网络参数

    之前写了一篇pso工程上使用方法 xff0c 这一篇使用布谷鸟算法 xff0c 相关的原理也比较多的介绍了 目前实验结果还是pso快一点 一 布谷鸟算法介绍 布谷鸟搜索算法 xff0c 是 由剑 桥 大 学YANG等在文献 中提出的一种群智
  • 多线程之线程安全(Thread Safety)

    什么是线程安全 Thread Safety xff1f 怎样才能做到线程安全 xff1f 线程安全 线程安全指某个函数 函数库在多线程环境中被调用时 xff0c 能够正确地处理多个线程之间的共享变量 xff0c 使程序功能正确完成 数据类型
  • 多线程之简易注册验证程序

    问题描述 使用VC2010或以上版本编写一个多线程注册验证程序 xff0c 要求 xff1a 通过对话框输入若干人的学号和姓名 xff0c 并存入列表中作为注册记录 用户输入一个学号 xff0c 程序能通过多线程的方式与注册记录比对来验证其
  • 多线程之基于积分法与欧拉恒等式法的圆周率计算及OMP优化

    文章目录 一 问题描述二 积分法算法推导编程实现OMP优化 三 欧拉恒等式算法推导编程实现前期准备加法减法乘法除法 算法实现 OMP优化 四 总结积分法与欧拉恒等式法的对比OMP实现方式的对比 一 问题描述 分别采用积分法和欧拉恒等式计算
  • 语音信号处理 | 基于Hilbert-Huang变换的基音检测方法

    HHT原理 Hiibert Huang变换是由Huang等人于1998年提出来的一种信号分析方法 xff0c 它主要由两个部分组成 经验模型分解 Empirical Mode Decomposition EMD 和希尔伯特变换 xff08
  • 机器学习 | 使用TensorFlow搭建神经网络实现鸢尾花分类

    鸢尾花分类问题是机器学习领域一个非常经典的问题 xff0c 本文将利用神经网络来实现鸢尾花分类 实验环境 xff1a Windows10 TensorFlow2 0 Spyder 参考资料 xff1a 人工智能实践 xff1a Tensor
  • 语音信号处理 | 基于卡尔曼滤波的语音增强算法

    文章目录 1 概述2 卡尔曼滤波原理被估计的信号离散卡尔曼滤波算法参数选择 3 基于卡尔曼滤波的语音增强算法语音模型分析参数确定 4 程序实现语音数据的导入 加噪与分帧卡尔曼滤波器参数初始化卡尔曼滤波过程结果可视化 5 运行结果与结果分析运
  • UDP实时图像传输进阶篇——1080P视频传输

    在UDP实时图像传输一文中 xff0c 介绍了如何使用UDP来实现图像的实时传输 xff0c 并使用C 进行了发送端和接收端的搭建 但是文中的方法是对整张图片进行JPEG压缩 xff0c 并通过UDP一次性地发送到接收端 xff0c 由于一
  • 机器人路径规划之Dijkstra算法

    在机器人路径规划之动态窗口法文中 xff0c 介绍了一种局部路径规划方法 动态窗口法 xff0c 本文将介绍一种全局路径规划方法 Dijkstra算法 狄克斯特拉算法 Dijkstra算法是从一个顶点到其余各顶点的最短路径算法 xff0c