7.2.4 RRT_Connect 算法
RRT-Connect 算法是 RRT(Rapidly-exploring Random Tree)算法的一种变体,用于解决路径规划问题。与标准的 RRT 算法不同,RRT-Connect 算法旨在通过两个相互连接的 RRT 树来更快地找到起始点和目标点之间的路径。
上述的RRT 每次搜索都只有从初始状态点生长的快速扩展随机树来搜索整个状态空间,如果从初始状态点和目标状态点同时生长两棵快速扩展随机树来搜索状态空间,效率会更高。为此,在 2000 年由 LaValle 教授和日本东京大学的 Kuffner 教授联合提出了基于双向扩展平衡的连结型双树RRT 算法,即RRT_Connect 算法。
RRT-Connect 算法的基本思想是从起始点和目标点分别开始,在两个树之间进行交替的扩展,直到两个树连接在一起或达到最大迭代次数。算法会在两个树中选择一个目标点,然后利用 RRT 的基本扩展过程来不断扩展树,直到找到连接起始点和目标点的路径为止。
RRT-Connect 算法的优点如下所示:
- 较快地找到路径:通过同时从起始点和目标点开始扩展树,可以更快地找到连接两点的路径。
- 避免局部最优:由于使用了两个相互连接的树,可以避免陷入局部最优解。
RRT-Connect 算法在机器人路径规划和运动规划等领域得到了广泛的应用,特别是在需要快速找到路径且避免局部最优的情况下。
RRT-Connect 算法与原始 RRT 相比,在目标点区域建立第二棵树进行扩展。每一次迭代中,开始步骤与原始的 RRT 算法一样,都是采样随机点然后进行扩展。然后扩展完第一棵树的新节点𝑞𝑛𝑒𝑤后,以这个新的目标点作为第二棵树扩展的方向。同时第二棵树扩展的方式略有不同,首先它会扩展第一步得到𝑞′𝑛𝑒𝑤,如果没有碰撞,继续往相同的方向扩展第二步,直到扩展失败或者𝑞′𝑛𝑒𝑤= 𝑞𝑛𝑒𝑤表示与第一棵树相连了,即 connect了,整个算法结束。当然在每次迭代中必须考虑两棵树的平衡性,即两棵树的节点数的多少(也可以考虑两棵树总共花费的路径长度),交换次序选择“小”的那棵树进行扩展。这种双向的 RRT 技术具有良好的搜索特性,比原始 RRT 算法的搜索速度、搜索效率有了显著提高,被广泛应用。首先,Connect 算法较之前的算法在扩展的步长上更长,使得树的生长更快;其次,两棵树不断朝向对方交替扩展, 而不是采用随机扩展的方式,特别当起始位姿和目标位姿处于约束区域时,两棵树可以通过朝向对方快速扩展而逃离各自的约束区域。这种带有启发性的扩展使得树的扩展更加贪婪和明确,使得双树RRT 算法较之单树RRT 算法更加有效。
例如下面的实例演示了实现 RRT_Connect 算法的过程,首先定义了一个简单的二维空间,包括起始点和目标点。然后使用 RRT_Connect 算法寻找连接起始点和目标点的路径。如果找到路径,则输出路径上的节点;如果未找到路径,则输出“Failed to find a path!”。
实例7-3:使用RRT_Connect 算法寻找路径(codes/7/Connect.py)
实例文件Connect.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 sample_random_point():
return Node(random.randint(0, 100), random.randint(0, 100))
# 扩展树
def extend(tree, q_new, step_size):
q_nearest = min(tree, key=lambda n: distance(n, q_new))
theta = math.atan2(q_new.y - q_nearest.y, q_new.x - q_nearest.x)
x = q_nearest.x + step_size * math.cos(theta)
y = q_nearest.y + step_size * math.sin(theta)
q_new_extended = Node(x, y)
tree.append(q_new_extended)
return q_new_extended
# 检查是否连接两棵树
def is_connected(q1, q2, threshold):
return distance(q1, q2) < threshold
# RRT_Connect 算法
def rrt_connect(start, goal, max_iter, step_size, threshold):
tree_start, tree_goal = [start], [goal]
path = []
for _ in range(max_iter):
# 从起始树扩展
q_rand = sample_random_point()
q_extended_start = extend(tree_start, q_rand, step_size)
# 从目标树扩展
q_extended_goal = extend(tree_goal, q_extended_start, step_size)
# 检查是否连接
if is_connected(q_extended_start, q_extended_goal, threshold):
# 如果连接,构建路径并返回
path = [start] + tree_start + [q_extended_start] + list(reversed(tree_goal)) + [goal]
break
return path
# 可视化路径规划的过程和结果
def visualize(start, goal, path, tree_start, tree_goal):
plt.figure(figsize=(8, 6))
# 绘制起始点和目标点
plt.plot(start.x, start.y, 'go', markersize=10, label='Start')
plt.plot(goal.x, goal.y, 'ro', markersize=10, label='Goal')
# 绘制路径
if path:
path_x = [node.x for node in path]
path_y = [node.y for node in path]
plt.plot(path_x, path_y, 'b-', linewidth=2, label='Path')
# 绘制树
tree_start_x = [node.x for node in tree_start]
tree_start_y = [node.y for node in tree_start]
tree_goal_x = [node.x for node in tree_goal]
tree_goal_y = [node.y for node in tree_goal]
plt.plot(tree_start_x, tree_start_y, 'gx', label='Tree Start')
plt.plot(tree_goal_x, tree_goal_y, 'rx', label='Tree Goal')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('RRT_Connect Path Planning')
plt.legend()
plt.grid(True)
plt.show()
if __name__ == "__main__":
start = Node(0, 0) # 起始点
goal = Node(10, 10) # 目标点
max_iter = 1000 # 最大迭代次数
step_size = 1.0 # 扩展步长
threshold = 1.0 # 连接阈值
tree_start, tree_goal = [start], [goal]
path = rrt_connect(start, goal, max_iter, step_size, threshold)
if not path:
print("Failed to find a path!")
else:
print("Found a path:")
for node in path:
print(f"({node.x}, {node.y})", end=" ")
print()
visualize(start, goal, path, tree_start, tree_goal)
}
对上述代码的实现流程如下所示:
- 定义节点结构:定义了一个 Node 结构体,用于表示二维空间中的节点,包含节点的 x 和 y 坐标。
- 计算节点距离:实现了 distance 函数,用于计算两个节点之间的欧氏距离。
- 随机采样点:实现了 SampleRandomPoint 函数,用于在给定的空间内随机采样一个点作为新节点。
- 扩展树:实现了 Extend 函数,用于在树中扩展一个新节点。该函数会找到距离新节点最近的节点,并沿着连接这两个节点的方向进行扩展。
- 检查连接:实现了 IsConnected 函数,用于检查两个节点之间的距离是否小于给定的阈值,从而判断是否连接。
- RRT_Connect 算法:实现了 RRT_Connect 函数,该函数接收起始点、目标点、最大迭代次数、扩展步长和连接阈值作为输入参数。在每次迭代中,该函数会从起始树和目标树分别扩展节点,并检查是否两棵树已经连接。如果连接,则构建路径并返回;如果达到最大迭代次数仍未找到路径,则返回空路径。
- 可视化功能:在主函数中实现了路径规划的可视化功能。通过调用 RRT_Connect 函数获取路径后,利用 matplotlib 库绘制搜索过程和路径,如图7-4所示。起始点、目标点、随机采样点、扩展过程以及最终路径都会以不同的颜色和标记进行显示,帮助我们直观地理解算法的工作原理和路径规划的过程。
图7-4 路径规划的可视化图