Python实现改进后的Bi-RRT算法实例1.背景说明以下代码是参照上海交通大学海洋工程国家重点实验室《基于改进双向RRT的无人艇局部路径规划算法研究》的算法思想实现的 。
2.算法流程
- 产生随机节点pi
- 寻找T1中距离p1最近的节点pn
- 以pn为父节点按原始步长向pi延伸得到虚新节点pa
- 确定距离pi最近的障碍物
- 使用动态步长策略计算实际步长sf
- 按照实际sf延伸得到实际节点新pw
- 障碍物检测 通过则进入步骤8 否则重回步骤1
- 转角约束检测 通过则进入步骤9 否则重回步骤1
- 将pw加入T1
- 在T2中寻找距离pw最近的节点pj
- 以pj为父节点按原始步长向pw延伸得到虚新节点pb
- 确定距离pb最近的障碍物
- 使用动态步长策略计算实际步长sf
- 按照实际sf延伸得到实际新节点px
- 障碍物检测 通过则进入步骤16 否则重回步骤1
- 转角约束检测 通过则进入步骤17 否则重回步骤1
- 将pw加入T2
- 检测是否满足相遇条件 是则进入步骤20 否则继续步骤1
- 检测是否满足平滑连接 是则结束搜索 否则继续步骤1
- 路径回溯
"""基于改进双向RRT算法的路径规划"""import matplotlib.pyplot as pltfrom matplotlib.pyplot import MultipleLocatorimport numpy as npimport mathimport randomimport copyclass Point(object):"""路径节点"""def __init__(self, x, y):self.x = xself.y = yself.parent = Noneclass BiRRT(object):"""双向RRT算法实现"""def __init__(self, start, goal, angle, step, distance, obstacle_list, rand_area, safe, recover):"""初始化:param start: 起点 [x,y]:param goal: 终点 [x,y]:param angle: 转向角 60:param step: 基础步长 10:param obstacle_list: 障碍物列表 [[x,y,radius]...]:param rand_area: 区域大小:param safe: 安全航迹结束点:param recover: 安全航迹恢复点"""self.start = Point(start[0], start[1])self.goal = Point(goal[0], goal[1])self.angle = angleself.step = stepself.distance = distanceself.obstacle_list = obstacle_listself.min_rand = rand_area[0]self.max_rand = rand_area[1]self.goalSampleRate = 0.05self.safe = Point(safe[0], safe[1])self.recover = Point(recover[0], recover[1])# 从起点开始搜索self.point_list_from_start = [self.start]begin = copy.deepcopy(self.safe)begin.parent = 0self.point_list_from_start.append(begin)# 从终点开始搜索self.point_list_from_goal = [self.goal]begin = copy.deepcopy(self.recover)begin.parent = 0self.point_list_from_goal.append(begin)def random_point(self):"""产生随机节点:return:"""point_x = random.uniform(self.safe.x, self.recover.y)point_y = random.uniform(self.safe.x, self.recover.y)point = [point_x, point_y]return point@staticmethoddef get_nearest_list_index(point_list, rnd):"""在节点列表中找到距离目标节点中最近的点:param point_list: 节点列表 T1 or obstacle_list:param rnd: 目标节点:return: 最近节点的位置"""d_list = [(point.x - rnd[0]) ** 2 + (point.y - rnd[1]) ** 2 for point in point_list]min_index = d_list.index(min(d_list))return min_indexdef get_nearest_obstacle_index(self, point):"""找到距离point最近的障碍物:param point: 节点:return: 最近的障碍物"""d_list = [(math.sqrt((point.x - x) ** 2 + (point.y - y) ** 2)) - r for (x, y, r) in self.obstacle_list]min_index = d_list.index(min(d_list))return min_indexdef collision_check(self, t, new_point, obstacle_list):"""检查新的节点是否会碰撞或穿越到障碍物:param t: 树:param new_point: 实际新节点:param obstacle_list: 障碍物列表:return:"""flag = 1for (ox, oy, radius) in obstacle_list:# 点到障碍物中心的距离dx = ox - new_point.xdy = oy - new_point.yd = math.sqrt(dx * dx + dy * dy)# 判断是否穿过障碍物if t == 1:parent_point = self.point_list_from_start[new_point.parent]else:parent_point = self.point_list_from_goal[new_point.parent]vector_o = np.array([ox, oy])vector_p = np.array([parent_point.x, parent_point.y])vector_n = np.array([new_point.x, new_point.y])d_p_n = np.abs(np.cross(vector_p - vector_o, vector_n - vector_o)) / np.linalg.norm(vector_p - vector_n)# 如果点落在或穿过障碍物if d < radius or d_p_n < radius:flag = 0return flagreturn flagdef angle_check(self, new_point, parent_point, ancestor_point):"""转角约束:param new_point: 新节点 w:param parent_point: n节点(新节点的父级节点):param ancestor_point: f祖先节点:return:"""vector_p_n = np.array([new_point.x - parent_point.x, new_point.y - parent_point.y])vector_a_p = np.array([parent_point.x - ancestor_point.x, parent_point.y - ancestor_point.y])angle = get_angle(vector_a_p, vector_p_n)if angle <= self.angle:return Trueelse:return Falsedef dynamic_step(self, n_point, a_point):"""计算动态步长:param n_point: 父节点:param a_point: 虚新节点:return: Sf 动态步长"""tan = math.atan2(a_point.y - n_point.y, a_point.x - n_point.x)a_point.x += math.cos(tan) * (self.distance + self.step) / 2a_point.y += math.sin(tan) * (self.distance + self.step) / 2# 距离最近的障碍物obstacle_min = self.obstacle_list[self.get_nearest_obstacle_index(a_point)]# 虚拟节点a_point至障碍物边缘的距离l_al_a = math.sqrt((a_point.x - obstacle_min[0]) ** 2 + (a_point.y - obstacle_min[1]) ** 2) - obstacle_min[2]# 生长点n_point至障碍物边缘的距离l_nl_n = math.sqrt(np.square(n_point.x - obstacle_min[0]) + np.square(n_point.y - obstacle_min[1])) - obstacle_min[2]dynamic = self.step / (1 + (self.step / self.distance - 1) * math.exp(-3 * l_n / self.step))return dynamicdef coordinate(self, t, rnd):"""实际坐标计算:param t: 搜索树编号 1 2:param rnd: 虚新节点:return: 实际新节点"""# 在搜索树中找到距离rnd最近的节点if t == 1:min_index = self.get_nearest_list_index(self.point_list_from_start, rnd)nearest_point = self.point_list_from_start[min_index]elif t == 2:min_index = self.get_nearest_list_index(self.point_list_from_goal, rnd)nearest_point = self.point_list_from_goal[min_index]# 按照原始步长计算坐标theta = math.atan2(rnd[1] - nearest_point.y, rnd[0] - nearest_point.x)new_point = copy.deepcopy(nearest_point)new_point.x += math.cos(theta) * self.stepnew_point.y += math.sin(theta) * self.stepnew_point.parent = min_index# 使用动态步长策略计算实际坐标actual_step = self.dynamic_step(nearest_point, new_point)new_point.x = nearest_point.x + math.cos(theta) * actual_stepnew_point.y = nearest_point.y + math.sin(theta) * actual_stepreturn new_point, actual_stepdef condition_check(self, t, new_point):"""限制条件检测1.碰撞检测2.转交约束检测:param t: 搜索树:param new_point: 实际新节点:return: Boolean"""# 碰撞检测if self.collision_check(t, new_point, self.obstacle_list):if t == 1:# 搜索树1的转角约束检测n_point = self.point_list_from_start[new_point.parent]if n_point.parent is None:return Falsef_point = self.point_list_from_start[n_point.parent]if self.angle_check(new_point, n_point, f_point):return Trueelse:return Falseelse:# 搜索树2的转角约束检测n_point = self.point_list_from_goal[new_point.parent]if n_point.parent is None:return Falsef_point = self.point_list_from_goal[n_point.parent]if self.angle_check(new_point, n_point, f_point):return Trueelse:return Falseelse:return Falsedef perfect_connect(self, one_point, two_point):"""计算是否满足平滑连接:param one_point: 1号树的节点 w:param two_point: 2号树的节点 x:return:"""one_parent = self.point_list_from_start[one_point.parent]# ntwo_parent = self.point_list_from_goal[two_point.parent]# jvector_n_w = np.array([one_point.x - one_parent.x, one_point.y - one_parent.y])vector_w_x = np.array([two_point.x - one_point.x, two_point.y - one_point.y])vector_x_j = np.array([two_parent.x - two_point.x, two_parent.y - two_point.y])angle_one = get_angle(vector_n_w, vector_w_x)angle_two = get_angle(vector_w_x, vector_x_j)if angle_one <= self.angle:if angle_two == 180.0 or angle_one == 0.0:return Falseelse:print("phi: {0}, delta: {1}".format(angle_one, angle_two))return Trueelse:return Falsedef generate_path_list(self):"""路径回溯:return: list"""path = []path_1 = []path_2 = []last_index = len(self.point_list_from_start) - 1while self.point_list_from_start[last_index].parent is not None:point = self.point_list_from_start[last_index]path.append([point.x, point.y])path_1.append([point.x, point.y])last_index = point.parentpath.append([self.start.x, self.start.y])path_1.append([self.start.x, self.start.y])path = path[::-1]last_index = len(self.point_list_from_goal) - 1while self.point_list_from_goal[last_index].parent is not None:point = self.point_list_from_goal[last_index]path.append([point.x, point.y])path_2.append([point.x, point.y])last_index = point.parentpath.append([self.goal.x, self.goal.y])path_2.append([self.goal.x, self.goal.y])print("最终规划路径:", path)print("搜索树1:", path_1)print("搜索树2:", path_2)return path, path_1, path_2def planning(self):"""路径规划算法的具体实现流程:1.产生随机节点pi2.寻找T1中距离p1最近的节点pn3.以pn为父节点按原始步长向pi延伸得到虚新节点pa4.确定距离pi最近的障碍物5.使用动态步长策略计算实际步长sf6.按照实际sf延伸得到实际节点新pw7.障碍物检测 通过则进入步骤8 否则重回步骤18.转角约束检测 通过则进入步骤9 否则重回步骤19.将pw加入T110.在T2中寻找距离pw最近的节点pj11.以pj为父节点按原始步长向pw延伸得到虚新节点pb12.确定距离pb最近的障碍物13.使用动态步长策略计算实际步长sf14.按照实际sf延伸得到实际新节点px15.障碍物检测 通过则进入步骤16 否则重回步骤116.转角约束检测 通过则进入步骤17 否则重回步骤118.将pw加入T219.检测是否满足相遇条件 是则进入步骤20 否则继续步骤120.检测是否满足平滑连接 是则结束搜索 否则继续步骤121.路径回溯:return: [[x, y]]"""# 路径搜索while True:"""搜索树1的实现"""# T1产生随机节点if random.random() > self.goalSampleRate:rnd = self.random_point()else:rnd = [self.goal.x, self.goal.y]# 计算后的实际新节点和动态步长new_point, actual_step = self.coordinate(1, rnd)# 限制条件检测if not self.condition_check(1, new_point):continue# 实际新节点通过检测 加入T1self.point_list_from_start.append(new_point)"""搜索树2的实现"""# 实际新节点new_point_two, actual_step = self.coordinate(2, [new_point.x, new_point.y])# 限制条件检测if not self.condition_check(2, new_point_two):continue# 实际新节点加入 T2self.point_list_from_goal.append(new_point_two)"""判断是否达到目标点"""# 判断是否满足相遇条件dx = new_point.x - new_point_two.xdy = new_point.y - new_point_two.yd = math.sqrt(dx * dx + dy * dy)if self.distance < d < self.step:if self.perfect_connect(new_point, new_point_two):breakelse:continueelse:continuereturn self.generate_path_list()def draw_statistic(self, path):"""绘制静态图像:param path: 规划完成的路径:return:"""plt.clf()# 绘制区域# x轴刻度区间x_major_location = MultipleLocator(10)# y轴刻度区间y_major_location = MultipleLocator(10)# 坐标轴实例ax = plt.gca()ax.xaxis.set_major_locator(x_major_location)ax.yaxis.set_major_locator(y_major_location)plt.axis([self.min_rand, self.max_rand, self.min_rand, self.max_rand])# 绘制障碍物for (ox, oy, radius) in self.obstacle_list:circle = plt.Circle(xy=(ox, oy), radius=radius, color="r")ax.add_patch(circle)# 绘制起点plt.plot(self.start.x, self.start.y, "^g")# 绘制终点plt.plot(self.goal.x, self.goal.y, "^b")# 绘制规划的路径plt.plot([data[0] for data in path], [data[1] for data in path], "-y")for (x, y) in path:plt.scatter(x, y, marker='o', c='b', edgecolors='b')ax.set_aspect('equal', adjustable='datalim')ax.plot()plt.grid(True)plt.show()def get_angle(a, b):"""向量夹角计算:param a::param b::return:"""a_norm = np.sqrt(np.sum(a * a))b_norm = np.sqrt(np.sum(b * b))cos_value = https://www.huyubaike.com/biancheng/float(np.dot(a, b) / (a_norm * b_norm))eps = 1e-6if 1.0
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Java实现6种常见排序
- C++实现双向RRT算法
- frp服务利用云主机实现Windows远程连接
- WPF开发经验-实现自带触控键盘的TextBox
- frp服务利用云主机docker服务实现Windows远程连接
- 1 python-数据描述与分析
- 51单片机下实现软件模拟IIC通信
- 含源码 手把手教你使用LabVIEW OpenCV DNN实现手写数字识别
- 分享一个Vue实现图片水平瀑布流的插件
- Python中list列表的常见操作