RRT、RRT-connect、RRT*等算法、A*等等路径规划算法

1

原始RRT算法运行结果:python,这里以2D_rrt及其衍生相关算法为例(边做边更新

CV搬运工们,先上github连接:(点个赞呗)(不想要拿github包的后面有现成代码)GitHub - zhm-real/PathPlanning: Common used path planning algorithms with animations.

路径算法的讲解可以看路径规划算法_qq_935160072的博客-优快云博客这篇上放置的B站上up主课程链接

别忘了先阅读README.md,对内容进行简单了解。包含的路径规划算法如下图所示:

那路径规划有什么用呢阿米特的 A* 页面 (stanford.edu)

直接open整个文件包就OK了

在下载文件包后有报错需要修改:

如果发生    from Sampling_based_Planning.rrt_2D import env, plotting, utils
ModuleNotFoundError: No module named 'Sampling_based_Planning'类似的报错。

from Sampling_based_Planning.rrt_2D import env, plotting, utils

将该部分from import 改为

import env
import plotting
import utils

如果NO module  env,plotting....将对应的代码.py文件该env.py放入rrt.py文件相同的文件夹下即可

该代码是在实现路径规划后再进行绘图显示(需要等待几秒)

!!!!!!!!!!!!!!!!!!!!!!!!!!

必须包含3个.py文件 env,plotting,utils分别包含(障碍物,绘图,碰撞检测)

同样我也贴出来:

env.py:


class Env:
    def __init__(self):
        self.x_range = (0, 50)
        self.y_range = (0, 30)
        self.obs_boundary = self.obs_boundary()
        self.obs_circle = self.obs_circle()
        self.obs_rectangle = self.obs_rectangle()

    @staticmethod
    def obs_boundary():
        obs_boundary = [
            [0, 0, 1, 30],
            [0, 30, 50, 1],
            [1, 0, 50, 1],
            [50, 1, 1, 30]
        ]
        return obs_boundary

    @staticmethod
    def obs_rectangle():
        obs_rectangle = [
            [14, 12, 8, 2],
            [18, 22, 8, 3],
            [26, 7, 2, 12],
            [32, 14, 10, 2]
        ]
        return obs_rectangle

    @staticmethod
    def obs_circle():
        obs_cir = [
            [7, 12, 3],
            [46, 20, 2],
            [15, 5, 2],
            [37, 7, 3],
            [37, 23, 3],
            #[20, 8, 3],
            #[31, 20, 3]
        ]

        return obs_cir

plotting:


import matplotlib.pyplot as plt
import matplotlib.patches as patches
import os
import sys

sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
                "/../../Sampling_based_Planning/")

import env


class Plotting:
    def __init__(self, x_start, x_goal):
        self.xI, self.xG = x_start, x_goal
        self.env = env.Env()
        self.obs_bound = self.env.obs_boundary
        self.obs_circle = self.env.obs_circle
        self.obs_rectangle = self.env.obs_rectangle

    def animation(self, nodelist, path, name, animation=False):
        self.plot_grid(name)
        self.plot_visited(nodelist, animation)
        self.plot_path(path)

    def animation_connect(self, V1, V2, path, name):
        self.plot_grid(name)
        self.plot_visited_connect(V1, V2)
        self.plot_path(path)

    def plot_grid(self, name):
        fig, ax = plt.subplots()

        for (ox, oy, w, h) in self.obs_bound:
            ax.add_patch(
                patches.Rectangle(
                    (ox, oy), w, h,
                    edgecolor='black',
                    facecolor='black',
                    fill=True
                )
            )

        for (ox, oy, w, h) in self.obs_rectangle:
            ax.add_patch(
                patches.Rectangle(
                    (ox, oy), w, h,
                    edgecolor='black',
                    facecolor='gray',
                    fill=True
                )
            )

        for (ox, oy, r) in self.obs_circle:
            ax.add_patch(
                patches.Circle(
                    (ox, oy), r,
                    edgecolor='black',
                    facecolor='gray',
                    fill=True
                )
            )

        plt.plot(self.xI[0], self.xI[1], "bs", linewidth=3)
        plt.plot(self.xG[0], self.xG[1], "gs", linewidth=3)

        plt.title(name)
        plt.axis("equal")

    @staticmethod
    def plot_visited(nodelist, animation):
        if animation:
            count = 0
            for node in nodelist:
                count += 1
                if node.parent:
                    plt.plot([node.parent.x, node.x], [node.parent.y, node.y], "-g")
                    plt.gcf().canvas.mpl_connect('key_release_event',
                                                 lambda event:
                                                 [exit(0) if event.key == 'escape' else None])
                    if count % 10 == 0:
                        plt.pause(0.001)
        else:
            for node in nodelist:
                if node.parent:
                    plt.plot([node.parent.x, node.x], [node.parent.y, node.y], "-g")

    @staticmethod
    def plot_visited_connect(V1, V2):
        len1, len2 = len(V1), len(V2)

        for k in range(max(len1, len2)):
            if k < len1:
                if V1[k].parent:
                    plt.plot([V1[k].x, V1[k].parent.x], [V1[k].y, V1[k].parent.y], "-g")
            if k < len2:
                if V2[k].parent:
                    plt.plot([V2[k].x, V2[k].parent.x], [V2[k].y, V2[k].parent.y], "-g")

            plt.gcf().canvas.mpl_connect('key_release_event',
                                         lambda event: [exit(0) if event.key == 'escape' else None])

            if k % 2 == 0:
                plt.pause(0.001)

        plt.pause(0.01)

    @staticmethod
    def plot_path(path):
        if len(path) != 0:
            plt.plot([x[0] for x in path], [x[1] for x in path], '-r', linewidth=2)
            plt.pause(0.01)
        plt.show()

utils.py:


import math
import numpy as np
import os
import sys

sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
                "/../../Sampling_based_Planning/")

import env

class Node:
    def __init__(self, n):
        self.x = n[0]
        self.y = n[1]
        self.parent = None


class Utils:
    def __init__(self):
        self.env = env.Env()                             #初始化环境信息

        self.delta = 0.5
        self.obs_circle = self.env.obs_circle
        self.obs_rectangle = self.env.obs_rectangle
        self.obs_boundary = self.env.obs_boundary

    def update_obs(self, obs_cir, obs_bound, obs_rec):   #更新环境信息
        self.obs_circle = obs_cir
        self.obs_boundary = obs_bound
        self.obs_rectangle = obs_rec

    def get_obs_vertex(self):                            #获取障碍物点
        delta = self.delta
        obs_list = []                                    #障碍物列表

        for (ox, oy, w, h) in self.obs_rectangle:
            vertex_list = [[ox - delta, oy - delta],
                           [ox + w + delta, oy - delta],
                           [ox + w + delta, oy + h + delta],
                           [ox - delta, oy + h + delta]]
            obs_list.append(vertex_list)

        return obs_list

    def is_intersect_rec(self, start, end, o, d, a, b):
        v1 = [o[0] - a[0], o[1] - a[1]]                #v1=o和a的xy坐标差
        v2 = [b[0] - a[0], b[1] - a[1]]                #v2=b和a的xy坐标差
        v3 = [-d[1], d[0]]

        div = np.dot(v2, v3)                           #v2, v3点乘

        if div == 0:                                   #点乘等于0表示向量垂直
            return False

        t1 = np.linalg.norm(np.cross(v2, v1)) / div
        t2 = np.dot(v1, v3) / div

        if t1 >= 0 and 0 <= t2 <= 1:
            shot = Node((o[0] + t1 * d[0], o[1] + t1 * d[1]))
            dist_obs = self.get_dist(start, shot)
            dist_seg = self.get_dist(start, end)
            if dist_obs <= dist_seg:
                return True

        return False

    def is_intersect_circle(self, o, d, a, r):
        d2 = np.dot(d, d)
        delta = self.delta

        if d2 == 0:
            return False

        t = np.dot([a[0] - o[0], a[1] - o[1]], d) / d2

        if 0 <= t <= 1:
            shot = Node((o[0] + t * d[0], o[1] + t * d[1]))
            if self.get_dist(shot, Node(a)) <= r + delta:
                return True

        return False

    def is_collision(self, start, end):
        if self.is_inside_obs(start) or self.is_inside_obs(end):
            return True

        o, d = self.get_ray(start, end)                             #o, d为起点和终点
        obs_vertex = self.get_obs_vertex()                          #获取更新的障碍物

        for (v1, v2, v3, v4) in obs_vertex:                         #
            if self.is_intersect_rec(start, end, o, d, v1, v2):
                return True
            if self.is_intersect_rec(start, end, o, d, v2, v3):
                return True
            if self.is_intersect_rec(start, end, o, d, v3, v4):
                return True
            if self.is_intersect_rec(start, end, o, d, v4, v1):
                return True

        for (x, y, r) in self.obs_circle:
            if self.is_intersect_circle(o, d, [x, y], r):
                return True

        return False



    #通过改变避障方式,增加判断当发生碰撞时改变扩展方向进行障碍物的避绕






    def is_inside_obs(self, node):                                  #在障碍物中的数据信息,
        delta = self.delta

        for (x, y, r) in self.obs_circle:                           #圆形障碍物
            if math.hypot(node.x - x, node.y - y) <= r + delta:
                return True

        for (x, y, w, h) in self.obs_rectangle:                     #矩形障碍物
            if 0 <= node.x - (x - delta) <= w + 2 * delta \
                    and 0 <= node.y - (y - delta) <= h + 2 * delta:
                return True

        for (x, y, w, h) in self.obs_boundary:                      #边界障碍物
            if 0 <= node.x - (x - delta) <= w + 2 * delta \
                    and 0 <= node.y - (y - delta) <= h + 2 * delta:
                return True

        return False

    @staticmethod
    def get_ray(start, end):
        orig = [start.x, start.y]
        direc = [end.x - start.x, end.y - start.y]            #终点-起始点得到生长方向
        return orig, direc

    @staticmethod
    def get_dist(start, end):
        return math.hypot(end.x - start.x, end.y - start.y)     #两点间的距离

RRT代码介绍连接:(14条消息) RRT算法简介_魂淡1994的博客-优快云博客

仿真结果如下:

具体代码已经贴出:注释自己写的可能有小错误,可以帮忙指出


import os
import sys
import math
import time
import random
import numpy as np

sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
                "/../../Sampling_based_Planning/")

import env            #障碍物图
import plotting       #画图
import utils


class Node:
    def __init__(self, n):
        self.x = n[0]
        self.y = n[1]
        self.parent = None


class Rrt:
    def __init__(self, s_start, s_goal, step_len, goal_sample_rate, iter_max):
        self.s_start = Node(s_start)
        self.s_goal = Node(s_goal)
        self.step_len = step_len
        self.goal_sample_rate = goal_sample_rate
        self.iter_max = iter_max
        self.vertex = [self.s_start]

        self.env = env.Env()
        self.plotting = plotting.Plotting(s_start, s_goal)
        self.utils = utils.Utils()

        self.x_range = self.env.x_range
        self.y_range = self.env.y_range
        self.obs_circle = self.env.obs_circle
        self.obs_rectangle = self.env.obs_rectangle
        self.obs_boundary = self.env.obs_boundary
        self.iterations = 0

    def planning(self):
        for i in range(self.iter_max):
            node_rand = self.generate_random_node(self.goal_sample_rate)           #随机生成的节点
            node_near = self.nearest_neighbor(self.vertex, node_rand)              #最近的节点
            node_new = self.new_state(node_near, node_rand)                        #新节点

            """
            ######################节点重选择部分
            node_vector = np
            v_1 = (node_new[0]-node_near[0], node_new[1]-node_near[1])
            v_2 = ()



            ######################节点重选择部分
            """
            
            self.iterations += 1
            time.sleep(0.001)

            if node_new and not self.utils.is_collision(node_near, node_new):
                self.vertex.append(node_new)
                dist, _ = self.get_distance_and_angle(node_new, self.s_goal)

                if dist <= self.step_len and not self.utils.is_collision(node_new, self.s_goal):
                    self.new_state(node_new, self.s_goal)
                    return self.extract_path(node_new)
        return None

    def generate_random_node(self, goal_sample_rate):
        delta = self.utils.delta

        if random.randint(0, 100) > goal_sample_rate:
            return Node((np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta),
                         np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)))

        return self.s_goal

    @staticmethod
    def nearest_neighbor(node_list, n):
        return node_list[int(np.argmin([math.hypot(nd.x - n.x, nd.y - n.y)
                                        for nd in node_list]))]

    def new_state(self, node_start, node_end):
        dist, theta = self.get_distance_and_angle(node_start, node_end)

        dist = min(self.step_len, dist)
        node_new = Node((node_start.x + dist * math.cos(theta),
                         node_start.y + dist * math.sin(theta)))
        node_new.parent = node_start
        #a = math.tan(theta)                                                 #根据两点计算角度的弧度
        #k = -1/a                                                            #随机向量垂直的方向
        #print(k)

        #print(a)

        return node_new

    def extract_path(self, node_end):
        path = [(self.s_goal.x, self.s_goal.y)]
        node_now = node_end

        while node_now.parent is not None:
            node_now = node_now.parent
            path.append((node_now.x, node_now.y))

        return path

    @staticmethod
    def get_distance_and_angle(node_start, node_end):
        dx = node_end.x - node_start.x
        dy = node_end.y - node_start.y
        return math.hypot(dx, dy), math.atan2(dy, dx)


def main():
    start_time = time.time()  # 规划时间
    x_start = (2, 2)  # Starting node
    x_goal = (49, 24)  # Goal node

    rrt = Rrt(x_start, x_goal, 0.5, 0, 10000)  #起点,目标点,步长,随机概率,最大迭代次数
    path = rrt.planning()
    print((time.time() - start_time))
    print(f"迭代次数为: {rrt.iterations}")
    #print(f"Path length: {path_length}")

    if path:
        rrt.plotting.animation(rrt.vertex, path, "RRT", True)
        count = 0
        for i in path:
            count += 1
        print("距离长度为:" + str(count) + "mm")                     #路径有问题
    else:
        print("No Path Found!")


if __name__ == '__main__':
    main()

RRT算法加入目标偏置概率(random()函数,大于设置值取目标点,小于则取随机生成的点)后随机性明显变小(过大过小均不合适),,,修改注释代表的随机概率即可

def main():
    start_time = time.time()  # 规划时间
    x_start = (2, 2)  # Starting node
    x_goal = (49, 24)  # Goal node

    rrt = Rrt(x_start, x_goal, 0.5, 0, 10000)  #起点,目标点,步长,随机概率,最大迭代次数
    path = rrt.planning()
    print((time.time() - start_time))
    print(f"迭代次数为: {rrt.iterations}")
    #print(f"Path length: {path_length}")

    if path:
        rrt.plotting.animation(rrt.vertex, path, "RRT", True)
        count = 0
        for i in path:
            count += 1
        print("距离长度为:" + str(count) + "mm")                     #路径有问题
    else:
        print("No Path Found!")


if __name__ == '__main__':
    main()

RRT-connect算法采用双向搜索树交替进行搜索(包括目标偏置和贪婪算法)原理介绍链接:(14条消息) RRT-connect算法__yuan_的博客-优快云博客

代码如下(同样贪婪算法部分也标注出来了):



import os
import sys
import math
import copy
import random
import time
import numpy as np
import matplotlib.pyplot as plt

sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
                "/../../Sampling_based_Planning/")

import env
import plotting
import utils


class Node:                             #定义一个节点
    def __init__(self, n):
        self.x = n[0]
        self.y = n[1]
        self.parent = None


class RrtConnect:
    def __init__(self, s_start, s_goal, step_len, goal_sample_rate, iter_max):
        self.s_start = Node(s_start)
        self.s_goal = Node(s_goal)
        self.step_len = step_len
        self.goal_sample_rate = goal_sample_rate
        self.iter_max = iter_max
        self.V1 = [self.s_start]
        self.V2 = [self.s_goal]

        self.env = env.Env()
        self.plotting = plotting.Plotting(s_start, s_goal)
        self.utils = utils.Utils()

        self.x_range = self.env.x_range
        self.y_range = self.env.y_range
        self.obs_circle = self.env.obs_circle         #更新圆形障碍物
        self.obs_rectangle = self.env.obs_rectangle   #更新矩形障碍物
        self.obs_boundary = self.env.obs_boundary     #更新地图边界
        self.iterations = 0                           #初始化迭代次数为0

    def planning(self):                                                                  #定义函数获取路径

        for i in range(self.iter_max):
            node_rand = self.generate_random_node(self.s_goal, self.goal_sample_rate)    #随机点=产生目标点和目标概率
            node_near = self.nearest_neighbor(self.V1, node_rand)                        #最近的点与随机点的V1距离
            node_new = self.new_state(node_near, node_rand)                              #new_state()函数返回新节点
            self.iterations += 1                                                         #迭代次数+1
            time.sleep(0.001)
            if node_new and not self.utils.is_collision(node_near, node_new):            #utils.py文件中进行碰撞检测
                self.V1.append(node_new)                                                 #无碰撞后将新节点加入(V1)中
                node_near_prim = self.nearest_neighbor(self.V2, node_new)                #返回最近节点赋值给node_near_prim(根据最近节点获取方向,得到下面的)
                node_new_prim = self.new_state(node_near_prim, node_new)                 #将新生成的节点赋值给node_new_prim
                """
            ######################贪婪算法部分

                if node_new_prim and not self.utils.is_collision(node_new_prim, node_near_prim):  #如果新节点也不发生碰撞(新生成的节点,最近的节点)
                    #self.V2.append(node_new_prim)                                                #将新生成的节点加入V2

                    #while True:                                                                  #发生碰撞则进行下列操作
                        #node_new_prim2 = self.new_state(node_new_prim, node_new)                 #因为第一棵树碰撞,与第二棵树交换进行
                        #if node_new_prim2 and not self.utils.is_collision(node_new_prim2, node_new_prim):   #如果与第二棵树没发生碰撞(第二棵树的节点,新生成的节点)
                            #self.V2.append(node_new_prim2)                                       #然后将该节点加入V2中
                            #node_new_prim = self.change_node(node_new_prim, node_new_prim2)      #交换节点后赋值为新节点
                        #else:
                            #break

                        #if self.is_node_same(node_new_prim, node_new):
                            #break
                            
            #######################贪婪算法部分
                """

                if self.is_node_same(node_new_prim, node_new):                                   #is_node_same函数判断新节点是不是目标点
                    return self.extract_path(node_new, node_new_prim)                            #返回路径

            if len(self.V2) < len(self.V1):                                                      #对比第一棵树和第二棵树的长度,平衡随机树长度,交换
                list_mid = self.V2
                self.V2 = self.V1
                self.V1 = list_mid

            """判断偶数进行树扩展的交换
            if i % 2 == 0:                                                                    
                list_mid = self.V2
                self.V2 = self.V1
                self.V1 = list_mid
            """

        return None

    @staticmethod
    def change_node(node_new_prim, node_new_prim2):                        #交换节点
        node_new = Node((node_new_prim2.x, node_new_prim2.y))              #将第二课树的节点赋值为新节点
        node_new.parent = node_new_prim                                    #将node_new_prim赋值给父节点

        return node_new

    @staticmethod
    def is_node_same(node_new_prim, node_new):                             #如果新节点是目标点,则返回True
        if node_new_prim.x == node_new.x and \
                node_new_prim.y == node_new.y:
            return True

        return False

    def generate_random_node(self, sample_goal, goal_sample_rate):         #随机生成数大于目标概率则生成随机点,否则去目标点作为随机点
        delta = self.utils.delta

        if random.randint(0, 100) > goal_sample_rate:
            return Node((np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta),
                         np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)))

        return sample_goal

    @staticmethod
    def nearest_neighbor(node_list, n):                                    #从节点列表中找到最近节点,并返回
        return node_list[int(np.argmin([math.hypot(nd.x - n.x, nd.y - n.y) #返回最近的节点
                                        for nd in node_list]))]

    def new_state(self, node_start, node_end):                             #函数获得新节点扩展的位置
        dist, theta = self.get_distance_and_angle(node_start, node_end)    #获得了距离,角度

        dist = min(self.step_len, dist)
        node_new = Node((node_start.x + dist * math.cos(theta),
                         node_start.y + dist * math.sin(theta)))
        node_new.parent = node_start                                       #将父节点作为起点



        print(theta)                                                       #(theta)<0代表向下,>0代表向下


        return node_new                                                    #返回新节点位置

    @staticmethod
    def extract_path(node_new, node_new_prim):                             #获得生成的路径(path1 + path2)
        path1 = [(node_new.x, node_new.y)]
        node_now = node_new

        while node_now.parent is not None:
            node_now = node_now.parent
            path1.append((node_now.x, node_now.y))

        path2 = [(node_new_prim.x, node_new_prim.y)]
        node_now = node_new_prim

        while node_now.parent is not None:
            node_now = node_now.parent
            path2.append((node_now.x, node_now.y))

        return list(list(reversed(path1)) + path2)

    @staticmethod
    def get_distance_and_angle(node_start, node_end):       #根据开始的节点和最后的节点获取距离和角度
        dx = node_end.x - node_start.x
        dy = node_end.y - node_start.y
        return math.hypot(dx, dy), math.atan2(dy, dx)       #hypot()函数计算两点间的距离



def main():
    start_time = time.time()                                 # 规划时间
    x_start = (2, 2)                                         # 起始节点
    x_goal = (49, 24)                                        # 最终节点

    rrt_connect = RrtConnect(x_start, x_goal, 0.5, 0, 5000)  #起点,目标点,步长,随机概率,最大迭代次数
    path = rrt_connect.planning()
    print((time.time() - start_time))
    print(f"迭代次数为: {rrt_connect.iterations}")


    rrt_connect.plotting.animation_connect(rrt_connect.V1, rrt_connect.V2, path, "RRT_CONNECT")


if __name__ == '__main__':
    main()

将贪婪算法部分注释掉后的运行结果(为了方便阅读,将全文注释了一遍,但是有些部分目前还没看懂)

RRT*是渐进优化算法(等待时间较长)

代码如下:
 

"""
RRT_star 2D
@author: huiming zhou
"""

import os
import sys
import math
import time
import numpy as np

sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
                "/../../Sampling_based_Planning/")

import env
import plotting
import utils
import queue


class Node:
    def __init__(self, n):
        self.x = n[0]
        self.y = n[1]
        self.parent = None


class RrtStar:
    def __init__(self, x_start, x_goal, step_len,
                 goal_sample_rate, search_radius, iter_max):
        self.s_start = Node(x_start)
        self.s_goal = Node(x_goal)
        self.step_len = step_len
        self.goal_sample_rate = goal_sample_rate
        self.search_radius = search_radius
        self.iter_max = iter_max
        self.vertex = [self.s_start]
        self.path = []

        self.env = env.Env()
        self.plotting = plotting.Plotting(x_start, x_goal)
        self.utils = utils.Utils()

        self.x_range = self.env.x_range
        self.y_range = self.env.y_range
        self.obs_circle = self.env.obs_circle
        self.obs_rectangle = self.env.obs_rectangle
        self.obs_boundary = self.env.obs_boundary
        self.iterations = 0

    def planning(self):
        for k in range(self.iter_max):
            node_rand = self.generate_random_node(self.goal_sample_rate)
            node_near = self.nearest_neighbor(self.vertex, node_rand)
            node_new = self.new_state(node_near, node_rand)
            self.iterations += 1
            time.sleep(0.001)

            if k % 500 == 0:
                print(k)

            if node_new and not self.utils.is_collision(node_near, node_new):
                neighbor_index = self.find_near_neighbor(node_new)
                self.vertex.append(node_new)

                if neighbor_index:
                    self.choose_parent(node_new, neighbor_index)
                    self.rewire(node_new, neighbor_index)

        index = self.search_goal_parent()
        self.path = self.extract_path(self.vertex[index])

        self.plotting.animation(self.vertex, self.path, "rrt*, N = " + str(self.iter_max))

    def new_state(self, node_start, node_goal):
        dist, theta = self.get_distance_and_angle(node_start, node_goal)

        dist = min(self.step_len, dist)
        node_new = Node((node_start.x + dist * math.cos(theta),
                         node_start.y + dist * math.sin(theta)))

        node_new.parent = node_start

        return node_new

    def choose_parent(self, node_new, neighbor_index):
        cost = [self.get_new_cost(self.vertex[i], node_new) for i in neighbor_index]

        cost_min_index = neighbor_index[int(np.argmin(cost))]
        node_new.parent = self.vertex[cost_min_index]

    def rewire(self, node_new, neighbor_index):
        for i in neighbor_index:
            node_neighbor = self.vertex[i]

            if self.cost(node_neighbor) > self.get_new_cost(node_new, node_neighbor):
                node_neighbor.parent = node_new

    def search_goal_parent(self):
        dist_list = [math.hypot(n.x - self.s_goal.x, n.y - self.s_goal.y) for n in self.vertex]
        node_index = [i for i in range(len(dist_list)) if dist_list[i] <= self.step_len]

        if len(node_index) > 0:
            cost_list = [dist_list[i] + self.cost(self.vertex[i]) for i in node_index
                         if not self.utils.is_collision(self.vertex[i], self.s_goal)]
            return node_index[int(np.argmin(cost_list))]

        return len(self.vertex) - 1

    def get_new_cost(self, node_start, node_end):
        dist, _ = self.get_distance_and_angle(node_start, node_end)

        return self.cost(node_start) + dist

    def generate_random_node(self, goal_sample_rate):
        delta = self.utils.delta

        if np.random.random() > goal_sample_rate:
            return Node((np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta),
                         np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)))

        return self.s_goal

    def find_near_neighbor(self, node_new):
        n = len(self.vertex) + 1
        r = min(self.search_radius * math.sqrt((math.log(n) / n)), self.step_len)

        dist_table = [math.hypot(nd.x - node_new.x, nd.y - node_new.y) for nd in self.vertex]
        dist_table_index = [ind for ind in range(len(dist_table)) if dist_table[ind] <= r and
                            not self.utils.is_collision(node_new, self.vertex[ind])]

        return dist_table_index

    @staticmethod
    def nearest_neighbor(node_list, n):
        return node_list[int(np.argmin([math.hypot(nd.x - n.x, nd.y - n.y)
                                        for nd in node_list]))]

    @staticmethod
    def cost(node_p):
        node = node_p
        cost = 0.0

        while node.parent:
            cost += math.hypot(node.x - node.parent.x, node.y - node.parent.y)
            node = node.parent

        return cost

    def update_cost(self, parent_node):
        OPEN = queue.QueueFIFO()
        OPEN.put(parent_node)

        while not OPEN.empty():
            node = OPEN.get()

            if len(node.child) == 0:
                continue

            for node_c in node.child:
                node_c.Cost = self.get_new_cost(node, node_c)
                OPEN.put(node_c)

    def extract_path(self, node_end):
        path = [[self.s_goal.x, self.s_goal.y]]
        node = node_end

        while node.parent is not None:
            path.append([node.x, node.y])
            node = node.parent
        path.append([node.x, node.y])

        return path

    @staticmethod
    def get_distance_and_angle(node_start, node_end):
        dx = node_end.x - node_start.x
        dy = node_end.y - node_start.y
        return math.hypot(dx, dy), math.atan2(dy, dx)


def main():
    start_time = time.time()  # 规划时间
    x_start = (2, 2)  # Starting node
    x_goal = (49, 24)  # Goal node

    rrt_star = RrtStar(x_start, x_goal, 1, 0, 20, 10000)
    rrt_star.planning()
    print((time.time() - start_time))
    print(f"迭代次数为: {rrt_star.iterations}")


if __name__ == '__main__':
    main()

 这三种算法的介绍连接如下        :(12条消息) RRT、RRT_Connect、RRT*_-点灯-的博客-优快云博客_rrt-connect

以下是双向RRT算法Python代码示例: ```python import random import math import matplotlib.pyplot as plt class RRTNode: def __init__(self, x, y): self.x = x self.y = y self.parent = None class BiRRT: def __init__(self, start, goal, obstacle_list, rand_area, expand_dist=0.5, goal_sample_rate=20, max_iter=500): self.start_node = RRTNode(start[0], start[1]) self.goal_node = RRTNode(goal[0], goal[1]) self.obstacle_list = obstacle_list self.min_rand = rand_area[0] self.max_rand = rand_area[1] self.expand_dist = expand_dist self.goal_sample_rate = goal_sample_rate self.max_iter = max_iter self.node_list1 = [self.start_node] self.node_list2 = [self.goal_node] self.path = [] def planning(self): for i in range(self.max_iter): if random.randint(0, 100) > self.goal_sample_rate: rnd = self.get_random_node() else: rnd = self.goal_node nearest_node1 = self.nearest_node(self.node_list1, rnd) nearest_node2 = self.nearest_node(self.node_list2, rnd) new_node1 = self.steer(nearest_node1, rnd, self.expand_dist) new_node2 = self.steer(nearest_node2, rnd, self.expand_dist) if self.check_collision(new_node1) and self.check_collision(new_node2): self.node_list1.append(new_node1) self.node_list2.append(new_node2) self.connect(new_node1, new_node2) if self.calc_dist(new_node1, self.goal_node) < self.expand_dist: final_node = self.steer(new_node1, self.goal_node, self.expand_dist) if self.check_collision(final_node): self.path = self.get_path(final_node) return self.path self.node_list1, self.node_list2 = self.node_list2, self.node_list1 def steer(self, from_node, to_node, extend_length=float("inf")): new_node = RRTNode(from_node.x, from_node.y) dist, angle = self.calc_distance_and_angle(new_node, to_node) if dist < extend_length: extend_length = dist new_node.x += extend_length * math.cos(angle) new_node.y += extend_length * math.sin(angle) new_node.parent = from_node return new_node def connect(self, from_node, to_node): from_node.parent = to_node def get_path(self, node): path = [[node.x, node.y]] while node.parent: node = node.parent path.append([node.x, node.y]) return path def nearest_node(self, node_list, node): nearest_node = node_list[0] for n in node_list: if self.calc_dist(n, node) < self.calc_dist(nearest_node, node): nearest_node = n return nearest_node def calc_dist(self, from_node, to_node): return math.sqrt((from_node.x - to_node.x) ** 2 + (from_node.y - to_node.y) ** 2) def calc_distance_and_angle(self, from_node, to_node): dx = to_node.x - from_node.x dy = to_node.y - from_node.y dist = math.sqrt(dx ** 2 + dy ** 2) angle = math.atan2(dy, dx) return dist, angle def check_collision(self, node): for (ox, oy, size) in self.obstacle_list: if math.sqrt((node.x - ox) ** 2 + (node.y - oy) ** 2) <= size: return False return True def get_random_node(self): if random.randint(0, 100) > self.goal_sample_rate: rnd = RRTNode(random.uniform(self.min_rand, self.max_rand), random.uniform(self.min_rand, self.max_rand)) else: rnd = self.goal_node return rnd def plot_path(self): plt.plot([x for (x, y) in self.path], [y for (x, y) in self.path], '-r') for (ox, oy, size) in obstacleList: circle = plt.Circle((ox, oy), size, color='b') plt.gcf().gca().add_artist(circle) plt.plot(self.start_node.x, self.start_node.y, 'xr') plt.plot(self.goal_node.x, self.goal_node.y, 'xr') plt.axis('equal') plt.show() if __name__ == '__main__': obstacleList = [(5, 5, 1), (3, 6, 2), (3, 8, 2), (5, 10, 2), (7, 9, 2), (9, 10, 2)] start = [0.0, 0.0] goal = [10.0, 10.0] rrt = BiRRT(start, goal, obstacleList, [-2, 12]) path = rrt.planning() if path: print(path) rrt.plot_path() else: print("Cannot find path!") ``` 请注意,此示例仅用于演示双向RRT算法,并且可能需要根据您的具体需求进行修改。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值