From ffa911e80ce0ec00ebb34605ef9f8ead889b66b4 Mon Sep 17 00:00:00 2001 From: zhm-real Date: Tue, 28 Jul 2020 00:48:51 -0700 Subject: [PATCH] update --- Sampling-based Planning/gif/RRT_STAR_2D.gif | Bin 0 -> 70611 bytes .../rrt_2D/informed_rrt_star.py | 211 ++++++++++++++++++ .../rrt_2D/optimal_bi_rrt.py | 134 +++++++++++ Sampling-based Planning/rrt_2D/rrt_star.py | 2 +- Sampling-based Planning/rrt_3D/rrtstar3D.py | 4 +- Sampling-based Planning/rrt_3D/utils3D.py | 2 +- Search-based Planning/Search_2D/ARAstar.py | 8 +- .../Search_2D/Anytime_D_star.py | 6 +- Search-based Planning/Search_2D/Astar.py | 14 +- .../Search_2D/Bidirectional_a_star.py | 10 +- Search-based Planning/Search_2D/D_star.py | 6 +- .../Search_2D/D_star_Lite.py | 6 +- Search-based Planning/Search_2D/Dijkstra.py | 8 +- Search-based Planning/Search_2D/LPAstar.py | 6 +- Search-based Planning/Search_2D/LRTAstar.py | 12 +- Search-based Planning/Search_2D/RTAAstar.py | 10 +- .../Search_3D/Anytime_Dstar3D.py | 20 +- Search-based Planning/Search_3D/Dstar3D.py | 2 +- .../Search_3D/DstarLite3D.py | 20 +- Search-based Planning/Search_3D/LP_Astar3D.py | 6 +- Search-based Planning/Search_3D/utils3D.py | 2 +- 21 files changed, 417 insertions(+), 72 deletions(-) create mode 100644 Sampling-based Planning/gif/RRT_STAR_2D.gif create mode 100644 Sampling-based Planning/rrt_2D/informed_rrt_star.py diff --git a/Sampling-based Planning/gif/RRT_STAR_2D.gif b/Sampling-based Planning/gif/RRT_STAR_2D.gif new file mode 100644 index 0000000000000000000000000000000000000000..c4ddfcb038a3683c37ea236521f60573d9fa0a90 GIT binary patch literal 70611 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 z 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 OVon90-W4AUc>WjfU)YiW literal 0 HcmV?d00001 diff --git a/Sampling-based Planning/rrt_2D/informed_rrt_star.py b/Sampling-based Planning/rrt_2D/informed_rrt_star.py new file mode 100644 index 0000000..891d9fc --- /dev/null +++ b/Sampling-based Planning/rrt_2D/informed_rrt_star.py @@ -0,0 +1,211 @@ +""" +INFORMED_RRT_STAR 2D +@author: huiming zhou +""" + +import os +import sys +import math +import random +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.patches as patches + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + + "/../../Sampling-based Planning/") + +from rrt_2D import env +from rrt_2D import plotting +from rrt_2D import utils +from rrt_2D import queue + + +class Node: + def __init__(self, n): + self.x = n[0] + self.y = n[1] + self.parent = None + + +class IRrtStar: + def __init__(self, x_start, x_goal, step_len, + goal_sample_rate, search_radius, iter_max): + self.x_start = Node(x_start) + self.x_goal = Node(x_goal) + self.step_len = step_len + self.goal_sample_rate = goal_sample_rate + self.search_radius = search_radius + self.iter_max = iter_max + + self.env = env.Env() + self.plotting = plotting.Plotting(x_start, x_goal) + self.utils = utils.Utils() + + # self.fig, self.ax = plt.subplots() + self.x_range = self.env.x_range + self.y_range = self.env.y_range + self.obs_circle = self.env.obs_circle + self.obs_rectangle = self.env.obs_rectangle + self.obs_boundary = self.env.obs_boundary + + self.V = [self.x_start] + self.X_soln = set() + self.path = None + + def planning(self): + c_best = np.inf + c_min = self.Line(self.x_start, self.x_goal) + x_center = np.array([[(self.x_start.x + self.x_goal.x) / 2.0], + [(self.x_start.y + self.x_goal.y) / 2.0], [0.0]]) + a1 = np.array([[(self.x_goal.x - self.x_start.x) / c_min], + [(self.x_goal.y - self.x_start.y) / c_min], [0.0]]) + e_theta = math.atan2(a1[1], a1[0]) + id1_t = np.array([[1.0, 0.0, 0.0]]) + M = a1 @ id1_t + U, S, Vh = np.linalg.svd(M, True, True) + C = np.dot(np.dot(U, np.diag( + [1.0, 1.0, np.linalg.det(U) * np.linalg.det(np.transpose(Vh))])), Vh) + + for k in range(self.iter_max): + if k % 500 == 0: + print(k) + + if self.X_soln: + c_best = min([self.Cost(x) for x in self.X_soln]) + + x_rand = self.Sample(self.x_start, self.x_goal, c_best, x_center, C) + x_nearest = self.Nearest(self.V, x_rand) + x_new = self.Steer(x_nearest, x_rand) + + if x_new and not self.utils.is_collision(x_nearest, x_new): + self.V.append(x_new) + X_near = self.Near(self.V, x_new) + x_min = x_nearest + c_min = self.Cost(x_min) + self.Line(x_nearest, x_new) + + for x_near in X_near: + c_new = self.Cost(x_near) + self.Line(x_near, x_new) + if c_new < c_min: + x_new.parent = x_near + c_min = c_new + + for x_near in X_near: + c_near = self.Cost(x_near) + c_new = self.Cost(x_new) + self.Line(x_new, x_near) + if c_new < c_near: + x_near.parent = x_new + + if self.InGoalRegion(x_new): + self.X_soln.add(x_new) + + path = self.ExtractPath(self.V[-1]) + self.plotting.animation(self.V, path, "Informed rrt*") + + def ExtractPath(self, node): + path = [[self.x_goal.x, self.x_goal.y]] + + while node.parent: + path.append([node.x, node.y]) + node = node.parent + + path.append([self.x_start.x, self.x_start.y]) + + return path + + def InGoalRegion(self, node): + if self.Line(node, self.x_goal) < self.step_len: + return True + + return False + + def Steer(self, x_start, x_goal): + dist, theta = self.get_distance_and_angle(x_start, x_goal) + dist = min(self.step_len, dist) + node_new = Node((x_start.x + dist * math.cos(theta), + x_start.y + dist * math.sin(theta))) + node_new.parent = x_start + + return node_new + + def Near(self, nodelist, node): + n = len(nodelist) + 1 + r = 2 * self.search_radius * math.sqrt((math.log(n) / n)) + + dist_table = [math.hypot(nd.x - node.x, nd.y - node.y) for nd in nodelist] + X_near = [nodelist[ind] for ind in range(len(dist_table)) if dist_table[ind] <= r and + not self.utils.is_collision(node, nodelist[ind])] + + return X_near + + def Sample(self, x_start, x_goal, c_max, x_center, C): + if c_max < np.inf: + c_min = self.Line(x_start, x_goal) + r = [c_max / 2.0, + math.sqrt(c_max ** 2 - c_min ** 2) / 2.0, + math.sqrt(c_max ** 2 - c_min ** 2) / 2.0] + L = np.diag(r) + x_ball = self.SampleUnitNBall() + x_rand = np.dot(np.dot(C, L), x_ball) + x_center + else: + x_rand = self.SampleFreeSpace() + + return x_rand + + def SampleFreeSpace(self): + delta = self.utils.delta + + if np.random.random() > self.goal_sample_rate: + return [np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta), + np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)] + + return [self.x_goal.x, self.x_goal.y] + + @staticmethod + def SampleUnitNBall(): + x, y = random.random(), random.random() + + if y < x: + x, y = y, x + + sample = np.array([[y * math.cos(2 * math.pi * x / y)], + [y * math.sin(2 * math.pi * x / y)], [0.0]]) + + return sample + + @staticmethod + def Nearest(nodelist, n): + return nodelist[int(np.argmin([math.hypot(nd.x - n.x, nd.y - n.y) + for nd in nodelist]))] + + @staticmethod + def Line(x_start, x_goal): + return math.hypot(x_goal.x - x_start.x, x_goal.y - x_start.y) + + @staticmethod + def Cost(node_p): + node = node_p + cost = 0.0 + + while node.parent: + cost += math.hypot(node.x - node.parent.x, node.y - node.parent.y) + node = node.parent + + return cost + + @staticmethod + def get_distance_and_angle(node_start, node_end): + dx = node_end.x - node_start.x + dy = node_end.y - node_start.y + return math.hypot(dx, dy), math.atan2(dy, dx) + + +def main(): + x_start = (2, 2) # Starting node + x_goal = (49, 24) # Goal node + + rrt_star = IRrtStar(x_start, x_goal, 10, 0.10, 20, 4000) + rrt_star.planning() + + +if __name__ == '__main__': + main() diff --git a/Sampling-based Planning/rrt_2D/optimal_bi_rrt.py b/Sampling-based Planning/rrt_2D/optimal_bi_rrt.py index e69de29..3aa2b41 100644 --- a/Sampling-based Planning/rrt_2D/optimal_bi_rrt.py +++ b/Sampling-based Planning/rrt_2D/optimal_bi_rrt.py @@ -0,0 +1,134 @@ +""" +Optimal_Bidirectional_RRT 2D +@author: huiming zhou +""" + +import os +import sys +import math +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.patches as patches + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + + "/../../Sampling-based Planning/") + +from rrt_2D import env +from rrt_2D import plotting +from rrt_2D import utils +from rrt_2D import queue + + +class Node: + def __init__(self, n): + self.x = n[0] + self.y = n[1] + self.parent = None + + +class OBiRrt: + def __init__(self, x_start, x_goal, step_len, + goal_sample_rate, search_radius, iter_max): + self.x_init = Node(x_start) + self.x_goal = Node(x_goal) + self.step_len = step_len + self.goal_sample_rate = goal_sample_rate + self.search_radius = search_radius + self.iter_max = iter_max + + self.Ta = [self.x_init] + self.Tb = [self.x_goal] + self.c_best = np.inf + self.sigma_best = {} + self.path = [] + self.visited = [] + + self.env = env.Env() + self.plotting = plotting.Plotting(x_start, x_goal) + self.utils = utils.Utils() + # self.fig, self.ax = plt.subplots() + + self.x_range = self.env.x_range + self.y_range = self.env.y_range + self.obs_circle = self.env.obs_circle + self.obs_rectangle = self.env.obs_rectangle + self.obs_boundary = self.env.obs_boundary + + def planning(self): + for k in range(self.iter_max): + x_rand = self.generate_random_node(self.x_goal, self.goal_sample_rate) + x_nearest = self.nearest_neighbor(self.Ta, x_rand) + x_new = self.steer(x_nearest, x_rand) + X_near_ind = self.nearest_neighbor(self.Ta, x_new) + L_near = [] + + for x_near_ind in X_near_ind: + x_near = self.Ta[x_near_ind] + sigma_near = self.steer(x_near, x_new) + c_near = self.cost(x_near) + self.cost(sigma_near) + L_near.append((c_near, x_near, sigma_near)) + + L_near.sort() + + for c_near, x_near, sigma_near in L_near: + if c_near + self.cost_to_go() + + + def cost_to_go(self, x_start, x_goal): + return math.hypot(x_goal.x - x_start.x, x_goal.y - x_start.y) + + def generate_random_node(self, goal_point, goal_sample_rate): + delta = self.utils.delta + + if np.random.random() > goal_sample_rate: + return Node((np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta), + np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta))) + + return goal_point + + @staticmethod + def nearest_neighbor(V, node): + return V[int(np.argmin([math.hypot(nd.x - node.x, nd.y - node.y) for nd in V]))] + + def steer(self, node_start, node_goal): + dist, theta = self.get_distance_and_angle(node_start, node_goal) + + dist = min(self.step_len, dist) + node_new = Node((node_start.x + dist * math.cos(theta), + node_start.y + dist * math.sin(theta))) + + node_new.parent = node_start + + return node_new + + def find_near_neighbor(self, V, node): + n = len(V) + 1 + r = min(self.search_radius * math.sqrt((math.log(n) / n)), self.step_len) + + dist_table = [(nd.x - node.x) ** 2 + (nd.y - node.y) ** 2 for nd in V] + dist_table_index = [ind for ind in range(len(dist_table)) if dist_table[ind] <= r and + not self.utils.is_collision(node, V[ind])] + + return dist_table_index + + def get_new_cost(self, node_start, node_end): + dist, _ = self.get_distance_and_angle(node_start, node_end) + + return self.cost(node_start) + dist + + @staticmethod + def cost(node_p): + node = node_p + cost = 0.0 + + while node.parent: + cost += math.hypot(node.x - node.parent.x, node.y - node.parent.y) + node = node.parent + + return cost + + @staticmethod + def get_distance_and_angle(node_start, node_end): + dx = node_end.x - node_start.x + dy = node_end.y - node_start.y + return math.hypot(dx, dy), math.atan2(dy, dx) diff --git a/Sampling-based Planning/rrt_2D/rrt_star.py b/Sampling-based Planning/rrt_2D/rrt_star.py index 90735f4..1a9db94 100644 --- a/Sampling-based Planning/rrt_2D/rrt_star.py +++ b/Sampling-based Planning/rrt_2D/rrt_star.py @@ -218,7 +218,7 @@ class RrtStar: continue for node_c in node.child: - node_c.cost = self.get_new_cost(node, node_c) + node_c.Cost = self.get_new_cost(node, node_c) OPEN.put(node_c) def extract_path(self, node_end): diff --git a/Sampling-based Planning/rrt_3D/rrtstar3D.py b/Sampling-based Planning/rrt_3D/rrtstar3D.py index e22e781..61b457c 100644 --- a/Sampling-based Planning/rrt_3D/rrtstar3D.py +++ b/Sampling-based Planning/rrt_3D/rrtstar3D.py @@ -66,9 +66,9 @@ class rrtstar(): Xnear = near(self,xnew) self.V.append(xnew) # add point # visualization(self) - # minimal path and minimal cost + # minimal path and minimal Cost xmin, cmin = xnearest, cost(self, xnearest) + getDist(xnearest, xnew) - # connecting along minimal cost path + # connecting along minimal Cost path for xnear in Xnear: xnear = tuple(xnear) c1 = cost(self, xnear) + getDist(xnew, xnear) diff --git a/Sampling-based Planning/rrt_3D/utils3D.py b/Sampling-based Planning/rrt_3D/utils3D.py index 107e16a..0adab8f 100644 --- a/Sampling-based Planning/rrt_3D/utils3D.py +++ b/Sampling-based Planning/rrt_3D/utils3D.py @@ -199,7 +199,7 @@ def steer(initparams, x, y): return xnew def cost(initparams, x): - '''here use the additive recursive cost function''' + '''here use the additive recursive Cost function''' if x == initparams.x0: return 0 return cost(initparams, initparams.Parent[x]) + getDist(x, initparams.Parent[x]) diff --git a/Search-based Planning/Search_2D/ARAstar.py b/Search-based Planning/Search_2D/ARAstar.py index 58e3c12..0867f89 100644 --- a/Search-based Planning/Search_2D/ARAstar.py +++ b/Search-based Planning/Search_2D/ARAstar.py @@ -24,7 +24,7 @@ class AraStar: self.u_set = self.Env.motions # feasible input set self.obs = self.Env.obs # position of obstacles self.e = e # initial weight - self.g = {self.s_start: 0, self.s_goal: float("inf")} # cost to come + self.g = {self.s_start: 0, self.s_goal: float("inf")} # Cost to come self.OPEN = {self.s_start: self.fvalue(self.s_start)} # priority queue / OPEN set self.CLOSED = set() # CLOSED set @@ -155,11 +155,11 @@ class AraStar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/Anytime_D_star.py b/Search-based Planning/Search_2D/Anytime_D_star.py index c82b588..4cebb48 100644 --- a/Search-based Planning/Search_2D/Anytime_D_star.py +++ b/Search-based Planning/Search_2D/Anytime_D_star.py @@ -217,11 +217,11 @@ class ADStar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/Astar.py b/Search-based Planning/Search_2D/Astar.py index 8d2361c..444a4d4 100644 --- a/Search-based Planning/Search_2D/Astar.py +++ b/Search-based Planning/Search_2D/Astar.py @@ -25,7 +25,7 @@ class Astar: self.u_set = self.Env.motions # feasible input set self.obs = self.Env.obs # position of obstacles - self.g = {self.s_start: 0, self.s_goal: float("inf")} # cost to come + self.g = {self.s_start: 0, self.s_goal: float("inf")} # Cost to come self.OPEN = queue.QueuePrior() # priority queue / OPEN set self.OPEN.put(self.s_start, self.fvalue(self.s_start)) self.CLOSED = [] # CLOSED set / VISITED order @@ -48,7 +48,7 @@ class Astar: new_cost = self.g[s] + self.cost(s, s_n) if s_n not in self.g: self.g[s_n] = float("inf") - if new_cost < self.g[s_n]: # conditions for updating cost + if new_cost < self.g[s_n]: # conditions for updating Cost self.g[s_n] = new_cost self.PARENT[s_n] = s self.OPEN.put(s_n, self.fvalue(s_n)) @@ -99,7 +99,7 @@ class Astar: new_cost = g[s] + self.cost(s, s_n) if s_n not in g: g[s_n] = float("inf") - if new_cost < g[s_n]: # conditions for updating cost + if new_cost < g[s_n]: # conditions for updating Cost g[s_n] = new_cost PARENT[s_n] = s OPEN.put(s_n, g[s_n] + e * self.Heuristic(s_n)) @@ -122,11 +122,11 @@ class Astar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): @@ -153,7 +153,7 @@ class Astar: def fvalue(self, x): """ - f = g + h. (g: cost to come, h: heuristic function) + f = g + h. (g: Cost to come, h: heuristic function) :param x: current state :return: f """ diff --git a/Search-based Planning/Search_2D/Bidirectional_a_star.py b/Search-based Planning/Search_2D/Bidirectional_a_star.py index 4f01dfd..8ffafc1 100644 --- a/Search-based Planning/Search_2D/Bidirectional_a_star.py +++ b/Search-based Planning/Search_2D/Bidirectional_a_star.py @@ -25,8 +25,8 @@ class BidirectionalAstar: self.u_set = self.Env.motions # feasible input set self.obs = self.Env.obs # position of obstacles - self.g_fore = {self.s_start: 0, self.s_goal: float("inf")} # cost to come: from s_start - self.g_back = {self.s_goal: 0, self.s_start: float("inf")} # cost to come: form s_goal + self.g_fore = {self.s_start: 0, self.s_goal: float("inf")} # Cost to come: from x_start + self.g_back = {self.s_goal: 0, self.s_start: float("inf")} # Cost to come: form x_goal self.OPEN_fore = queue.QueuePrior() # OPEN set for foreward searching self.OPEN_fore.put(self.s_start, @@ -142,11 +142,11 @@ class BidirectionalAstar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/D_star.py b/Search-based Planning/Search_2D/D_star.py index 792620a..23522e4 100644 --- a/Search-based Planning/Search_2D/D_star.py +++ b/Search-based Planning/Search_2D/D_star.py @@ -177,11 +177,11 @@ class Dstar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/D_star_Lite.py b/Search-based Planning/Search_2D/D_star_Lite.py index ea10baf..6277b68 100644 --- a/Search-based Planning/Search_2D/D_star_Lite.py +++ b/Search-based Planning/Search_2D/D_star_Lite.py @@ -150,11 +150,11 @@ class DStar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/Dijkstra.py b/Search-based Planning/Search_2D/Dijkstra.py index 1d98611..9b4d4fb 100644 --- a/Search-based Planning/Search_2D/Dijkstra.py +++ b/Search-based Planning/Search_2D/Dijkstra.py @@ -25,7 +25,7 @@ class Dijkstra: self.u_set = self.Env.motions # feasible input set self.obs = self.Env.obs # position of obstacles - self.g = {self.s_start: 0, self.s_goal: float("inf")} # cost to come + self.g = {self.s_start: 0, self.s_goal: float("inf")} # Cost to come self.OPEN = queue.QueuePrior() # priority queue / OPEN set self.OPEN.put(self.s_start, 0) self.CLOSED = [] # closed set & visited @@ -89,11 +89,11 @@ class Dijkstra: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/LPAstar.py b/Search-based Planning/Search_2D/LPAstar.py index 70e816a..92b2656 100644 --- a/Search-based Planning/Search_2D/LPAstar.py +++ b/Search-based Planning/Search_2D/LPAstar.py @@ -149,11 +149,11 @@ class LpaStar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/LRTAstar.py b/Search-based Planning/Search_2D/LRTAstar.py index 7363f0e..f3594cb 100644 --- a/Search-based Planning/Search_2D/LRTAstar.py +++ b/Search-based Planning/Search_2D/LRTAstar.py @@ -50,7 +50,7 @@ class LrtAstarN: for x in h_value: self.h_table[x] = h_value[x] - s_start, path_k = self.extract_path_in_CLOSE(s_start, h_value) # s_start -> expected node in OPEN set + s_start, path_k = self.extract_path_in_CLOSE(s_start, h_value) # x_start -> expected node in OPEN set self.path.append(path_k) def extract_path_in_CLOSE(self, s_start, h_value): @@ -95,7 +95,7 @@ class LrtAstarN: OPEN = queue.QueuePrior() # OPEN set OPEN.put(x_start, self.h(x_start)) CLOSED = [] # CLOSED set - g_table = {x_start: 0, self.s_goal: float("inf")} # cost to come + g_table = {x_start: 0, self.s_goal: float("inf")} # Cost to come PARENT = {x_start: x_start} # relations count = 0 # counter @@ -113,7 +113,7 @@ class LrtAstarN: new_cost = g_table[s] + self.cost(s, s_n) if s_n not in g_table: g_table[s_n] = float("inf") - if new_cost < g_table[s_n]: # conditions for updating cost + if new_cost < g_table[s_n]: # conditions for updating Cost g_table[s_n] = new_cost PARENT[s_n] = s OPEN.put(s_n, g_table[s_n] + self.h_table[s_n]) @@ -177,11 +177,11 @@ class LrtAstarN: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_2D/RTAAstar.py b/Search-based Planning/Search_2D/RTAAstar.py index 3575eac..b73be99 100644 --- a/Search-based Planning/Search_2D/RTAAstar.py +++ b/Search-based Planning/Search_2D/RTAAstar.py @@ -90,7 +90,7 @@ class RtaAstar: OPEN = queue.QueuePrior() # OPEN set OPEN.put(x_start, self.h_table[x_start]) CLOSED = [] # CLOSED set - g_table = {x_start: 0, self.s_goal: float("inf")} # cost to come + g_table = {x_start: 0, self.s_goal: float("inf")} # Cost to come PARENT = {x_start: x_start} # relations count = 0 # counter @@ -108,7 +108,7 @@ class RtaAstar: new_cost = g_table[s] + self.cost(s, s_n) if s_n not in g_table: g_table[s_n] = float("inf") - if new_cost < g_table[s_n]: # conditions for updating cost + if new_cost < g_table[s_n]: # conditions for updating Cost g_table[s_n] = new_cost PARENT[s_n] = s OPEN.put(s_n, g_table[s_n] + self.h_table[s_n]) @@ -186,11 +186,11 @@ class RtaAstar: def cost(self, s_start, s_goal): """ - Calculate cost for this motion + Calculate Cost for this motion :param s_start: starting node :param s_goal: end node - :return: cost for this motion - :note: cost function could be more complicate! + :return: Cost for this motion + :note: Cost function could be more complicate! """ if self.is_collision(s_start, s_goal): diff --git a/Search-based Planning/Search_3D/Anytime_Dstar3D.py b/Search-based Planning/Search_3D/Anytime_Dstar3D.py index 43c0307..42075c6 100644 --- a/Search-based Planning/Search_3D/Anytime_Dstar3D.py +++ b/Search-based Planning/Search_3D/Anytime_Dstar3D.py @@ -41,7 +41,7 @@ class Anytime_Dstar(object): # init children set: self.CHILDREN = {} - # init cost set + # init Cost set self.COST = defaultdict(lambda: defaultdict(dict)) # for visualization @@ -88,7 +88,7 @@ class Anytime_Dstar(object): return self.rhs[xi] def updatecost(self, range_changed=None, new=None, old=None, mode=False): - # scan graph for changed cost, if cost is changed update it + # scan graph for changed Cost, if Cost is changed update it CHANGED = set() for xi in self.CLOSED: if isinbound(old, xi, mode) or isinbound(new, xi, mode): @@ -100,8 +100,8 @@ class Anytime_Dstar(object): return CHANGED # def updateGraphCost(self, range_changed=None, new=None, old=None, mode=False): - # # TODO scan graph for changed cost, if cost is changed update it - # # make the graph cost via vectorization + # # TODO scan graph for changed Cost, if Cost is changed update it + # # make the graph Cost via vectorization # CHANGED = set() # Allnodes = np.array(list(self.CLOSED)) # isChanged = isinbound(old, Allnodes, mode = mode, isarray = True) & \ @@ -112,7 +112,7 @@ class Anytime_Dstar(object): # CHANGED.add(xi) # self.CHILDREN[xi] = set(children(self, xi)) # for xj in self.CHILDREN: - # self.COST[xi][xj] = cost(self, xi, xj) + # self.COST[xi][xj] = Cost(self, xi, xj) # --------------main functions for Anytime D star @@ -177,7 +177,7 @@ class Anytime_Dstar(object): # islargelychanged = True self.Path = [] - # update cost with changed environment + # update Cost with changed environment if ischanged: # CHANGED = self.updatecost(True, new2, old2, mode='obb') CHANGED = self.updatecost(True, new2, old2) @@ -207,10 +207,10 @@ class Anytime_Dstar(object): def path(self, s_start=None): '''After ComputeShortestPath() - returns, one can then follow a shortest path from s_start to - s_goal by always moving from the current vertex s, starting - at s_start. , to any successor s' that minimizes c(s,s') + g(s') - until s_goal is reached (ties can be broken arbitrarily).''' + returns, one can then follow a shortest path from x_start to + x_goal by always moving from the current vertex s, starting + at x_start. , to any successor s' that minimizes c(s,s') + g(s') + until x_goal is reached (ties can be broken arbitrarily).''' path = [] s_goal = self.xt s = self.x0 diff --git a/Search-based Planning/Search_3D/Dstar3D.py b/Search-based Planning/Search_3D/Dstar3D.py index 09d4cea..2953e16 100644 --- a/Search-based Planning/Search_3D/Dstar3D.py +++ b/Search-based Planning/Search_3D/Dstar3D.py @@ -175,7 +175,7 @@ class D_star(object): sparent = self.b[self.x0] else: sparent = self.b[s] - # if there is a change of cost, or a collision. + # if there is a change of Cost, or a collision. if cost(self, s, sparent) == np.inf: self.modify(s) continue diff --git a/Search-based Planning/Search_3D/DstarLite3D.py b/Search-based Planning/Search_3D/DstarLite3D.py index d328f64..278fb60 100644 --- a/Search-based Planning/Search_3D/DstarLite3D.py +++ b/Search-based Planning/Search_3D/DstarLite3D.py @@ -41,7 +41,7 @@ class D_star_Lite(object): # init children set: self.CHILDREN = {} - # init cost set + # init Cost set self.COST = defaultdict(lambda: defaultdict(dict)) # for visualization @@ -51,7 +51,7 @@ class D_star_Lite(object): self.done = False def updatecost(self, range_changed=None, new=None, old=None, mode=False): - # scan graph for changed cost, if cost is changed update it + # scan graph for changed Cost, if Cost is changed update it CHANGED = set() for xi in self.CLOSED: if isinbound(old, xi, mode) or isinbound(new, xi, mode): @@ -100,7 +100,7 @@ class D_star_Lite(object): def UpdateVertex(self, u): # if still in the hunt - if not getDist(self.xt, u) <= self.env.resolution: # originally: u != s_goal + if not getDist(self.xt, u) <= self.env.resolution: # originally: u != x_goal if u in self.CHILDREN and len(self.CHILDREN[u]) == 0: self.rhs[u] = np.inf else: @@ -147,7 +147,7 @@ class D_star_Lite(object): ischanged = False self.V = set() while getDist(self.x0, self.xt) > 2*self.env.resolution: - #---------------------------------- at specific times, the environment is changed and cost is updated + #---------------------------------- at specific times, the environment is changed and Cost is updated if t % 2 == 0: new0,old0 = self.env.move_block(a=[-0.1, 0, -0.2], s=0.5, block_to_move=1, mode='translation') new1,old1 = self.env.move_block(a=[0, 0, -0.2], s=0.5, block_to_move=0, mode='translation') @@ -163,9 +163,9 @@ class D_star_Lite(object): self.x0 = children_new[np.argmin([self.getcost(self.x0,s_p) + self.getg(s_p) for s_p in children_new])] # TODO add the moving robot position codes self.env.start = self.x0 - # ---------------------------------- if any cost changed, update km, reset slast, + # ---------------------------------- if any Cost changed, update km, reset slast, # for all directed edgees (u,v) with chaged edge costs, - # update the edge cost c(u,v) and update vertex u. then replan + # update the edge Cost c(u,v) and update vertex u. then replan if ischanged: self.km += heuristic_fun(self, self.x0, s_last) s_last = self.x0 @@ -186,10 +186,10 @@ class D_star_Lite(object): def path(self, s_start=None): '''After ComputeShortestPath() - returns, one can then follow a shortest path from s_start to - s_goal by always moving from the current vertex s, starting - at s_start. , to any successor s' that minimizes c(s,s') + g(s') - until s_goal is reached (ties can be broken arbitrarily).''' + returns, one can then follow a shortest path from x_start to + x_goal by always moving from the current vertex s, starting + at x_start. , to any successor s' that minimizes c(s,s') + g(s') + until x_goal is reached (ties can be broken arbitrarily).''' path = [] s_goal = self.xt if not s_start: diff --git a/Search-based Planning/Search_3D/LP_Astar3D.py b/Search-based Planning/Search_3D/LP_Astar3D.py index a4df422..497fbb1 100644 --- a/Search-based Planning/Search_3D/LP_Astar3D.py +++ b/Search-based Planning/Search_3D/LP_Astar3D.py @@ -48,7 +48,7 @@ class Lifelong_Astar(object): self.CHILDREN = {} self.getCHILDRENset() - # initialize cost list + # initialize Cost list self.COST = {} _ = self.costset() @@ -58,7 +58,7 @@ class Lifelong_Astar(object): children = self.CHILDREN[xi] toUpdate = [self.cost(xj,xi) for xj in children] if xi in self.COST: - # if the old cost not equal to new cost + # if the old Cost not equal to new Cost diff = np.not_equal(self.COST[xi],toUpdate) cd = np.array(children)[diff] for i in cd: @@ -126,7 +126,7 @@ class Lifelong_Astar(object): j = x nei = self.CHILDREN[x] gset = [self.g[xi] for xi in nei] - # collision check and make g cost inf + # collision check and make g Cost inf for i in range(len(nei)): if self.isCollide(nei[i],j)[0]: gset[i] = np.inf diff --git a/Search-based Planning/Search_3D/utils3D.py b/Search-based Planning/Search_3D/utils3D.py index b421f35..116282f 100644 --- a/Search-based Planning/Search_3D/utils3D.py +++ b/Search-based Planning/Search_3D/utils3D.py @@ -336,7 +336,7 @@ def cost(initparams, i, j, dist=None, settings='Euclidean'): def initcost(initparams): - # initialize cost dictionary, could be modifed lateron + # initialize Cost dictionary, could be modifed lateron c = defaultdict(lambda: defaultdict(dict)) # two key dicionary for xi in initparams.X: cdren = children(initparams, xi)