路径规划——RRT算法

news2024/11/15 23:33:48

路径规划——RRT算法

算法原理

RRT算法的全称是快速扩展随机树算法(Rapidly Exploring Random Tree),它的思想是选取一个初始点作为根节点,通过随机采样,增加叶子节点的方式,生成一个随机扩展树,当随机树中的叶子节点包含了目标点或进入了目标区域,边可以在随机树中通过回溯的方式,找到这条从初始点到目标点的路径。

此算法的重点随机采样+步⻓限制+碰撞检测

算法流程:
1.初始化:以起点start为根节点,创建一棵树(通常用二叉树表示),树的根节点表示起始位置。
2.随机采样:在搜索空间中随机生成一个点x_rand。这个点可能在自由空间中,也可能在障碍物中。
3.寻找最近的节点:在当前的树中找到距离x_rand最近的节点x_near
4.扩展树:从x_near沿着指向x_rand的方向移动一小步,生成一个新的节点x_new。如果x_new在自由空间中(即不与障碍物碰撞),则将x_new加入到树中,并将x_nearn_new用一条边连接。
5.检查目标:检查x_new是否在目标区域附近,这里的“附近”可以设置一个搜索距离来量化。如果是,则生成一条路径从起点到x_new,并结束算法。
6.迭代:重复步骤2~步骤5,直到找到目标点goal,或达到预设的迭代次数。

由于RRT采用随机采样的方法,RRT生成的路径通常不一定是最优路径,但可以通过多次运行RRT或结合其他优化算法来获得更优路径。

在这里插入图片描述

算法实现

import numpy as np
import random
import math
from itertools import combinations
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.patches as patches

class RRT:
    def __init__(self,start,goal,obstacles,board_size,max_try,max_dist,goal_sample_rate,env) -> None:
        self.start = self.Node(start,None,0)
        self.goal = self.Node(goal,None,0)
        self.obstacles = obstacles
        self.board_size = board_size
        self.max_try = max_try # Number of iterations
        self.max_dist = max_dist # Maximum sampling distance
        self.goal_sample_rate = goal_sample_rate
        self.env = env
        self.inflation = 1
        self.searched = []

    class Node:
        def __init__(self,position,parent,cost):
            self.position = position
            self.parent = parent
            self.cost = cost

    def run(self):
        cost,path = self.plan()
        self.visualize(cost,path)

    def plan(self):
        self.searched.append(self.start)
        closed_list = {self.start.position: self.start}
        # plan max_try times
        for i in range(self.max_try):
            node_rand = self.get_random_node()
            # visited
            if node_rand.position in closed_list:
                continue
            # Get the nearest neighbor node
            node_near = self.get_nearest_neighbor(list(closed_list.values()),node_rand)
            # Get the new node
            node_new = self.get_new_node(node_rand,node_near)
            if node_new:
                closed_list[node_new.position] = node_new
                self.searched.append(node_new)
                dist = self.distance(node_new,self.goal)
                # Found goal successfully
                if dist <= self.max_dist and not self.isCollision(node_new,self.goal):
                    self.searched.append(self.goal)
                    self.goal.parent = node_new
                    self.goal.cost = node_new.cost + self.distance(self.goal,node_new)
                    closed_list[self.goal.position] = self.goal
                    cost, path= self.extractPath(closed_list)

                    print("Exploring {} nodes.".format(i))
                    return cost,path
                
        return 0,None


    def get_random_node(self) :
        """
            Return a random node.
        """
        if random.random()>self.goal_sample_rate:
            node = self.Node(
                (random.uniform(0,self.env.height),random.uniform(0,self.env.width)),None,0)
        else:
            node = self.Node(self.goal.position,None,0)
            
        return node

    def get_nearest_neighbor(self,node_list,node) -> Node:
        """
            Return node that is nearest to 'node' in node_list
        """
        dist = [self.distance(node, n) for n in node_list]
        node_near = node_list[int(np.argmin(dist))]
        return node_near
    
    def get_new_node(self,node_rand,node_near):
        """
            Return node found based on node_near and node_rand.
        """
        dx = node_rand.position[0] - node_near.position[0]
        dy = node_rand.position[1] - node_near.position[1]
        dist = math.hypot(dx,dy)
        theta = math.atan2(dy, dx)

        d = min(self.max_dist,dist)
        position = ((node_near.position[0]+d*math.cos(theta)),node_near.position[1]+d*math.sin(theta))

        node_new = self.Node(position,node_near,node_near.cost+d)

        if self.isCollision(node_new, node_near):
            return None
        return node_new
    
    def isCollision(self,node1,node2):
        """
            Judge collision from node1 to node2 
        """
        if self.isInObstacles(node1) or self.isInObstacles(node2):
            return True
        
        for rect in self.env.obs_rectangle:
            if self.isInterRect(node1,node2,rect):
                return True
        
        for circle in self.env.obs_circle:
            if self.isInterCircle(node1,node2,circle):
                return True
        
        return False
    
    def distance(self,node1,node2):
        dx = node2.position[0] - node1.position[0]
        dy = node2.position[1] - node1.position[1]

        return math.hypot(dx,dy)
        

    def isInObstacles(self,node):
        """
            Determine whether it is in obstacles or not.
        """
        x,y = node.position[0],node.position[1]
        for (ox,oy,w,h) in self.env.boundary:
            if ox-self.inflation<x<ox+w+self.inflation and oy-self.inflation<y<oy+h+self.inflation:
                return True
        
        for (ox,oy,w,h) in self.env.obs_rectangle:
            if ox-self.inflation<x<ox+w+self.inflation and oy-self.inflation<y<oy+h+self.inflation:
                return True
            
        for (ox,oy,r) in self.env.obs_circle:
            if math.hypot(x-ox,y-oy)<=r+self.inflation:
                return True
        
        return False
    
    def isInterRect(self,node1,node2,rect):
        """"
            Judge whether it will cross the rectangle when moving from node1 to node2
        
        """
        ox,oy,w,h = rect
        vertex = [[ox-self.inflation,oy-self.inflation],
                  [ox+w+self.inflation,oy-self.inflation],
                  [ox+w+self.inflation,oy+h+self.inflation],
                  [ox-self.inflation,oy+h+self.inflation]]
        
        x1,y1 = node1.position
        x2,y2 = node2.position

        def cross(p1,p2,p3):
            x1 = p2[0]-p1[0]
            y1 = p2[1]-p1[1]
            x2 = p3[0]-p1[0]
            y2 = p3[1]-p1[0]
            return x1*y2 - x2*y1
        
        for v1,v2 in combinations(vertex,2):
            if max(x1,x2) >= min(v1[0],v2[0]) and min(x1,x2)<=max(v1[0],v2[0]) and \
                max(y1,y2) >= min(v1[1],v2[1]) and min(y1,y2) <= max(v1[1],v2[1]):
                if cross(v1,v2,node1.position) * cross(v1,v2,node2.position)<=0 and \
                    cross(node1.position,node2.position,v1) * cross(node1.position,node2.position,v2):
                    return True
    
        return False
    
    def isInterCircle(self,node1,node2,circle):
        """
            Judge whether it will cross the circle when moving from node1 to node2
        """
        ox,oy,r = circle

        dx = node2.position[0] - node1.position[0]
        dy = node2.position[1] - node1.position[1]
            
        # Projection
        t = ((ox - node1.position[0]) * dx + (oy - node1.position[1]) * dy) / (dx * dx + dy * dy)
        
        # The projection point is on line segment AB
        if 0 <= t <= 1:
            closest_x = node1.position[0] + t * dx
            closest_y = node1.position[1] + t * dy
        
            # Distance from center of the circle to line segment AB
            distance = math.hypot(ox-closest_x,oy-closest_y)
            
            return distance <= r+self.inflation
        
        return False

    
    def extractPath(self,closed_list):
        """"
            Extract the path based on the closed list.
        """
        node = closed_list[self.goal.position]
        path = [node.position]
        cost = node.cost
        while node != self.start:
            parent = node.parent
            node_parent = closed_list[parent.position]
            node = node_parent
            path.append(node.position)

        return cost,path


    def visualize(self, cost, path):
        """
            Plot the map.
        """
        ....

结果图:

在这里插入图片描述

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

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

相关文章

基于阿里云函数计算(FC)x 云原生 API 网关构建生产级别 LLM Chat 应用方案最佳实践

作者&#xff1a;计缘 LLM Chat 应用大家应该都不陌生&#xff0c;这类应用也逐渐称为了我们日常的得力助手&#xff0c;如果只是个人使用&#xff0c;那么目前市面上有很多方案可以快速的构建出一个LLM Chat应用&#xff0c;但是如果要用在企业生产级别的项目中&#xff0c;那…

开源软件如何保证数据安全?从一下七个方面进行分析

1、加密软件来保护 在开源软件中&#xff0c;数据加密和保护是保障数据安全的重要手段。开发者应该使用强加密算法的加密软件来保护敏感数据&#xff0c;并确保数据传输和存储的安全性。通过驱动层加密技术&#xff0c;对开发源代码进行强制加密处理&#xff0c;文件创建自动进…

Mac在Python项目中通过opencv模版匹配定位不到图片

起因 原本一行代码的事情&#xff0c;但是在Mac上总能出现意外&#xff0c;如下 box pyautogui.locateOnScreen(obsidian.png) print(box) pyautogui.moveTo(box[0],box[1])上面的代码用来定位图片在屏幕中的位置&#xff0c;然后移动鼠标到定位到的屏幕位置坐标。 意外…

IT管理:我与IT的故事9-数字化转型7步思考行动法

四书即论语、孟子、大学、中庸&#xff0c;又称四子书&#xff0c;为历代儒学子首要研习之书。南宋朱熹取《礼记》之大学、中庸篇&#xff0c;分章注释&#xff0c;与论语、孟子合为“四书”。 四书及其注释包涵孔子弟子及再传弟子、孟子、程子、朱熹等&#xff0c;其编撰时长达…

代码随想录Day 38|背包问题完结,题目322.零钱兑换、279.完全平方数、139,单词拆分数

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 动态规划part06题目题目一&#xff1a;322. 零钱兑换解题思路&#xff1a;题目二&#xff1a;279.完全平方数题目三&#xff1a;139.单词拆分数解题思路&#xff1a;背包问题 多重背包&#xff08;…

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中&#xff0c;积水问题日益严重&#xff0c;特别是在大雨过后&#xff0c;积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术&#xff0c;我们能够智能化地检测和识别积水区域&#xff0c;减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积…

Unity使用自定义类型作为字典Key的最佳实践与避坑指南

自定义类型作为字典Key的最佳实践与避坑指南文章首发 问题背景 首先提一下之前项目开发时遇到的一个将自定义类型作为Dictionary键的坑。 项目中&#xff0c;我们有两个业务类BusinessA和BusinessB&#xff0c;因为某个需求&#xff0c;我们需要将这两个类建立一个映射关系&…

游泳馆收银系统源码解析之手牌管理--SAAS本地化及未来之窗行业应用跨平台架构

一、代码 if(手牌状态 "空"){结算界面 "";未来之窗_人工智能_通用页面_尺寸(title"游泳馆",收费,500,300);}else{未来之窗_人工智能_通用页面_尺寸(title"游泳馆",退款,1200,500);} 二、阿雪技术观 拥抱开源与共享&#xff0c;见…

探索图论中的关键算法(Java 实现)

“日出东海落西山 愁也一天 喜也一天 遇事不钻牛角尖” 文章目录 前言文章有误敬请斧正 不胜感恩&#xff01;||Day031. 最短路径算法Dijkstra算法Java 实现&#xff1a; Bellman-Ford算法Java 实现&#xff1a; 2. 最小生成树算法Prim算法Java 实现&#xff1a; Kruskal算法Ja…

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态&#xff0c;生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案&#xff0c;则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时&#x…

读软件设计的要素05概念的特性

1. 概念的特性 1.1. 专一性原则(specificity principle)认为概念与目的应该一一对应 1.1.1. 专一性原则已被证明是概念设计中最有用的原则之一 1.1.2. 一个概念最多只能满足一个目的 1.2. 很少有没有目的的概念 1.2.1. 如果本应隐藏的用户机制被暴露&#xff0c;可能会产生…

通信工程学习:什么是2ASK/BASK二进制振幅键控

2ASK/BASK&#xff1a;二进制振幅键控 2ASK/BASK二进制振幅键控是一种数字调制技术&#xff0c;其全称是二进制振幅键控&#xff08;Binary Amplitude Shift Keying&#xff09;。该技术通过改变载波的振幅来传递二进制数字信息&#xff0c;而载波的频率和相位则保持不变。以下…

RISC-V (九)抢占式多任务

主要的思想&#xff1a;借用定时器中断实现。设置定时器寄存器&#xff0c;系统自动触发定时器中断时会跳到trap handler这个函数里。借用这个函数做上下文的切换&#xff0c;从而实现了抢占式多任务。 定时器中断&#xff1a;跳到trap handler函数&#xff0c;同时系统自动将…

清华计算几何--凸Polygon的相交问题

凸Polygon和相交定义 本节只讨论凸Polygon的问题&#xff0c;不涉及凹Polygon. 相交包含了边相交和完全包含。 凸Polygon相交的两个问题 Detection(检测) 判断两个凸Polygon是否相交&#xff0c;至于相交部分是什么不关心. Construction(构造) 求出两个凸Polygon具体相交…

Linux_kernel移植rootfs10

一、动态更改内核 1、low level&#xff08;静态修改&#xff09; 【1】将led_drv.c拷贝到kernel/drivers/char/目录中 【2】修改当前目录下的Makefile文件 obj-y led_drv.o #将新添加的驱动文件加入到Makefile文件中 【3】退回kernel目录&#xff0c;执行make uImage …

熬夜后补救措施

人体的肝功能问题 直接体现在体态和容颜上 伤肝 三大坏行为 熬夜后补救 *补充养b族、口、、锌、硒 加强代谢 能力 (1)另外熬夜后一定要多喝水 提升身体代谢能力 (2)谷肤甘肽清肝 肝脏排毒&#xff0c;减轻负拒 (3)水飞前含量高点 &#xff08;4)熬夜出更多油 容易长痘 需要清…

标准库标头 <filesystem> (C++17)学习之文件类型

本篇介绍filesystem文件库的文件类型API。 文件类型 is_block_file (C17) 检查给定的路径是否表示块设备 (函数) is_character_file (C17) 检查给定的路径是否表示字符设备 (函数) is_directory (C17) 检查给定的路径是否表示一个目录 (函数) is_empty (C17) 检查给定的路径是…

STM32G474之使用DAC1和DAC2测试模拟比较器

STM32G474使用DAC1和DAC2的输出作为比较器输入&#xff0c;测试模拟比较器&#xff0c;方法如下&#xff1a; PA1的附加功能为COMP1_INP&#xff0c;无需映射&#xff0c;直接将它配置为模拟功能&#xff0c;就可以使用了。 将COMP1_OUT引脚映射到PA0; 采用DAC2_OUT1输出电压给…

【大疆 SDR 图传 P1 】 功能拆解,通信功能剖析

大疆 SDR 图传 P1 拆解视频P1 SoC1、哲酷2、小米3、大疆&#xff08;文章主角&#xff09; 一、为什么说SDR技术1、sdr 软件无线电2、影视博主的测评方法3、第一个说自己SDR的还是这个老登 二、大疆的图传发展历程1、FPGA AD93632、 P1 自研1、2个DSP和一个CPU A72、音频子系统…

SpringMVC;MVC模式;Spring环境搭建;

一&#xff0c;介绍MVC模式&#xff1a; MVC模式&#xff1a; 1.M:model 模型,业务模型和数据模型. 2.C:controller 控制器 3.V:view 视图 优点: 使用控制器C把视图V和业务模型M分离&#xff0c;从而使同一个程序可以使用不同的表现形式 使用场景: 中大型项目 核心: 控制器 二…