路径规划 | 图解动态A*(D*)算法(附ROS C++/Python/Matlab仿真)

news2024/11/16 13:42:18

目录

  • 0 专栏介绍
  • 1 什么是D*算法?
  • 2 D*算法核心概念一览
  • 3 D*算法流程图
  • 4 步步图解:算法实例
  • 5 算法仿真与实现
    • 5.1 ROS C++实现
    • 5.2 Python实现

0 专栏介绍

🔥附C++/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。

🚀详情:图解自动驾驶中的运动规划(Motion Planning),附几十种规划算法


1 什么是D*算法?

动态A*(Dynamic A*, D*)算法是一种增量式路径规划算法,与A*算法相比,它最大的优势是可以同时兼容静态环境和存在未知动态变化的场景,曾被美国用于火星探测器寻路。如果还不了解A*算法,可以看路径规划 | 图解A*、Dijkstra、GBFS算法的异同(附C++/Python/Matlab仿真)

在这里插入图片描述

这里有一个概念——增量式,什么是增量式呢?与启发式搜索利用启发函数指导高效搜索不同,增量式搜索对曾经的规划信息进行综合再利用以减少搜索范围和时间。

D*算法实现增量式规划采用从目标点向起始点的反向搜索策略当既定路径被障碍阻塞时,障碍后各个节点到目标点的最短路径未被影响,只需在障碍附近重规划并更新起点到障碍处各节点的信息,当路径绕过障碍后即可重新利用曾经规划的到达目标位置的最短路径

所以动态障碍越靠近起点,能重复利用的信息越多,规划效率越高。当动态障碍靠近终点时,仍要更新整张地图节点信息,相当于应用反向A*算法进行重规划。

2 D*算法核心概念一览

D*算法的核心概念如下所示:

  • c ( x , y ) c\left( x,y \right) c(x,y):从节点 x x x移动到节点 y y y的代价,若 x x x y y y间存在障碍则 c ( x , y ) = i n f c\left( x,y \right) =\mathrm{inf} c(x,y)=inf

  • t ( x ) t\left( x \right) t(x):节点 x x x表状态。有

    1. NEW——未被搜索过的点
    2. OPEN——正在搜索的待考察节点
    3. CLOSED——被搜索过的节点。

    为了适应动态环境,D*算法的OPENCLOSED状态允许相互转化,当节点扩展后从开节点表中移除时,状态从OPEN变为CLOSED;当节点传播动态障碍信息给邻域时,节点将再次加入开节点表,状态从CLOSED变为OPEN

  • h ( x ) h\left( x \right) h(x):从节点 x x x到目标点的代价;

  • k ( x ) k\left( x \right) k(x):节点 x x x的历史最小 h ( x ) h\left( x \right) h(x)值,即
    k ( x ) = { h ( x )    , t ( x ) = N E W min ⁡ { k ( x ) , h ( x ) } , o t h e r w i s e k\left( x \right) =\begin{cases} h\left( x \right) \,\, , t\left( x \right) =\mathrm{NEW}\\ \min \left\{ k\left( x \right) ,h\left( x \right) \right\} , \mathrm{otherwise}\\\end{cases} k(x)={h(x),t(x)=NEWmin{k(x),h(x)},otherwise

    设置 k ( x ) k\left( x \right) k(x)的目的在于加快障碍处局部路径重规划的效率。当某个路径点变为障碍时,其 h ( x ) = i n f h\left( x \right) =\mathrm{inf} h(x)=inf k ( x ) k\left( x \right) k(x)不变。若从开节点表中首选 h ( x ) h\left( x \right) h(x)最小的点,则将最后考察障碍附近的点;而若从开节点表中首选 k ( x ) k\left( x \right) k(x)最小的点,则将率先考察障碍附近的点,符合实际情况;

  • 节点 x x x元状态:有

    1. RAISED——此时 k ( x ) < h ( x ) k\left( x \right) <h\left( x \right) k(x)<h(x)说明节点 x x x受到障碍影响
    2. LOWER——此时 k ( x ) = h ( x ) k\left( x \right) =h\left( x \right) k(x)=h(x)说明节点 x x x未受障碍影响;
  • p r o c e s s _ s t a t e ( ) \mathrm{process}\_\mathrm{state}\left( \right) process_state()核心函数,静态环境下可以更新各节点到达目标点的最短路径及节点连接关系,动态环境下可以传播受障碍影响后节点 h ( x ) h\left( x \right) h(x)的变更信息到邻域;

  • i n s e r t ( x , v a l ) \mathrm{insert}\left( x,val \right) insert(x,val):将节点 x x x插入开节点表,并令其 h ( x ) = v a l h\left( x \right) =val h(x)=val,更新 k ( x ) k\left( x \right) k(x)

  • m o d i f y _ cos ⁡ t ( x ) \mathrm{modify}\_\cos\mathrm{t}\left( x \right) modify_cost(x):通过 i n s e r t ( x , h ( x ) + c ( x , x . p a r e n t ) ) \mathrm{insert}\left( x,h\left( x \right) +c\left( x,x.\mathrm{parent} \right) \right) insert(x,h(x)+c(x,x.parent))将处于CLOSED状态的节点 x x x转换为OPEN状态

3 D*算法流程图

D*算法主函数流程如下所示

在这里插入图片描述
其中核心的 p r o c e s s _ s t a t e ( ) \mathrm{process}\_\mathrm{state}\left( \right) process_state()算法流程如下

在这里插入图片描述
在将动态信息传播到邻域进行修正的过程中,分为两种情况讨论:

  • 节点 x x x处于LOWER态。考虑到障碍的出现只可能让路径不变或更曲折,即让节点 h ( x ) ⩾ k ( x ) h\left( x \right) \geqslant k\left( x \right) h(x)k(x),所以对处在LOWER态的节点,不存在更优路径,此时只需将节点 的最优信息更新到邻域即可;
  • 节点 x x x处于RAISED态。与LOWER态节点不同,此时节点 x x x处可能存在更优路径,即可能存在 y ∈ n e i g h b o r ( x ) y\in \mathrm{neighbor}\left( x \right) yneighbor(x)使 h ( x ) > h ( y ) + c ( x , y ) h\left( x \right) >h\left( y \right) +c\left( x,y \right) h(x)>h(y)+c(x,y)。对于 y . p a r e n t = x y.\mathrm{parent}=x y.parent=x的情形RAISED态与LOWER态更新情况相同,以保持联结节点信息的同步。对于 y . p a r e n t ≠ x y.\mathrm{parent}\ne x y.parent=x的情形,若 h ( y ) > h ( x ) + c ( x , y ) h\left( y \right) >h\left( x \right) +c\left( x,y \right) h(y)>h(x)+c(x,y)则重新将节点 x x x加入开节点表进行考察,因为 x x x可能可以用更优的代价值来更新邻域;若 h ( x ) > h ( y ) + c ( x , y ) h\left( x \right) >h\left( y \right) +c\left( x,y \right) h(x)>h(y)+c(x,y),考虑到 h ( y ) ⩽ k o l d h\left( y \right) \leqslant k_{\mathrm{old}} h(y)kold的情形在S2处已考虑,因此只需包含 h ( y ) > k o l d h\left( y \right) >k_{\mathrm{old}} h(y)>kold,更进一步,由于节点 y y y处在CLOSED状态,所以通常 h ( y ) = k ( y ) ⩽ k o l d h\left( y \right) =k\left( y \right) \leqslant k_{\mathrm{old}} h(y)=k(y)kold,但此处 h ( y ) > k o l d h\left( y \right) >k_{\mathrm{old}} h(y)>kold说明节点 y y y也受到了障碍影响导致价值升高,体现了将 y y y重新纳入开节点表的必要性。

4 步步图解:算法实例

以下面的栅格地图为例,红色栅格表示起点,蓝色栅格表示终点,黄色栅格表示开节点表中的节点,绿色栅格表示闭节点表中的栅格

在这里插入图片描述
D*算法的静态规划阶段如下图所示

在这里插入图片描述

D*算法动态路径修正阶段如下所示

在这里插入图片描述

5 算法仿真与实现

5.1 ROS C++实现

double DStar::processState()
{
  if (open_list_.empty())
    return -1;

  double k_old = open_list_.begin()->first;
  DNodePtr x = open_list_.begin()->second;
  open_list_.erase(open_list_.begin());
  x->t = CLOSED;
  expand_.push_back(*x);

  std::vector<DNodePtr> neigbours;
  this->getNeighbours(x, neigbours);

  // RAISE state, try to reduce k value by neibhbours
  if (k_old < x->g_)
  {
    for (DNodePtr y : neigbours)
    {
      if (y->t != NEW && y->g_ <= k_old && x->g_ > y->g_ + this->getCost(y, x))
      {
        x->pid_ = y->id_;
        x->g_ = y->g_ + this->getCost(y, x);
      }
    }
  }

  // LOWER state, cost reductions
  if (k_old == x->g_)
  {
    for (DNodePtr y : neigbours)
    {
      if (y->t == NEW || ((y->pid_ == x->id_) && (y->g_ != x->g_ + this->getCost(x, y))) ||
          ((y->pid_ != x->id_) && (y->g_ > x->g_ + this->getCost(x, y))))
      {
        y->pid_ = x->id_;
        this->insert(y, x->g_ + this->getCost(x, y));
      }
    }
  }
  else
  {
    // RAISE state
    for (DNodePtr y : neigbours)
    {
      if (y->t == NEW || ((y->pid_ == x->id_) && (y->g_ != x->g_ + this->getCost(x, y))))
      {
        y->pid_ = x->id_;
        this->insert(y, x->g_ + this->getCost(x, y));
      }
      else if (y->pid_ != x->id_ && (y->g_ > x->g_ + this->getCost(x, y)))
      {
        this->insert(x, x->g_);
      }
      else if (y->pid_ != x->id_ && (x->g_ > y->g_ + this->getCost(y, x)) && y->t == CLOSED && (y->g_ > k_old))
      {
        this->insert(y, y->g_);
      }
    }
  }
  return open_list_.begin()->first;
}

在这里插入图片描述

5.2 Python实现

def processState(self) -> float:
	# get node in OPEN set with min k value
	node = self.min_state
	self.EXPAND.append(node)
	
	if node is None:
	    return -1
	
	# record the min k value of this iteration
	k_old = self.min_k
	# move node from OPEN set to CLOSED set
	self.delete(node)  
	
	# k_min < h[x] --> x: RAISE state (try to reduce k value by neighbor)
	if k_old < node.h:
	    for node_n in self.getNeighbor(node):
	        if node_n.h <= k_old and node.h > node_n.h + self.cost(node, node_n):
	            # update h_value and choose parent
	            node.parent = node_n.current
	            node.h = node_n.h + self.cost(node, node_n)
	
	# k_min >= h[x] -- > x: LOWER state (cost reductions)
	if k_old == node.h:
	    for node_n in self.getNeighbor(node):
	        if node_n.t == 'NEW' or \
	            (node_n.parent == node.current and node_n.h != node.h + self.cost(node, node_n)) or \
	            (node_n.parent != node.current and node_n.h > node.h + self.cost(node, node_n)):
	            # Condition:
	            # 1) t[node_n] == 'NEW': not visited
	            # 2) node_n's parent: cost reduction
	            # 3) node_n find a better parent
	            node_n.parent = node.current
	            self.insert(node_n, node.h + self.cost(node, node_n))
	else:
	    for node_n in self.getNeighbor(node):
	        if node_n.t == 'NEW' or \
	            (node_n.parent == node.current and node_n.h != node.h + self.cost(node, node_n)):
	            node_n.parent = node.current
	            self.insert(node_n, node.h + self.cost(node, node_n))
	        else:
	            if node_n.parent != node.current and \
	                node_n.h > node.h + self.cost(node, node_n):
	                self.insert(node, node.h)
	            else:
	                if node_n.parent != node.current and \
	                    node.h > node_n.h + self.cost(node, node_n) and \
	                    node_n.t == 'CLOSED' and \
	                    node_n.h > k_old:
	                    self.insert(node_n, node_n.h)
	return self.min_k

在这里插入图片描述

完整工程代码请联系下方博主名片获取


🔥 更多精彩专栏

  • 《ROS从入门到精通》
  • 《Pytorch深度学习实战》
  • 《机器学习强基计划》
  • 《运动规划实战精讲》

👇源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系👇

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

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

相关文章

【工具】logseq 使用分享

Github: https://github.com/logseq/logseq 三月八日国际劳动妇女节&#xff0c;当然要分享一款好用的记事本软件。 这次介绍的笔记本软件叫 logseq。 logseq 与传统的笔记软件不同&#xff0c;传统的笔记软件有各种数据单元&#xff08;post、title、refs、category、tags、…

智慧灌区信息化解决方案

系统概述智慧灌区信息化解决方案主要对对灌区的水情、雨情、土壤墒情、气象等信息进行监测&#xff0c;对重点区域进行视频监控&#xff0c;同时对泵站、闸门进行远程控制&#xff0c;实现了信息的测量、统计、分析、控制、调度等功能。为灌区管理部门科学决策提供了依据&#…

VITA/PYTHON/LUPA families

Image Sensor Group Top to Bottom Portfolio in Industrial Imaging Machine Vision • Factory automation and inspection • Robotic vision • Biometrics High-End Surveillance • Aerial Surveillance • Intelligent Traffic Systems (ITS) • Mapping Medical and Sc…

【UML】软件需求说明书

目录&#x1f981; 故事的开端一. &#x1f981; 引言1.1编写目的1.2背景1.3定义1.4参考资料二. &#x1f981; 任务概述2.1目标2.2用户的特点2.3假定和约束三. &#x1f981; 需求规定3.1 功能性需求3.1.1系统用例图3.1.2用户登录用例3.1.3学员注册用例3.1.4 学员修改个人信息…

Uipath DataTable-FilterDataTable(筛选数据表)

FilterDataTable(筛选数据表) 活动描述 FilterDataTable(筛选数据表)&#xff1a;通过在“筛选器向导”窗口中指定条件来筛选“DataTable”数据表变量&#xff0c;可以根据在该向导中指定的逻辑条件保留或删除行或列。使用如下图&#xff1a; FilterDataTable(筛选数据表)属…

Graph Partition: Edge cut and Vertex cut

Graph PartitionEdge cut and Vertex cutEdge cutVertex cut实际如何进行点分割和边分割的呢&#xff1f;Graph store format情况1&#xff1a;按照边列表存储&#xff1a;情况2&#xff1a;按照邻接表存储&#xff1a;Edge cut and Vertex cut 图结构描述了数据流动&#xff…

项目经理必看!常用的项目管理工具及方法

本文为你介绍&#xff1a;1、好用的项目管理工具&#xff1b;2、项目管理方法 随着企业日益复杂的业务流程和庞大的项目数量&#xff0c;如何高效地管理项目成为了必须面对的挑战&#xff0c;许多企业开始使用项目管理工具和方法来更好地管理项目。 今天我就来介绍几个好用的…

【UE】大世界子关卡StreamingLevel加载流程

受限于硬件&#xff0c;当项目需要制作大世界的时候&#xff0c;整张大地图无法也没必要全部加载进内存。和所有支持大世界的引擎一样&#xff0c;UE采取了分块加载的方式&#xff1a;除了一个持久关卡&#xff08;PersistentLevel&#xff09;的加载以外&#xff0c;采用的都是…

网络通信快速入门

&#x1f3e1;个人主页 &#xff1a; 守夜人st &#x1f680;系列专栏&#xff1a;Java …持续更新中敬请关注… &#x1f649;博主简介&#xff1a;软件工程专业&#xff0c;在校学生&#xff0c;写博客是为了总结回顾一些所学知识点 目录网络编程实现网络编程的三要素&#x…

少儿编程 电子学会图形化编程等级考试Scratch一级真题解析(选择题)2022年12月

少儿编程 电子学会图形化编程等级考试Scratch一级真题解析2022年12月 选择题(共25题,每题2分,共50分) 1、小明想在开始表演之前向大家问好并做自我介绍,应运行下列哪个程序 A、 B、 C、 D、 答案:D

【MySQL】第17章_触发器

第17章_触发器 在实际开发中&#xff0c;我们经常会遇到这样的情况&#xff1a;有 2 个或者多个相互关联的表&#xff0c;如商品信息和库存信息分别存放在 2 个不同的数据表中&#xff0c;我们在添加一条新商品记录的时候&#xff0c;为了保证数据的完整性&#xff0c;必须同时…

Linux - 内存性能评估

文章目录概述free 命令指定的时间段内不间断地监控内存的使用情况通过watch与free相结合动态监控内存状况vmstat命令监控内存“sar –r”命令组合小结概述 内存的管理和优化是系统性能优化的一个重要部分&#xff0c;内存资源的充足与否直接影响应用系统的使用性能。在进行内存…

C语言-基础了解-07-C运算符

c运算符 一、算术运算符 假设变量 A 的值为 10&#xff0c;变量 B 的值为 20&#xff0c;则&#xff1a; 实例 #include <stdio.h>int main() {int a 21;int b 10;int c ;c a b;printf("Line 1 - c 的值是 %d\n", c );c a - b;printf("Line 2 - …

机器学习100天(四十一):041 对偶支持向量机-公式推导

《机器学习100天》完整目录:目录 机器学习 100 天,今天讲的是:对偶支持向量机-公式推导! 本节主要延续上一节的内容,推导线性支持向量机的对偶形式。本节内容包含的数学理论和推导很多,我尽量简化其中的数学部分,只做感性的介绍,便于大家在理解的同时不受数学复杂公式…

ubuntu 18.04 虚拟机分区扩容

我的虚拟机存在一个问题&#xff0c;原来分配的是60G的空间&#xff0c;但实际只用了30G就已经最显示空间已经满&#xff0c;没办法使用:通过fdisk -l查看分区情况查看LVM卷组的信息Free PE / Size 7551 / <29..50 GiB&#xff0c;这是还可以扩充的大小#lvextend -L 10G /de…

git常用命令汇总

Git 是一种分布式版本控制系统&#xff0c;它具有以下优点&#xff1a; 分布式&#xff1a;每个开发者都可以拥有自己的本地代码仓库&#xff0c;不需要连接到中央服务器&#xff0c;这样可以避免单点故障和网络延迟等问题。 非线性开发&#xff1a;Git 可以支持多个分支并行开…

踩坑:解决npm版本升级报错,无法安装node-sass的问题

npm版本由于经常更新&#xff0c;迁移前端项目时经常发现报错安装不上。 比如&#xff0c;项目经常使用的sass模块&#xff0c;可能迁移的时候就发现安装不了。 因为node-sass 编译器是通过 C 实现的。在 Node.js 中&#xff0c;采用 gyp 构建工具进行构建 C 代码&#xff0c…

自制有声书阅读器:用PaddleSpeech打开读书新方式

吕声辉&#xff0c;飞桨开发者技术专家&#xff08;PPDE&#xff09;&#xff0c;某网络科技公司研发工程师。主要研究方向为图像识别&#xff0c;自然语言处理等。 • AI Studio主页 https://aistudio.baidu.com/aistudio/personalcenter/thirdview/227158 项目背景 随着互联…

第十四届蓝桥杯三月真题刷题训练——第 3 天

目录 题目1&#xff1a;门牌制作 题目描述 运行限制 代码&#xff1a; 题目2&#xff1a;货物摆放_long 题目描述 答案提交 运行限制 代码&#xff1a; 题目3&#xff1a;跳跃_dp 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码&#xff1a; 题目4&a…

AAAI顶会行人重识别算法详解——Relation Network for Person Re-identification

1.论文整体框架概述 在行人重识别任务中,通常都是对整个输入数据进行特征提取,但是缺少了局部信息。能不能既考虑局部与整体信息,也同时加入他们的联系呢?这篇论文主要的思想就是局部信息和全局信息的融合。 整体流程如上图所示, 首先对整体进行特征提取, 通常采用…