RRT与RRT*算法具体步骤与程序详解(python)

RRT与RRT*算法具体步骤与程序详解(python),第1张

提示:前面写了A*、D

文章目录
  • 前言
  • 一、RRT的原理与步骤
  • 二、RRT算法编写的步骤
    • 1.算法步骤
    • 2.算法的实现
  • 三、所有程序附录与效果展示


前言

RRT和RRT*的区别:

RRT的中文名为快速随机探索树,它的原理很简单,实际上就是维护一棵路径树:从起点开始,在空间中随机采样,并找到路径树上与采样点最接近且能与它无障碍地连接的点,连接这个点与采样点,将采样点加入路径树,直至终点附近区域被探索到。这种方式无法保证得到的路径是最优的。
RRT* 在RRT基础上做了改进,主要是进行了重新选择父节点和重布线的 *** 作。试想在RRT中,我们的采样点最终与整棵树上和它最近的点连了起来,但这未必是最好的选择,我们的最终目的是让这个点与起点的距离尽可能近。RRT* 便对此做了改进,它在采样点加入路径树以后,以其为圆心画了一个小圈,考虑是否有更好的父节点,连到那些节点上能使起点到该点的距离更短(尽管那些节点并不是离采样点最近的点)。如果选择了更加合适的父节点,那么就把它们连接起来,并去除原来的连线(重布线)。


一、RRT的原理与步骤

我的原理启蒙:RRT算法原理图解
根据这篇文章,班门弄斧自己推导一遍这个过程,加强理解:

如图所示,红色的圆是起点,黄色的圆是终点,黑色代表障碍物
RRT的原理如下:

  1. 在空间中随机采样
    如图中的蓝色圆,将其作为目标点
  2. 确定生长树的生长方向
    以刚刚生成的随机点为目标,遍历生长树上的现存节点,计算每个节点到该随机点的距离,筛选出距离最小的节点作为最近点。此时树上仅存在起点(一颗没发芽的种子),所以直接选取起点为最近点。以最近点和随机点的连线为生长方向,如图中红色箭头所示
  3. 向目标点生长
    生长步长是固定的,可由程序决定,但不宜太大也不宜太小,太小的话路径规划时间长,太大则会略过目标点。从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆)
  4. 循环1~2步
    随机采样(蓝色圆形)

    确定生长树的生长方向,图中共有两个点,红色和紫色圆,离目标点(蓝色)最近的是红色点,以最近点和随机点的连线为生长方向,如图中红色箭头所示

    从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆)

    随机采样(蓝色圆形)

    确定生长树的生长方向,以图中离目标点(蓝色)最近的点和随机点的连线为生长方向,如图中红色箭头所示,从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆)

    随机采样(蓝色圆形)

    确定生长树的生长方向,以图中离目标点(蓝色)最近的点和随机点的连线为生长方向,如图中红色箭头所示

    从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆),但是生长点都长障碍物里面去了会发生碰撞,生长失败!

    剔除该生长节点,此次生长作废,不合格,树不接受。

    重复以上的步骤,直到有生长节点进入终点的设定邻域

    不断追溯它们的父节点,可找到一条从起点到终点的安全路径。如图中绿色线所示
二、RRT算法编写的步骤 1.算法步骤
  1. 初始化整个空间,定义初始点、终点、采样点数、点与点之间的步长t等信息
  2. 在空间中随机产生一个点xrand
  3. 在已知树的点集合中找到距离这个随机点最近的点xnear
  4. 在xnear到xrand的直线方向上从xnear以步长t截取点xnew
  5. 判断从xnear到xnew之间是否存在障碍物,若存在则舍弃该点
  6. 将new点加入到树集合中
  7. 循环2~6,循环结束条件:有一个new点在终点的设定邻域内
2.算法的实现
  1. 初始化整个空间,定义初始点、终点、采样点数、点与点之间的步长t等信息
from math import sqrt
import numpy as np
import random
import itertools
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings('ignore')

# 初始化整个空间,定义初始点、终点、采样点数、点与点之间的步长t等信息
x_width = 25  # 空间的长度
y_width = 12  # 空间的宽度
error_list = [[0 for i in range(0, x_width)] for j in range(0, y_width)]
error_list[2][10] = 1
error_list[3][10] = 1
error_list[4][10] = 1
error_list[5][10] = 1
error_list[6][10] = 1
error_list[7][10] = 1
error_list[8][10] = 1

x0 = 6  # 定义初始点的x坐标
y0 = 4  # 定义初始点的y坐标
xn = 17  # 定义终点的x坐标
yn = 5  # 定义终点的y坐标
t = 1  # 点与点之间的步长
error_list[y0][x0] = 4
error_list[yn][xn] = 3
error_list = np.array(error_list)

# print(error_list)
plt.figure()
plt.xlim((-1, x_width))
plt.ylim((-1, y_width))
plt.xlabel('x')
plt.ylabel('y')
plt.xticks(np.arange(x_width))
plt.yticks(np.arange(y_width))
plt.grid()

tree_list = []
tree_list.append([x0, y0, x0, y0])  # 把起点作为树的点放入列表,避免随机点与起点重合
plt.plot(x0, y0, 'ro')
plt.plot(xn, yn, marker='o', color='yellow')
plt.plot([10, 10, 10, 10, 10, 10, 10], [2, 3, 4, 5, 6, 7, 8], 'k-', linewidth='5')

  1. 在空间中随机产生一个点xrand,这个点不能在tree_list里面,构建一个函数
# 在空间中随机产生一个点xrand ->这个点不能是起点
def product_rand(tree_list):
    x_width = 25  # 空间的长度
    y_width = 12  # 空间的宽度
    random_point = list(itertools.product(range(0, x_width), range(0, y_width)))
    xrand = random.sample(random_point, 1)
    xrand = list(xrand[0])  # 将随机点转换成list形式
    tree_list = np.array(tree_list)
    tree = tree_list[:, 0:2]
    while xrand in tree:  # 如果随机点在树的点列表里,重新生成随机点
        xrand = random.sample(random_point, 1)
        xrand = list(xrand[0])  # 将随机点转换成list形式
    return xrand
  1. 在已知树的点集合中找到距离这个随机点最近的点xnear,构建一个函数
# 在已知树的点集合中找到距离这个随机点最近的点xnear
def product_near(tree_list, xrand):
    m = np.inf
    for i in range(0, len(tree_list)):
        if abs(tree_list[i][0] - xrand[0]) + abs(tree_list[i][1] - xrand[1]) < m:
            m = abs(tree_list[i][0] - xrand[0]) + abs(tree_list[i][1] - xrand[1])
            xnear = [tree_list[i][0], tree_list[i][1]]
    return xnear
  1. 确定方向:在xnear到xrand的直线方向上从xnear以步长t截取点xnew,构建一个函数
def decide_direction(xrand, xnear, t):
    z_value = sqrt((xnear[0] - xrand[0]) ** 2 + (xnear[1] - xrand[1]) ** 2)  # 斜边长度
    cos_value = (xrand[0] - xnear[0]) / z_value
    sin_value = (xrand[1] - xnear[1]) / z_value
    xnew = [(xnear[0] + t * cos_value), (xnear[1] + t * sin_value)]
    return xnew
  1. 判断从xnear到xnew之间是否存在障碍物,若存在则舍弃该点
xrand = product_rand(tree_list)  # 随机生成点
xnear = product_near(tree_list, xrand)
xnew = decide_direction(xrand, xnear, t)
if xnear[0] != xrand[0]:
    k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
    y = k * (10 - xnear[0]) + xnear[1]
else:
    y = 0

while 10 <= max(xnear[0], xnew[0]) and 10 <= min(xnear[0], xnew[0]) and 2 <= y <= 8:
    xrand = product_rand(tree_list)  # 随机生成点
    xnear = product_near(tree_list, xrand)
    xnew = decide_direction(xrand, xnear, t)
    if xrand[0] - xnear[0] != 0:
        k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
        y = k * (10 - xnear[0]) + xnear[1]
tree_list.append([xnew[0], xnew[1], xnear[0], xnear[1]])
plt.plot(xrand[0], xrand[1], marker='o', color='cyan')
plt.plot(xnew[0], xnew[1], color='violet', marker='o')
  1. 循环,循环结束条件:有树节点在终点的设定固定邻域之内
# 循环
while ((xnew[0] - xn) ** 2 + (xnew[1] - yn) ** 2) > 1:
    xrand = product_rand(tree_list)  # 随机生成点
    xnear = product_near(tree_list, xrand)
    xnew = decide_direction(xrand, xnear, t)
    if xnear[0] != xrand[0]:
        k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
        y = k * (10 - xnear[0]) + xnear[1]
    else:
        y = 0

    while 10 <= max(xnear[0], xnew[0]) and 10 <= min(xnear[0], xnew[0]) and 2 <= y <= 8:
        xrand = product_rand(tree_list)  # 随机生成点
        xnear = product_near(tree_list, xrand)
        xnew = decide_direction(xrand, xnear, t)
        if xrand[0] - xnear[0] != 0:
            k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
            y = k * (10 - xnear[0]) + xnear[1]
    tree_list.append([xnew[0], xnew[1], xnear[0], xnear[1]])
    plt.plot(xrand[0], xrand[1], marker='o', color='cyan')
    plt.plot(xnew[0], xnew[1], color='violet', marker='o')

  1. 循环以找到父节点,将这些点保存在routine_list列表中,并可视化
tree_list = np.array(tree_list)
routine_list = [[xn,yn]]
n = len(tree_list)-1
x = tree_list[n,0]
y = tree_list[n,1]
f_x = tree_list[n,2]
f_y = tree_list[n,3]
routine_list.append([x,y])
search_list=[]
while [x0,y0] not in routine_list:
    search_list = tree_list[np.where((tree_list[:,0]==f_x) & (tree_list[:,1]==f_y))][0]
    search_list = search_list.tolist()
    routine_list.append([search_list[0],search_list[1]])
    f_x = search_list[2]
    f_y = search_list[3]

print(routine_list)
routine_list = np.array(routine_list)
plt.plot(routine_list[:,0], routine_list[:,1], '-', linewidth='2')
plt.show()

三、所有程序附录与效果展示
from math import sqrt
import numpy as np
import random
import itertools
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings('ignore')

# 初始化整个空间,定义初始点、终点、采样点数、点与点之间的步长t等信息
x_width = 25  # 空间的长度
y_width = 12  # 空间的宽度
error_list = [[0 for i in range(0, x_width)] for j in range(0, y_width)]
error_list[2][10] = 1
error_list[3][10] = 1
error_list[4][10] = 1
error_list[5][10] = 1
error_list[6][10] = 1
error_list[7][10] = 1
error_list[8][10] = 1

x0 = 6  # 定义初始点的x坐标
y0 = 4  # 定义初始点的y坐标
xn = 17  # 定义终点的x坐标
yn = 5  # 定义终点的y坐标
t = 1  # 点与点之间的步长
error_list[y0][x0] = 4
error_list[yn][xn] = 3
error_list = np.array(error_list)

# print(error_list)
plt.figure()
plt.xlim((-1, x_width))
plt.ylim((-1, y_width))
plt.xlabel('x')
plt.ylabel('y')
plt.xticks(np.arange(x_width))
plt.yticks(np.arange(y_width))
plt.grid()

tree_list = []
tree_list.append([x0, y0, x0, y0])  # 把起点作为树的点放入列表,避免随机点与起点重合
plt.plot(x0, y0, 'ro')
plt.plot(xn, yn, marker='o', color='yellow')
plt.plot([10, 10, 10, 10, 10, 10, 10], [2, 3, 4, 5, 6, 7, 8], 'k-', linewidth='5')


# 在空间中随机产生一个点xrand ->这个点不能是起点
def product_rand(tree_list):
    x_width = 25  # 空间的长度
    y_width = 12  # 空间的宽度
    random_point = list(itertools.product(range(0, x_width), range(0, y_width)))
    xrand = random.sample(random_point, 1)
    xrand = list(xrand[0])  # 将随机点转换成list形式
    tree_list = np.array(tree_list)
    tree = tree_list[:, 0:2]
    while xrand in tree:  # 如果随机点在树的点列表里,重新生成随机点
        xrand = random.sample(random_point, 1)
        xrand = list(xrand[0])  # 将随机点转换成list形式
    return xrand


# 在已知树的点集合中找到距离这个随机点最近的点xnear
def product_near(tree_list, xrand):
    m = np.inf
    for i in range(0, len(tree_list)):
        if abs(tree_list[i][0] - xrand[0]) + abs(tree_list[i][1] - xrand[1]) < m:
            m = abs(tree_list[i][0] - xrand[0]) + abs(tree_list[i][1] - xrand[1])
            xnear = [tree_list[i][0], tree_list[i][1]]
    return xnear


# 确定方向:在xnear到xrand的直线方向上从xnear以步长t截取点xnew
# tree_list.append(xrand)
def decide_direction(xrand, xnear, t):
    z_value = sqrt((xnear[0] - xrand[0]) ** 2 + (xnear[1] - xrand[1]) ** 2)  # 斜边长度
    cos_value = (xrand[0] - xnear[0]) / z_value
    sin_value = (xrand[1] - xnear[1]) / z_value
    xnew = [(xnear[0] + t * cos_value), (xnear[1] + t * sin_value)]
    return xnew


# 判断从xnear到xnew之间是否存在障碍物,若存在则舍弃该点
xrand = product_rand(tree_list)  # 随机生成点
xnear = product_near(tree_list, xrand)
xnew = decide_direction(xrand, xnear, t)
if xnear[0] != xrand[0]:
    k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
    y = k * (10 - xnear[0]) + xnear[1]
else:
    y = 0

while 10 <= max(xnear[0], xnew[0]) and 10 <= min(xnear[0], xnew[0]) and 2 <= y <= 8:
    xrand = product_rand(tree_list)  # 随机生成点
    xnear = product_near(tree_list, xrand)
    xnew = decide_direction(xrand, xnear, t)
    if xrand[0] - xnear[0] != 0:
        k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
        y = k * (10 - xnear[0]) + xnear[1]
tree_list.append([xnew[0], xnew[1], xnear[0], xnear[1]])
plt.plot(xrand[0], xrand[1], marker='o', color='cyan')
plt.plot(xnew[0], xnew[1], color='violet', marker='o')

# 循环
while ((xnew[0] - xn) ** 2 + (xnew[1] - yn) ** 2) > 1:
    xrand = product_rand(tree_list)  # 随机生成点
    xnear = product_near(tree_list, xrand)
    xnew = decide_direction(xrand, xnear, t)
    if xnear[0] != xrand[0]:
        k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
        y = k * (10 - xnear[0]) + xnear[1]
    else:
        y = 0

    while 10 <= max(xnear[0], xnew[0]) and 10 <= min(xnear[0], xnew[0]) and 2 <= y <= 8:
        xrand = product_rand(tree_list)  # 随机生成点
        xnear = product_near(tree_list, xrand)
        xnew = decide_direction(xrand, xnear, t)
        if xrand[0] - xnear[0] != 0:
            k = (xrand[1] - xnear[1]) / (xrand[0] - xnear[0])
            y = k * (10 - xnear[0]) + xnear[1]
    tree_list.append([xnew[0], xnew[1], xnear[0], xnear[1]])
    plt.plot(xrand[0], xrand[1], marker='o', color='cyan')
    plt.plot(xnew[0], xnew[1], color='violet', marker='o')

tree_list = np.array(tree_list)
routine_list = [[xn,yn]]
n = len(tree_list)-1
x = tree_list[n,0]
y = tree_list[n,1]
f_x = tree_list[n,2]
f_y = tree_list[n,3]
routine_list.append([x,y])
search_list=[]
while [x0,y0] not in routine_list:
    search_list = tree_list[np.where((tree_list[:,0]==f_x) & (tree_list[:,1]==f_y))][0]
    search_list = search_list.tolist()
    routine_list.append([search_list[0],search_list[1]])
    f_x = search_list[2]
    f_y = search_list[3]

print(routine_list)
routine_list = np.array(routine_list)
plt.plot(routine_list[:,0], routine_list[:,1], '-', linewidth='2')
plt.show()

不停地运行,可以得到不同的路径图

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/789110.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存