D*算法详解 (D星算法 / Dynamic A*算法/ Dstar算法)(死循环解决)

news2025/1/11 10:07:52

所需先验知识(没有也无大碍,只是了解的话会对D*的理解有帮助):A*算法/ Dijkstra算法

何为D*算法

Dijkstra算法是无启发的寻找图中两节点的最短连接路径的算法,A*算法则是在Dijkstra算法的基础上加入了启发函数h(x),以引导Dijkstra算法搜索过程中的搜索方向,让无必要搜索尽可能的少,从而提升找到最优解速度。这两者都可应用于机器人的离线路径规划问题,即已知环境地图,已知起点终点,要求寻找一条路径使机器人能从起点运动到终点。

路径规划问题:红色:起点;蓝色:终点;黑色:障碍物;浅蓝色:规划出来的路

但是上述两个算法在实际应用中会出现问题:机器人所拥有的地图不一定是最新的地图,或者说,机器人拥有的地图上明明是可以行走的地方,但是实际运行时却可能不能走,因为有可能出现有人突然在地上放了个东西,或者桌子被挪动了,或者单纯的有一个行人在机人运行时路过或挡在机器人的面前。

机器人走了2步突然发现自己地图上不存在的障碍物

碰到这样的问题,比如机器人沿着预定路径走到A点时,发现在预先规划的路径上,下一个应该走的点被障碍物挡住了,这种情况时,最简单的想法就是让机器人停下来,然后重新更新这个障碍物信息,并重新运行一次Dijkstra算法 / A*算法,这样就能重新找到一条路。

但是这样子做会带来一个问题:重复计算。假如如下图所示新的障碍物仅仅只是挡住了一点点,机器人完全可以小绕一下绕开这个障碍物,然后后面的路径仍然按照之前规划的走。可是重复运行Dijkstra算法 / A*算法时却把后面完全一样的路径重新又计算了一遍

标只需要小绕一下,后面的路径跟原来一模一样(本文中认为地图8邻接而非4邻接)

D*算法的存在就是为了解决这个重复计算的问题,在最开始求出目标路径后,把搜索过程的所有信息保存下来,等后面碰到了先验未知的障碍物时就可以利用一开始保存下来的信息快速的规划出新的路径。

顺便一提因为D*算法有上述的特性,所以D*算法可以使用在“无先验地图信息/先验地图信息不多的环境中的导航”的问题,因为只需要在最开始假装整个地图没有任何障碍,起点到终点的路径就是一条直线,然后再在在线运行时不断使用D*算法重新规划即可。

D*算法流程

# 伪代码

class state:
        # 存储了每个地图格子所需的信息,下面会说到这个类用在哪。以下为类成员变量
        x # 横坐标
        y # 纵坐标
        t = "new"  # 记录了当前点是否被搜索过(可为“new”,"open", "close",分别代表这个格子没被搜索过,这个格子在open表里,这个格子在close表里。关于什么是open表什么是close表,建议去看A*算法,能很快理解)
        parent = None  # 父指针,沿着某个点的父指针一路搜索就能找到从这个点到目标点end的最短路径
        h  # 当前代价值(D*算法核心)
        k  # 历史最小代价值(D*算法核心,意义是所有更新过的h之中最小的h值)

function Dstar(map, start, end):
    # map:m*n的地图,记录了障碍物。map[i][j]是一个state类对象
    # start:起点,state类对象
    # end: 终点,state类对象
    
    open_list = [ ] # 新建一个open list用于引导搜索
    insert_to_openlist(end,0, open_list)  # 将终点放入open_list中
    
    # 第一次搜索,基于离线先验地图找到从起点到终点的最短路径,注意从终点往起点找
    loop until (start.t  == “close”):

        process_state()   # D*算法核心函数之一

    end loop
 

    # 让机器人一步一步沿着路径走,有可能在走的过程中会发现新障碍物

    temp_p = start

    while (p != end) do

        if ( unknown obstacle found) then  # 发现新障碍物

                for new_obstacle in new_obstacles:     # 对每个新障碍物调用modify_cost函数    

                        modify_cost( new_obstacle )  #(D*算法核心函数之一)

                end for

                do 

                         k_min = process_state()
                while not ( k_min >= temp_p.h or open_list.isempty() )

                continue

        end if

        temp_p = temp_p.parent

     end while

        
    

上述伪代码中核心函数为2个:modify_cost 和 process_state。我翻阅了csdn几个关于process_state的解释,发现都有挺大的错误,会让整个算法在某些情况下陷入死循环(比如D*规划算法及python实现_mhrobot的博客-CSDN博客)。而且就连原论文的伪代码都有点问题(可能原论文(Optimal and Effificient Path Planning for Partially-Known Environments,

Anthony Stentz)有解释但是我没仔细看.....但是如果仅按其伪代码来实现process_state函数的话是会有问题的)。此文章最主要的目的就是说明这个问题并解决,解决方法来源于wikipedia的D*算法页面。
下面是modify_cost的伪代码:

 function modify_cost( new_obstacle ):

        set_cost(any point to new_obstacle ) = 10000000000  # 让“从任何点到障碍点的代价”和“从障碍点到任何点的代价” 均设置为一个超大的数(考虑8邻接)

        if new_obstacle.state == "close" then

                insert(new_obstacle, new_obstacle.h )  # 放到open表中,insert也是d*算法中的重要函数之一

        end if

        return get_min_k_(openlist)  # 返回openlist中最小的k值

下面是 Process_state函数的伪代码,注意标红那条

 function process_state( ):

         x = get_min_k_state(oepn_list)  # 拿出openlist中获取k值最小那个state,这点目的跟A*是一样的,都是利用k值引导搜索顺序,但注意这个k值相当于A*算法中的f值(f=g+h, g为实际代价函数值,h为估计代价启发函数值),而且在D*中,不使用h这个启发函数值, 仅使用实际代价值引导搜索,所以其实硬要说,D*更像dijkstra,都是使用实际代价引导搜索而不用启发函数缩减搜索范围,D*这点对于后面发现新障碍物进行重新规划来说是必要的。

        if x == Null then return -1

        k_old = get_min_k(oepn_list)  # 找到openlist中最小的k值,其实就是上面那个x的k值

        open_list,delete(x)  # 将x从open list中移除, 放入close表

        x.state = "close"   # 相当于放入close表,只不过这里不显式地维护一个close表

        

        # 以下为核心代码:

        if k_old < x.h then     # 满足这个条件说明x的h值被修改过,认为x处于raise状态

                for each_neighbor Y of X:  #考虑8邻接neighbor

                        if y.h<k_old   and  x.h> y.h + cost(y,x)  then

                                x.parent = y

                                x.h = y.h + cost(x,y)

                        end if

                end for

        end if 

        # 第二组判断

        if k_old == x.h then

                for each_neighbor Y of X:   #考虑8邻接neighbor

                        if y.state == "new" or

                           (y.parent == x and y.h !=x.h + cost(x,y) )  or

                           (y.parent != x and y.h >x.h + cost(x,y)) then

                               y.parent = x

                               insert(y, x.h + cost(x,y))

                        end if

                end for

         else:  # 不满足k_old == x.h  那就是k_old < x.h

                for each_neighbor Y of X:   #考虑8邻接neighbor

                        if y.state == "new" or

                           (y.parent == x and y.h !=x.h + cost(x,y) ) then

                               y.parent = x

                               insert(y, x.h + cost(x,y))

                        else:

                               if (y.parent != x and y.h >x.h + cost(x,y)) then

                                        x.k = x.h  # 注意这行!没有这行会出现特定情况死循环。在查阅大量资料后,在wikipedia的d*算法页面中找到解决办法就是这行代码。网上大部分资料,包括d*原始论文里都是没这句的,不知道为啥

                                        insert(x, x.h)

                                else:

                                        if (y.parent!=x and x.h>y.h+cost(y,x) and y.parent = "close" and y.h>k_old then

                                                insert(y,y.h)

                                        end if

                                end if

                        end if

                end for

        end if

        return get_min_k(oepn_list) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/602291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js正则中的match()

在前端开发中&#xff0c;正则表达式是一大利器。所以我们这次就来讨论下match()方法。 match本身是JavaScript语言中字符串对象的一个方法&#xff0c;该方法的签名是 match([string] | [RegExp]) 它的参数既可以是一个字符串&#xff0c;也可以是一个正则表达式。该方法绝…

windows 达梦数据库服务连接时提示:登录服务器失败,错误号6001,错误消息:网络通信异常 之数据库服务不存在的处理方式

在windows客户端上连接部署在windows操作系统上的达梦数据库&#xff0c; 使用DM管理工具连接数据库 正确输入用户名与密码之后点击确定按钮之后出现&#xff1a; 登录服务器失败&#xff0c;错误号6001&#xff0c;错误消息&#xff1a;网络通信异常 现象 如下图所示&#…

银行从业资格证 个人理财 各种年金计算公式总结

变量说明&#xff1a; C C C &#xff1a;每期投入的现金流 r r r&#xff1a;利率&#xff08;收益率/贴现率&#xff09; n n n &#xff1a;计息期数&#xff1b; F V FV FV&#xff1a;终值 P V PV PV&#xff1a;现值 推导计算过程用到等比数列求和公式 S n a 1 ∗ 1 −…

【算法训练(day7)】区间和并,离散化数组模板

目录 一.区间和并 二 .离散化数组 一.区间和并 问题&#xff1a;给定 n个区间 [li,ri]&#xff0c;要求合并所有有交集的区间。注意如果在端点处相交&#xff0c;也算有交集。输出合并完成后的区间个数。例如&#xff1a;[1,3][1,3] 和 [2,6][2,6] 可以合并为一个区间 [1,6][1…

htmlCSS-----CSS介绍与样式书写

目录 前言&#xff1a; 1. CSS是什么 2. CSS书写样式 (1)行内样式 (2)内部样式 3.外部样式 4.三者之间的比较 前言&#xff1a; 前面我们学习了HTML的相关标签和框架写法&#xff0c;那我们在了解这些标签用法了之后就要学会怎么去通过相关方法来使得界面美化处理&#xf…

06 Redis分布式锁

常见面试问题 Redis除了拿来做缓存&#xff0c;你还见过基于Redis的什么用法&#xff1f;Redis 做分布式锁的时候有需要注意的问题&#xff1f;如果是 Redis 是单点部署的&#xff0c;会带来什么问题&#xff1f;那你准备怎么解决单点问题呢&#xff1f;集群模式下&#xff0c…

LeetCode刷题集(七)(2315.统计星号)

&#x1f626;学习目标&#xff1a;拿下LeetCode2315.统计星号题目 &#x1f624; 学完本章节知识即可掌握本题&#xff01; 学习内容&#xff1a;LeetCode2315.统计星号 &#x1f624;题目&#xff1a;给你一个字符串 s &#xff0c;每 两个 连续竖线 ‘|’ 为 一对 。换言之&…

知识图谱涉及技术点分析

文章目录 数据从哪里来为什么通常将知识图谱划分到NLP领域&#xff1f;常用NLP技术点分析只是NLP任务吗&#xff1f;graph embedding知识融合业务还是算法&#xff1f;知识图谱组成 数据从哪里来 是手动提取关系吗&#xff1f;数据很多&#xff0c;关系确难涉及大量NLP技术关系…

Ansible基础五——条件语句、循环语句、handlers、任务失败处理

文章目录 一、 循环语句1.1 单量循环1.2 多量循环1.3 老版本用法1.4 loopregister 二、条件判断2.1 根据变量状态判断2.2 根据变量是否存在判断2.3 根据事实判断2.4 多条件判断2.4.1 and用法2.4.2 or用法 2.5 循环判断2.6 根据上个任务结果判断 三、handlers处理程序四、任务失…

5月《中国数据库行业分析报告》正式发布,首发时序、实时数据库两大【全球产业图谱】

为了帮助大家及时了解中国数据库行业发展现状、梳理当前数据库市场环境和产品生态等情况&#xff0c;从2022年4月起&#xff0c;墨天轮社区行业分析研究团队出品将持续每月为大家推出最新《中国数据库行业分析报告》&#xff0c;持续传播数据技术知识、努力促进技术创新与行业生…

ubuntu20安装xrdp以及解决黑屏问题

1、安装xrdp sudo apt-get install xrdp 2、将xrdp用户加入到如下用户组 sudo adduser xrdp ssl-cert 3、重启xrdp sudo service xrdp restart 4、打开windows远程面&#xff0c;连接&#xff0c;如果出现黑屏 sudo -s sudo vim /etc/xrdp/startwm.sh 加入如下内容&#xff…

攻防世界-web-Web_php_unserialize

1. 题目描述&#xff1a;查看以下代码&#xff0c;获取flag 2. 思路分析 从代码中不难看出&#xff0c;这里共有三个地方需要绕过 2.1 __wakeup函数&#xff1a;若在对象的魔法函数中存在的__wakeup方法&#xff0c;那么之后再调用 unserilize() 方法进行反序列化之前则会先…

数据分析概述

数据分析概述 数据的性质数据的概念数据与信息的区别和联系 数据的类型按照度量尺度分按时间状况分 什么是数据分析数据分析的重要性数据分析的内容数据分析作用 数据分析的基本流程典型的数据分析的流程 数据分析方法对比分析法分组分析法定量数据分布分析——具体事例 结构分…

上海亚商投顾:沪指高开高走 地产股迎来久违反弹

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日高开高走&#xff0c;沪指午后涨近1%&#xff0c;深成指、创业板指涨超1.2%&#xff0c;上证50盘中大…

惠更斯定理和格林定理

惠更斯原理和格林定理 惠更斯原理显示了表面上的波场如何决定表面 S S S外的波场。惠更斯在17世纪启发性地表达了这一概念。但这个想法的数学表达是由于19世纪的乔治格林。这一概念可以在数学上表达为标量波和矢量波。矢量波情形的推导与标量波情形是同态的。但是标量波情况下…

少儿编程python-一级

少儿编程python 文章目录 前言CSP-J与CSP-S少儿编程证书含金量排名&#xff08;国家承认的少儿编程证书&#xff09;非专业级软件能力认证&#xff08;CSP-J/S&#xff09;青少年编程能力等级测试&#xff08;CPA&#xff09;蓝桥杯青少年信息技术等级考试全国青少年软件编程等…

造船厂事故/风险(背景+官方统计数据)

造船厂事故/风险&#xff08;背景官方统计数据&#xff09; 船厂工地常见事故船厂事故:发人深省的伤害统计船厂工地常见的风险有哪些? 造船业是周期性的、资本密集型的行业。更严格的环境法规于2020年初生效&#xff0c;引发了对抑制船舶废气硫排放技术的需求。与此同时&#…

数据标记工具

检测分割标定 labelstudio https://labelstud.io/sudo apt install libpq-dev python3-devconda activate paddle_envpip install label-studiolabel-studio startlabel-studio --data-dir /data/data_label_studio<View><Image name"image" value"$im…

【shiro】shiro整合JWT——2.如何整合

前言 shiro整合JWT系列&#xff0c;主要记录核心思路–如何在shiroredis整合JWTToken。 上一篇中&#xff0c;我们知道了需要创建JwtToken、JwtUtil、JwtFilter。 该篇主要讲如何在shiro框架中&#xff0c;配置Jwt。 ps&#xff1a;本文主要以记录核心思路为主。 1、ShiroCon…

如何零基础自学黑客?

我经常会看到这一类的问题&#xff1a; 学习XXX知识没效果&#xff1b;学习XXX技能没方向&#xff1b;学习XXX没办法入门&#xff1b; 给大家一个忠告&#xff0c;如果你完全没有基础的话&#xff0c;前期最好不要盲目去找资料学习&#xff0c;因为大部分人把资料收集好之后&…