路径规划 | 详解维诺图Voronoi算法(附ROS C++/Python/Matlab仿真)

news2024/11/25 4:24:24

目录

  • 0 专栏介绍
  • 1 维诺图规划原理
  • 2 ROS C++实现(栅格图搜索)
  • 3 Python实现(路图搜索)
  • 4 Matlab实现(路图搜索)

0 专栏介绍

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

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


1 维诺图规划原理

在地图结构 | 图解维诺图Voronoi原理(附C++/Python/Matlab仿真)中,我们介绍了维诺图的概念。维诺图(Voronoi Diagram),也称为泰森多边形(Thiessen Polygon),是一种用于将空间分割为一组区域的图形化方法,其中每个区域都由一个特定点(种子点)控制,使得每个点到其控制的种子点最近。

在路径规划领域,维诺图作为一种栅格图分解方法用于自主导航任务。与计算几何的概念类似,令离散点集为障碍栅格,则定义规划空间中离最近的两个障碍物具有相同距离的点集为广义维诺图(Generalized Voronoi Diagram, GVD)。GVD通过对空间划分有效减少了路径搜索维度,且沿着GVD边缘移动可确保在穿越障碍物时具有最大的安全间隙

在这里插入图片描述

建立维诺图后,搜索对象从全域栅格节点减少为维诺节点,搜索效率提高。基于维诺图的路径规划虽然不满足路径最优,但可以最大程度保证运动安全。总体来说,基于维诺图的路径规划分为两部分:

  1. 根据栅格地图建立维诺图
  2. 在维诺图上运用最短路算法

这里提供两种常见的算法流程:栅格图搜索路图搜索,其中维诺图的构造算法详见地图结构 | 图解维诺图Voronoi原理(附C++/Python/Matlab仿真),本文不再赘述

在这里插入图片描述

在这里插入图片描述

接下来对这两种算法进行实现

2 ROS C++实现(栅格图搜索)

核心算法如下所示

bool VoronoiPlanner::plan(VoronoiData** voronoi_diagram, const Node& start, const Node& goal, std::vector<Node>& path)
{
  voronoi_diagram_ = voronoi_diagram;

  // clear vector
  path.clear();

  // start/goal to Voronoi Diagram, shortest path in Voronoi Diagram
  std::vector<Node> path_s, path_g, path_v;

  // start/goal point in Voronoi Diagram
  Node v_start, v_goal;

  if (!searchPathWithVoronoi(start, goal, path_s, &v_start))
    return false;

  if (!searchPathWithVoronoi(goal, start, path_g, &v_goal))
    return false;
  std::reverse(path_g.begin(), path_g.end());

  if (!searchPathWithVoronoi(v_start, v_goal, path_v))
    return false;

  path_g.insert(path_g.end(), path_v.begin(), path_v.end());
  path_g.insert(path_g.end(), path_s.begin(), path_s.end());
  path = path_g;

  return true;
}

效果如下

在这里插入图片描述

3 Python实现(路图搜索)

核心代码如下:

def plan(self):
	# sampling voronoi diagram
	vor = Voronoi(np.array(list(self.env.obstacles)))
	vx_list = [ix for [ix, _] in vor.vertices] + [self.start.x, self.goal.x]
	vy_list = [iy for [_, iy] in vor.vertices] + [self.start.y, self.goal.y]
	sample_num = len(vx_list)
	expand = [Node((vx_list[i], vy_list[i])) for i in range(sample_num)]
	
	# generate road map for voronoi nodes
	road_map = {}
	node_tree = cKDTree(np.vstack((vx_list, vy_list)).T)
	
	for node in expand:
	    edges = []
	    _, index_list = node_tree.query([node.x, node.y], k=sample_num)
	
	    for i in range(1, len(index_list)):
	        node_n = expand[index_list[i]]
	
	        if not self.isCollision(node, node_n):
	            edges.append(node_n)
	
	        if len(edges) >= self.n_knn:
	            break
	
	    road_map[node] = edges
	
	# calculate shortest path using graph search algorithm
	cost, path = self.getShortestPath(road_map)
	return cost, path, expand

效果如下:

在这里插入图片描述

4 Matlab实现(路图搜索)

function [path, goal_reached, cost, EXPAND] = voronoi_plan(map, start, goal)
    % Maximum expansion distance one step
    max_dist = 3;
    % map size
    [y_range, x_range] = size(map);
    % resolution
    resolution = 0.1;
    % number of edges from one sampled point
    n_knn = 5;
    
    % construct Voronoi diagram
    [ox, oy] = find(map == 2);
    [vx, vy] = voronoi(oy, ox);
    start(:, [1 2]) = start(:, [2 1]);
    goal(:, [1 2]) = goal(:, [2 1]);

    % Voronoi diagram filter
    index_x = intersect(find(vx(1, :) > 0 & vx(1, :) < x_range), ...
                                     find(vx(2, :) > 0 & vx(2, :) < x_range));
    index_y = intersect(find(vy(1, :) > 0 & vy(1, :) < y_range), ...
                                     find(vy(2, :) > 0 & vy(2, :) < y_range));
    index = intersect(index_x, index_y);
    vx = vx(:, index); vy = vy(:, index);
    vd_vertex = [];
    EXPAND = [];
    for i = 1:length(index)
        node1 = [vx(1, i), vy(1, i)];
        node2 = [vx(2, i), vy(2, i)]; 

        if ~all(node1 == node2) && ~is_collision(node1, node2, map, -1, resolution)
            EXPAND = [EXPAND, [vx(:, i); vy(:, i)]];
            vd_vertex = [vd_vertex; [vx(:, i), vy(:, i)]];
        end
    end
    vd_vertex = [unique(vd_vertex, 'rows'); start; goal];
    
    % generate road map for voronoi nodes
    road_map = containers.Map();
    num_vd = size(vd_vertex, 1);
    for i = 1:num_vd
        knn_nodes = vd_vertex(knnsearch(vd_vertex, vd_vertex(i, :), 'K', num_vd), :);
        edges = [];
        for j = 1:num_vd
            if ~is_collision(vd_vertex(i, :), knn_nodes(j, :), map, max_dist, resolution)
                edges = [edges; knn_nodes(j, :)];
            end
            if size(edges, 1) == n_knn
                break;
            end
        end
        % hash-map: from grid index to edges
        road_map(string(vd_vertex(i, 1) + x_range * vd_vertex(i, 2))) = edges;
    end

    [path, goal_reached, cost] = get_shortest_path(road_map, start, goal, map, max_dist, resolution);
    if goal_reached
        path(:, [1 2]) = path(:, [2 1]);
    else
        path = [];
        cost = 0;
    end
end

效果如下:

在这里插入图片描述

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


🔥 更多精彩专栏

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

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

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

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

相关文章

validation之自定义注解@Constraint

前言&#xff1a; 首先&#xff0c;接口参数校验应该都不陌生&#xff0c;大部分应该都会借助javax.validation进行快捷校验&#xff0c;一般都是在入参字段上添加NotNull、NotEmpty等&#xff0c;对于一些特殊的入参校验逻辑&#xff0c;可能不是很适用&#xff0c;现在介绍一…

Torch基本操作扫盲

torch.rand是均匀分布采样 torch.randn是标准正态分布采样 同时设定好了GPU种子 高斯/正态分布

强烈推荐一本讲IT管理的书

“真正的智慧不是知识&#xff0c;而是想象。” —— 阿尔伯特爱因斯坦 在这个信息化时代&#xff0c;IT行业以其巨大的生产力和创新力&#xff0c;深深地改变着每一个角落的生活和工作。而在这个行业里&#xff0c;IT运维无疑是一个至关重要的角色。然而&#xff0c;即使在IT界…

第二十一章 重要HL7操作场景 - HL7批量消息

文章目录 第二十一章 重要HL7操作场景 - HL7批量消息支持的批处理格式处理传入的批次文档批处理模式自定义出库批量处理 第二十一章 重要HL7操作场景 - HL7批量消息 Production品支持 HL7 中的嵌套子文档&#xff08;批处理格式&#xff09;。每个子文档本身就是一个虚拟文档。…

LeetCode 0617. 合并二叉树

【LetMeFly】617.合并二叉树 力扣题目链接&#xff1a;https://leetcode.cn/problems/merge-two-binary-trees/ 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而…

【代码随想录-Leetcode第六题:209. 长度最小的子数组】

209. 长度最小的子数组 题目思路代码实现 题目 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回…

网络编程(TFTP协议实验)

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <head.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h>#define PORT 69 //端口号&#xf…

详谈MongoDB的那些事

概念区分 什么是关系型数据库 关系型数据库&#xff08;Relational Database&#xff09;是一种基于关系模型的数据库管理系统&#xff08;DBMS&#xff09;。在关系型数据库中&#xff0c;数据以表格的形式存储&#xff0c;表格由行和列组成&#xff0c;行表示数据记录&…

TypeScript 语法

环境搭建 以javascript为基础构建的语言&#xff0c;一个js的超集&#xff0c;可以在任何支持js的平台中执行&#xff0c;ts扩展了js并且添加了类型&#xff0c;但是ts不能被js解析器直接执行&#xff0c;需要编译器编译为js文件&#xff0c;然后引入到 html 页面使用。 ts增…

Python批量给excel文件加密

有时候我们需要定期给公司外部发邮件&#xff0c;在自动化发邮件的时候需要对文件进行加密传输。本文和你一起来探索用python给单个文件和批量文件加密。    python自动化发邮件可参考【干货】用Python每天定时发送监控邮件。 文章目录 一、安装pypiwin32包二、定义给excel加…

推荐几款流行的项目管理系统,助力高效团队协作!

项目式管理是目前非常流行的企业管理方法&#xff0c;这种方法让是如何在确保时间、技术、经费和性能指标的条件下&#xff0c;以尽可能高的效率完成预定目标&#xff0c;让所有与企业相关方满意。在这种模式下&#xff0c;团队的层次关系不再那么重要&#xff0c;大家以项目结…

第一百二十八天学习记录:数据结构与算法基础:栈和队列(上)(王卓教学视频)

栈和队列的定义和特点 1、栈和队列是两种常用的、重要的数据结构 2、栈和队列是限定插入和删除只能在表的“端点”进行的线性表 线性表可以在任意一个位置插入和删除&#xff0c;栈只能在最后位置插入和删除 队列 只能删除第一个元素 栈和队列是线性表的子集&#xf…

测试开发探索:“WeTalk“网页聊天室的测试流程与自动化

目录 引言&#xff1a; 测试开发目标&#xff1a; "WeTalk"项目背景 关于登录测试用例的设计 测试开发策略与流程 集成测试&#xff1a;Selenium JUnit 接口测试&#xff1a;Postman 测试用例的设计与实现 自动化测试演示&#xff1a; 用例一&#xff1a;登…

【Linux操作系统】深入理解Linux系统编程中的传入参数、传出参数和传入传出参数

在Linux系统编程中&#xff0c;函数的参数扮演着至关重要的角色。参数的传递方式可以分为传入参数、传出参数和传入传出参数。本文将详细解释这三种参数的概念、特点以及如何使用它们来实现灵活和高效的函数调用和数据传递。 文章目录 1. 解释和举例1.1 传入参数&#xff08;i…

案例15 Spring Boot入门案例

1. 选择Spring Initializr快速构建项目 ​ 2. 设置项目信息 ​ 3. 选择依赖 ​ 4. 设置项目名称 ​ 5. 项目结构 ​ 6. 项目依赖 自动配置了Spring MVC、内置了Tomcat、配置了Logback(日志)、配置了JSON。 ​ 7. 创建HelloController类 com.wfit.boot.hello目录下创建HelloCo…

NO.3 MyBatis获取参数的两种方式

目录 1、两种方式的区别 2、单个字面量类型的参数 2.1 在映射文件中&#xff0c;用#{}加任意名称获取参数的值&#xff1a; 2.2 在映射文件中&#xff0c;用${}加任意名称获取参数的值&#xff1a; 2.3 小结 3、在map集合类型的参数 3.1 使用MyBatis默认的map映射集合 …

delphi11中的自动启动和关闭unigui应用服务器

1、设置。 注意&#xff1a;全部。 taskkill /f /im $(OUTPUTFILENAME) 2>1 || exit /B 0 自动运行chrome打开unigui网页 unit ServerModule;interfaceuses Winapi.ShellAPI, vcl.Dialogs;typeTUniServerModule class(TUniGUIServerModule)procedure UniGUIServerModu…

不一般的自定义时间(html+css+js)

自定义时间 写文章的因 关于要写这篇文章的原因 是记录在工作上遇到的困难需求&#xff0c;是希望能给大家提供一些解决问题的思路 接下来我描述这个需求的多样性&#xff0c;难点在哪。 勾选勾选框开始时间与结束时间默认显示昨天与今天。取消勾选框开始时间与结束时间清空。…

spring源码核心

spring创建bean的生命周期&#xff08;大概&#xff09; 容器 可以理解容器为一个Map<beanName, bean对象> 通过类的构造方法创建对象 有两个有参构造方法&#xff0c;就坏了&#xff0c;spring不知道用哪个&#xff0c;这个时候可以加**Autowired** 有无参和有参时…

运营商二要素认证API接口:提供手机号实名验证服务,确保用户信息的真实性

随着互联网的快速发展&#xff0c;各行各业都需要用户进行实名认证。其中&#xff0c;涉及到用户个人信息的场景&#xff0c;如电商、游戏、直播、金融等需要用户实名认证的场景&#xff0c;必须要进行实名认证。然而&#xff0c;对于这些场景&#xff0c;用户的个人信息的真实…