提示:前面写了A*、D
前言
RRT和RRT*的区别:
RRT的中文名为快速随机探索树,它的原理很简单,实际上就是维护一棵路径树:从起点开始,在空间中随机采样,并找到路径树上与采样点最接近且能与它无障碍地连接的点,连接这个点与采样点,将采样点加入路径树,直至终点附近区域被探索到。这种方式无法保证得到的路径是最优的。 RRT* 在RRT基础上做了改进,主要是进行了重新选择父节点和重布线的操作。试想在RRT中,我们的采样点最终与整棵树上和它最近的点连了起来,但这未必是最好的选择,我们的最终目的是让这个点与起点的距离尽可能近。RRT* 便对此做了改进,它在采样点加入路径树以后,以其为圆心画了一个小圈,考虑是否有更好的父节点,连到那些节点上能使起点到该点的距离更短(尽管那些节点并不是离采样点最近的点)。如果选择了更加合适的父节点,那么就把它们连接起来,并去除原来的连线(重布线)。
一、RRT的原理与步骤
我的原理启蒙:RRT算法原理图解 根据这篇文章,班门弄斧自己推导一遍这个过程,加强理解:
如图所示,红色的圆是起点,黄色的圆是终点,黑色代表障碍物 RRT的原理如下:
- 在空间中随机采样
如图中的蓝色圆,将其作为目标点 - 确定生长树的生长方向
以刚刚生成的随机点为目标,遍历生长树上的现存节点,计算每个节点到该随机点的距离,筛选出距离最小的节点作为最近点。此时树上仅存在起点(一颗没发芽的种子),所以直接选取起点为最近点。以最近点和随机点的连线为生长方向,如图中红色箭头所示 - 向目标点生长
生长步长是固定的,可由程序决定,但不宜太大也不宜太小,太小的话路径规划时间长,太大则会略过目标点。从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆) - 循环1~2步
随机采样(蓝色圆形) 确定生长树的生长方向,图中共有两个点,红色和紫色圆,离目标点(蓝色)最近的是红色点,以最近点和随机点的连线为生长方向,如图中红色箭头所示 从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆) 随机采样(蓝色圆形) 确定生长树的生长方向,以图中离目标点(蓝色)最近的点和随机点的连线为生长方向,如图中红色箭头所示,从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆) 随机采样(蓝色圆形) 确定生长树的生长方向,以图中离目标点(蓝色)最近的点和随机点的连线为生长方向,如图中红色箭头所示 从此时的最近点也就是起点沿着生长方向生长一个步长得到一个生长点(紫色圆),但是生长点都长障碍物里面去了会发生碰撞,生长失败! 剔除该生长节点,此次生长作废,不合格,树不接受。 重复以上的步骤,直到有生长节点进入终点的设定邻域 不断追溯它们的父节点,可找到一条从起点到终点的安全路径。如图中绿色线所示
二、RRT算法编写的步骤
1.算法步骤
- 初始化整个空间,定义初始点、终点、采样点数、点与点之间的步长t等信息
- 在空间中随机产生一个点xrand
- 在已知树的点集合中找到距离这个随机点最近的点xnear
- 在xnear到xrand的直线方向上从xnear以步长t截取点xnew
- 判断从xnear到xnew之间是否存在障碍物,若存在则舍弃该点
- 将new点加入到树集合中
- 循环2~6,循环结束条件:有一个new点在终点的设定邻域内
2.算法的实现
- 初始化整个空间,定义初始点、终点、采样点数、点与点之间的步长t等信息
from math import sqrt
import numpy as np
import random
import itertools
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
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
y0 = 4
xn = 17
yn = 5
t = 1
error_list[y0][x0] = 4
error_list[yn][xn] = 3
error_list = np.array(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,这个点不能在tree_list里面,构建一个函数
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])
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])
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,构建一个函数
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')
- 循环以找到父节点,将这些点保存在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')
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
y0 = 4
xn = 17
yn = 5
t = 1
error_list[y0][x0] = 4
error_list[yn][xn] = 3
error_list = np.array(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')
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])
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])
return xrand
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
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
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()
不停地运行,可以得到不同的路径图
|