路径规划 | 图解跳点搜索JPS算法(附ROS C++/Python/Matlab仿真)

news2024/9/21 20:36:31

目录

  • 0 专栏介绍
  • 1 A*算法的弊端
  • 2 跳点搜索算法
    • 2.1 自然与强制邻点
    • 2.2 跳点剪枝策略
  • 3 算法仿真与实现
    • 3.1 算法流程
    • 3.2 ROS C++实现
    • 3.3 Python实现
    • 3.4 Matlab实现

0 专栏介绍

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

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


1 A*算法的弊端

A*算法是非常有效且常用的路径规划算法之一,其是结合Dijsktra算法与GBFS各自优势的启发式搜索算法,其具体原理请参考路径规划 | 图解A*、Dijkstra、GBFS算法的异同(附C++/Python/Matlab仿真)。然而,A*算法有个明显的缺陷——拓展了太多的无用节点

例: 如图所示,从起点 s s s到终点 g g g有三条可行路线:

  • L 1 = { ( 1 , 2 ) → ( 2 , 3 ) → ( 3 , 2 ) } L_1=\left\{ \left( 1,2 \right) \rightarrow \left( 2,3 \right) \rightarrow \left( 3,2 \right) \right\} L1={(1,2)(2,3)(3,2)}
  • L 2 = { ( 1 , 2 ) → ( 2 , 2 ) → ( 3 , 2 ) } L_2=\left\{ \left( 1,2 \right) \rightarrow \left( 2,2 \right) \rightarrow \left( 3,2 \right) \right\} L2={(1,2)(2,2)(3,2)}
  • L 3 = { ( 1 , 2 ) → ( 2 , 1 ) → ( 3 , 2 ) } L_3=\left\{ \left( 1,2 \right) \rightarrow \left( 2,1 \right) \rightarrow \left( 3,2 \right) \right\} L3={(1,2)(2,1)(3,2)}

直观地,路径 L 1 L_1 L1 L 3 L_3 L3的探索对最优路径的生成时没有意义的,但传统A*算法仍会在扩展邻域时评估这些不必要的节点,例如图中的灰色栅格,造成其应用时存在内存消耗大、运行时间长等缺陷

在这里插入图片描述

2 跳点搜索算法

2.1 自然与强制邻点

针对A*算法的缺陷,Harabor等提出跳点搜索算法(Jump Point Search, JPS),筛选出有价值的节点——称为跳点而剪去那些无意义的冗余节点。

n n n是节点 x x x的邻接点, p p p是节点 x x x的父节点,节点 x x x的邻域采用八邻域法,则跳点剪枝策略中的基本概念如下:

  • 自然邻点:当节点 x x x邻域不存在障碍时(暂时移除障碍),若从 p p p出发任意不经过节点 x x x到达 n n n的路径 < p , ⋯   , n ∣ x > <p,\cdots ,n|x> <p,,nx>比经过 x x x到达 n n n的路径 < p , ⋯   , x , ⋯   , n > <p,\cdots ,x,\cdots ,n> <p,,x,,n>长,即
    { L ( < p , ⋯   , n ∣ x > ) ⩾ L ( < p , ⋯   , x , ⋯   , n > ) , p 是 x 的对角节点 L ( < p , ⋯   , n ∣ x > ) > L ( < p , ⋯   , x , ⋯   , n > ) , o t h e r w i s e \begin{cases} L\left( <p,\cdots ,n|x> \right) \geqslant L\left( <p,\cdots ,x,\cdots ,n> \right) , p\text{是}x\text{的对角节点}\\ L\left( <p,\cdots ,n|x> \right) >L\left( <p,\cdots ,x,\cdots ,n> \right) , \mathrm{otherwise}\\\end{cases} {L(<p,,nx>)L(<p,,x,,n>),px的对角节点L(<p,,nx>)>L(<p,,x,,n>),otherwise
    恒成立,则称邻接点 n n n是节点 x x x在父节点是 p p p时的自然邻点

  • 强制邻点:当节点 x x x的邻域存在障碍时,若从 p p p出发任意不经过节点 x x x到达 n n n的路径 < p , ⋯   , n ∣ x > <p,\cdots ,n|x> <p,,nx>比经过节点 x x x到达 n n n的路径 < p , ⋯   , x , ⋯   , n > <p,\cdots ,x,\cdots ,n> <p,,x,,n>长,且节点 n n n不是节点 x x x的自然邻点,则称邻接点 n n n是节点 x x x在父节点是 p p p时的强制邻点,如图所示为水平搜索与斜搜索情况下的八种强制邻点情况。

在这里插入图片描述

2.2 跳点剪枝策略

跳点本质上是搜索方向可能发生改变的点,其筛选规则为

  • 若节点 x x x是终点,则节点 x x x是跳点;
  • 若节点 x x x存在至少一个强制邻点,则节点 x x x是跳点;
  • 在斜向搜索时,若节点 x x x在水平或垂直分量上有跳点,则节点 x x x是跳点

用一个实例说明。如图所示的栅格地图中,绿色是起点,红色是终点,黑色是障碍物

在这里插入图片描述
我们首先用A*算法看看规划的路径,其中绿色是开节点表中的节点,蓝色是闭节点表中的节点,黄色是规划路径

在这里插入图片描述
再用JPS算法执行路径规划,灰色的是在搜索过程中被跳过的点,而绿色节点就是跳点,实际应用于算法搜索中的节点(绿色和蓝色),与A*算法相比大幅度减少。

在这里插入图片描述

3 算法仿真与实现

3.1 算法流程

JPS算法的核心就是jump()函数,我采用递归方法来实现,使得整体代码量下降,且逻辑更清晰明确。总的思路就是实现跳点剪枝的三条策略

  • 若节点 x x x是终点,则节点 x x x是跳点;
  • 若节点 x x x存在至少一个强制邻点,则节点 x x x是跳点;
  • 在斜向搜索时,若节点 x x x在水平或垂直分量上有跳点,则节点 x x x是跳点

在这里插入图片描述
跳点剪枝策略就是通过筛选跳点作为探索域,而忽略对搜索路径没有实质影响的冗余节点,实现大幅度降低计算复杂度的效果。JPS算法最大的优势是在障碍密集的情况下,相较传统A*算法的计算速度一般有量级的提升;缺陷是其不能应用于广义图搜索,只适用于栅格地图。

3.2 ROS C++实现

Node JumpPointSearch::jump(const Node& point, const Node& motion)
{
  Node new_point = point + motion;
  new_point.id_ = this->grid2Index(new_point.x_, new_point.y_);
  new_point.pid_ = point.id_;
  new_point.h_ = std::sqrt(std::pow(new_point.x_ - this->goal_.x_, 2) + std::pow(new_point.y_ - this->goal_.y_, 2));

  // next node hit the boundary or obstacle
  if (new_point.id_ < 0 || new_point.id_ >= this->ns_ || this->costs_[new_point.id_] >= this->lethal_cost_ * this->factor_)
    return Node(-1, -1, -1, -1, -1, -1);

  // goal found
  if (new_point == this->goal_)
    return new_point;

  // diagonal
  if (motion.x_ && motion.y_)
  {
    // if exists jump point at horizontal or vertical
    Node x_dir = Node(motion.x_, 0, 1, 0, 0, 0);
    Node y_dir = Node(0, motion.y_, 1, 0, 0, 0);
    if (this->jump(new_point, x_dir).id_ != -1 || this->jump(new_point, y_dir).id_ != -1)
      return new_point;
  }

  // exists forced neighbor
  if (this->detectForceNeighbor(new_point, motion))
    return new_point;
  else
    return this->jump(new_point, motion);
}

在这里插入图片描述

3.3 Python实现

def jump(self, node: Node, motion: Node):
    # explore a new node
    new_node = node + motion
    new_node.parent = node.current
    new_node.h = self.h(new_node, self.goal)

    # hit the obstacle
    if new_node.current in self.obstacles:
        return None

    # goal found
    if new_node == self.goal:
        return new_node

    # diagonal
    if motion.current[0] and motion.current[1]:
        # if exists jump point at horizontal or vertical
        x_dir = Node((motion.current[0], 0), None, 1, None)
        y_dir = Node((0, motion.current[1]), None, 1, None)
        if self.jump(new_node, x_dir) or self.jump(new_node, y_dir):
            return new_node
        
    # if exists forced neighbor
    if self.detectForceNeighbor(new_node, motion):
        return new_node
    else:
        return self.jump(new_node, motion)

在这里插入图片描述

3.4 Matlab实现

function [new_node, flag] = jump(cur_node, motion, goal, map)
    flag = false;

    % explore a new node
    new_node = [cur_node(1) + motion(1), ...
                      cur_node(2) + motion(2), ...
                      cur_node(3) + motion(3), ...
                      0, cur_node(1), cur_node(2)
                      ];
    new_node(4) = h(new_node(1:2), goal);

    % obstacle
    if new_node(1) <= 0 || new_node(2) <= 0 || map(new_node(1), new_node(2)) == 2
        return
    end

    % goal found
    if new_node(1) == goal(1) && new_node(2) == goal(2)
        flag = true;
        return
    end

    % diagonal
    if motion(1) && motion(2)
        % if exists jump point at horizontal or vertical
        x_dir = [motion(1), 0, 1];
        y_dir = [0, motion(2), 1];
        [~, flag_x] = jump(new_node, x_dir, goal, map);
        [~, flag_y] = jump(new_node, y_dir, goal, map);
        if  flag_x || flag_y 
            flag = true;
            return
        end
    end
            
    % if exists forced neighbor
    if detect_force(new_node, motion, map)
        flag = true;
        return
    else
        [new_node, flag] = jump(new_node, motion, goal, map);
        return
    end
end

在这里插入图片描述

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


🔥 更多精彩专栏

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

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

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

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

相关文章

2. Unity操作基础知识

1. 创建新项目 双击打开 unity hub管理器&#xff0c;点击左侧栏中的 项目 选项卡&#xff0c;在右上角点击 新项目 按钮&#xff0c;进入项目创建页面&#xff1a; 在项目创建页面中&#xff0c;选择合适的模板&#xff0c;并设置项目名称&#xff0c;选择项目保存位置&…

【郭东白架构课 模块一:生存法则】12|法则五:如何提升一个架构设计的外部适应性?

你好&#xff0c;我是郭东白。 上节课我们讲了外部适应性这个概念&#xff0c;也强调了架构师的职责是通过架构活动为企业不断注入外部适应性&#xff0c;从而帮助企业更好地实现它的战略意图。 那么该怎么注入呢&#xff1f; 上节课在讲影响技术体系外部适应性的因素这部分…

MYSQL---第四次索引视图

学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 学生选课表&#xff1a;SC (…

AtCoder Beginner Contest 290 A-E F只会n^2

ABC比较简单就不再复述 D - Marking 简要题意 &#xff1a;给你一个长度为nnn的数组,下标为0到n−10 到 n-10到n−1&#xff0c;最初指针位于0,重复执行n-1次操作&#xff0c;每次操作的定义为将当前指针加上ddd&#xff0c;如果该位置为空(未填数),否则我们向右找到第一个为空…

《刀锋》读书笔记

刀锋&#xff08;毛姆长篇作品精选&#xff09;毛姆50个笔记点评认为好看的确是完美的结局。《刀锋》里面的人每个人都以自己的方式生活着。艾略特的势利&#xff0c;拉里的自由&#xff0c;伊莎贝尔的现实&#xff0c;苏珊的清醒&#xff0c;索菲的堕落&#xff0c;至于“我”…

【数据结构与算法】链表2:节点交换与删除 链表相交 环形链表

文章目录今日任务1.Leetcode24&#xff1a;两两交换链表中的节点&#xff08;1&#xff09;题目&#xff08;2&#xff09;思路&#xff08;3&#xff09;代码实现2.Leetcode19&#xff1a;删除链表的倒数第N个节点&#xff08;1&#xff09;题目&#xff08;2&#xff09;思路…

芯片架构RISC-V、X86、ARM三足鼎立

2022 年 7 月&#xff0c;RISC-V 国际基金会首席执行官 Calista Redmond 在嵌入式世界大会上宣布 RISC-V 架构处理器核的出货数量已突破 100 亿颗。 序号架构特点代表性的厂商运营机构发明时间1X86性能高&#xff0c;速度快&#xff0c;兼容性好英特尔&#xff0c;AMD英特尔197…

nginx-服务器banner泄漏风险

http { server_tokens off; # 隐藏Nginx版本号 .... }

桌面美化方案分享+环境配置记录

桌面美化方案分享环境配置记录 旧笔记本是高考结束时候买的&#xff0c;做工稀烂&#xff0c;买来当天键盘就被我敲坏了。当时送去维修&#xff0c;那边的人说暂时没货&#xff0c;要等键盘进货才能换。然后等了四年&#xff0c;键盘还没进到货。 该换了。 旧笔记本上显卡是…

【Vue3源码】第二章 effect功能的完善补充

【Vue3源码】第二章 effect功能的完善补充 前言 上一章节我们实现了effect函数的功能stop和onstop&#xff0c;这次来优化下stop功能。 优化stop功能 之前我们的单元测试中&#xff0c;stop已经可以成功停止了响应式更新&#xff08;清空了收集到的dep依赖&#xff09; st…

nginx+php-fpm整体上线k8s集群之后虚拟内存不断上涨原因排查

背景 为了可以更好的管理我们的lnmp集群&#xff0c;打算将原有的php环境整体打包成一个镜像然后上到k8s容器&#xff0c;这样可以不仅使用到k8s的快速扩缩容和管理的好处&#xff0c;而且让机器资源能更好被利用&#xff0c;减少机器数量 问题 当我们将流量从原有的php机器…

Elasticsearch的安装及常用操作

文章目录一、Elasticsearch的介绍1、Elasticsearch索引2、Elasticsearch的介绍二、Elasticsearch的安装1、安装ES服务2、安装kibana3、Docker安装ES4、Docker安装Kibana三、ES的常用操作1、索引操作2、文档操作3、域的属性3.1 index3.2 type3.3 store总结一、Elasticsearch的介…

关于云计算,我们问了ChatGPT 10个问题

ChatGPT懂云计算吗&#xff1f;前些天&#xff0c;我们问了ChatGPT&#xff08;非Plus收费版&#xff09;一些问题。1. 什么是云计算&#xff1f;2. 云计算行业的护城河是什么&#xff1f;3. 什么是云原生&#xff1f;4. 微软Azure与亚马逊AWS的主要区别是什么&#xff1f;5. 为…

你真的会做APP UI自动化测试吗?我敢打赌百分之九十的人都不知道这个思路

目录 前言 一&#xff0c;开发语言选择 二&#xff0c;UI测试框架选择 1&#xff0c;Appium 2&#xff0c;Airtest 3&#xff0c;选择框架 三&#xff0c;单元测试框架选择 四&#xff0c;测试环境搭建 1&#xff0c;测试电脑选择 2&#xff0c;测试手机选择 3&#…

6.关于系统服务的思考—— native vs java

文章目录native服务 以sensor service为例Native 服务java 服务&#xff0c; 以vibrate为例java 服务 以一个demo为例native服务 以sensor service为例 service启动 SystemServer.startBootstrapServices---->>>mSystemServiceManager.startService—>>>Sen…

SQL语句创建视图:

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言初阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍数据库中有关视图的知识,参考学校作业. 金句分享:…

基于SpringBoot的在线文档管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…

进程-操作系统结构

进程-操作系统结构 中文仅本人理解&#xff0c;有错误请联系我。 操作系统为不同方面服务&#xff0c;有不同的设计角度。 为用户&#xff1a; 使用 为程序员&#xff1a;创造 程序员需要关注的就是system call接口的调度 file systems&#xff1a;ntfs&#xff0c;ext4 commu…

eclipse快捷开发学习笔记

快速收起java类中的所有代码当类中方法过多时&#xff0c;收起所有方法&#xff0c;可以方便查看注释找到方法右击左侧栏任意行号位置-点击Folding-点击Collapse All效果图如下代码格式化混乱的代码格式化后&#xff0c;方便阅读分析菜单栏-Source-Format效果如下3.查看方法被哪…

Bland-Altman图

介绍 Bland-Altman图是一种一致性评价测量方法&#xff0c;简称BA&#xff0c;常用于医学实验和数据分析。 可使用它检测两组数据的一致性&#xff0c;比如对比新旧两种方法&#xff0c;对比一组实际值和预测值等。相对于校准曲线&#xff0c;它能更好地对比两组数据中每个数据…