7.2 RRT算法的定义与实现
RRT算法通过随机采样和树结构迭代地探索搜索空间,直到找到连接起点和目标点的路径。算法不断生成新节点,并将其连接到最近邻节点,直到达到最大迭代次数或找到路径。最终,从树中提取路径作为解。
7.2.1 RRT算法的实现步骤
实现RRT算法的基本步骤如下所示。
(1)初始化:将起点添加到搜索树中作为唯一节点。
(2)循环:在搜索树中不断迭代,直到找到目标点或达到最大迭代次数。
- 采样:在自由空间中随机采样一个点作为新的探索点。
- 最近邻搜索:在搜索树中找到与新采样点最近的节点。
- 扩展:从最近邻节点向采样点之间的直线路径上进行一步扩展,并检查是否碰撞了障碍物。
- 连接:如果扩展路径是无碰撞的,则将新的节点添加到搜索树中,并将连接它的边添加到树中。
- 目标检测:检查新添加的节点是否足够接近目标点,如果是,则算法终止。
(3)路径提取:当算法终止时,从搜索树中提取从起点到目标点的路径。
7.2.2 原始的RRT算法
“原始的 RRT 算法”指的是最初提出的、最基本版本的 RRT(Rapidly-exploring Random Tree)算法。这个版本是由 Steven M. LaValle 在他的论文 "Rapidly-exploring Random Trees: A New Tool for Path Planning" 中提出的。原始的 RRT 算法是用于路径规划的一种基本方法,其核心思想是通过随机采样和树结构迭代地探索搜索空间,直到找到连接起点和目标点的路径。在算法的每次迭代中,随机生成一个点并通过扩展树来探索新的空间区域,以此逐步构建一棵树。通过这种方式,RRT 算法能够在自由空间中快速生成路径,并且在有限时间内收敛到一条可行路径。
原始的 RRT 算法包括两个关键部分:算法主体和 Extend 函数,具体说明如下所示。
1. RRT算法主体
算法主体通过初始化顶点和边集,然后在迭代过程中不断扩展树,直到达到指定的迭代次数。下面是RRT 算法主体部分的伪代码。
下面详细介绍每一步骤:
2. Extend 函数
Extend 函数是主体的一部分,它负责从采样到的点开始扩展树。下面是RRT 算法Extend 函数部分的伪代码。
下面详细介绍每一步骤:
从上述算法的实现过程中可以看出,RRT 的扩展能够趋向于位姿空间中没有扩展到的部分。这就决定了RRT 一开始能够快速的进行扩展,而且能够形成对空间的全面覆盖。RRT 顶点是分配在位姿空间中是一致均匀的,如果路径存在,在顶点数目一定的条件下是肯定可以找到一条路径的。当然 RRT 算法也有一些缺点,它是一种纯粹的随机搜索算法对环境类型不敏感,当 C 中包含大量障碍物和狭窄通道约束时,算法的收敛速度慢,效率会大幅下降。为了加快随机树到达目标点的速度,简单的改进方法是:在随机树每次的生长过程中,根据随机概率(0.0到1.0 的随机值 p)来选择生长方向是目标点还是随机点。
例如下面的例子实现了基本的RRT算法,在这个例子中,主要的RRT算法实现在 main 函数的for 循环中。在每次迭代中,都会随机采样一个点 q_rand,然后找到树中最接近该点的节点 q_nearest,并使用 extend 函数将该随机点扩展到树中。最后,将扩展后的节点加入树中。
实例7-1:使用原始的RRT算法寻找路径(codes/7/yuan.py)
实例文件yuan.py的具体实现代码如下所示。
import math
import random
import matplotlib.pyplot as plt
# 定义节点类
class Node:
def __init__(self, x, y):
self.x = x
self.y = y
# 计算两个节点之间的距离
def distance(n1, n2):
return math.sqrt((n1.x - n2.x)**2 + (n1.y - n2.y)**2)
# 扩展函数
def extend(nearest, rand, max_distance):
d = distance(nearest, rand)
if d <= max_distance:
return rand
else:
theta = math.atan2(rand.y - nearest.y, rand.x - nearest.x)
x = nearest.x + max_distance * math.cos(theta)
y = nearest.y + max_distance * math.sin(theta)
return Node(x, y)
# 主函数
def main():
q_init = Node(0, 0) # 起始点
q_goal = Node(10, 10) # 目标点
V = [q_init] # 存储节点的集合
iterations = 100 # 迭代次数
max_distance = 1.0 # 最大扩展距离
for i in range(iterations):
# 采样随机点
q_rand = Node(random.uniform(0, 100), random.uniform(0, 100))
# 找到距离随机点最近的节点
q_nearest = V[0]
for node in V:
if distance(node, q_rand) < distance(q_nearest, q_rand):
q_nearest = node
# 扩展树
q_new = extend(q_nearest, q_rand, max_distance)
V.append(q_new)
# 输出节点集合
print("Nodes:")
for node in V:
print("(", node.x, ",", node.y, ")", end=" ")
print()
# 绘制节点和路径
plt.figure(figsize=(8, 8))
plt.plot([node.x for node in V], [node.y for node in V], 'bo', markersize=3) # 绘制节点
plt.plot([q_init.x, q_goal.x], [q_init.y, q_goal.y], 'r-') # 绘制起点和终点之间的路径
plt.plot(q_init.x, q_init.y, 'go', label='Start') # 绘制起点
plt.plot(q_goal.x, q_goal.y, 'ro', label='Goal') # 绘制终点
plt.xlabel('X')
plt.ylabel('Y')
plt.title('RRT Algorithm Visualization')
plt.legend()
plt.grid(True)
plt.show()
if __name__ == "__main__":
main()
上述代码实现了基本的RRT(Rapidly-exploring Random Tree)算法,具体实现流程如下所示。
(1)首先,定义类Node,用于表示二维空间中的节点,每个节点有 x 和 y 坐标。
(2)然后,定义了一个计算两个节点之间距离的函数 distance,以及一个扩展节点的函数 extend。distance 函数使用欧几里得距离公式计算两个节点之间的距离,extend 函数用于在当前最近节点和随机生成的节点之间进行扩展,保证扩展距离不超过最大距离。
(3)接着,在主函数main中定义了起始节点 q_init 和目标节点 q_goal,并创建了一个存储节点的集合 V,将起始节点加入集合。
(4)在迭代过程中,程序将执行如下所示的操作:
- 采样随机点:生成一个随机的二维坐标点作为新的随机点 q_rand。
- 找到距离随机点最近的节点:遍历节点集合 V,找到与随机点 q_rand 最近的节点 q_nearest。
- 扩展树:使用 extend 函数将最近节点 q_nearest 和随机点 q_rand 之间的距离进行扩展,生成一个新的节点 q_new,并将其加入节点集合 V 中。
- 以上过程会持续进行指定的迭代次数。
(5)最后,将生成的节点和起点到终点之间的路径进行可视化展示,如图7-2所示。使用 matplotlib 库绘制了生成的节点和路径,节点用蓝色圆圈表示,起点用绿色圆圈表示,终点用红色圆圈表示,路径用红色线段表示。展示了算法在迭代过程中生成的节点分布情况以及起点到终点的路径。
图7-2 节点和路径的可视化