fix scanning error (#339)

This commit is contained in:
Atsushi Sakai
2020-06-08 21:43:37 +09:00
committed by GitHub
parent a36ddb4cff
commit fa1585d880
11 changed files with 476 additions and 381 deletions

View File

@@ -27,7 +27,8 @@ class RTree(object):
# Class to represent the explicit tree created
# while sampling through the state space
def __init__(self, start=None, lowerLimit=None, upperLimit=None, resolution=1.0):
def __init__(self, start=None, lowerLimit=None, upperLimit=None,
resolution=1.0):
if upperLimit is None:
upperLimit = [10, 10]
@@ -96,10 +97,11 @@ class RTree(object):
def real_world_to_node_id(self, real_coord):
# first convert the given coordinates to grid space and then
# convert the grid space coordinates to a unique node id
return self.grid_coordinate_to_node_id(self.real_coords_to_grid_coord(real_coord))
return self.grid_coordinate_to_node_id(
self.real_coords_to_grid_coord(real_coord))
def grid_coord_to_real_world_coord(self, coord):
# This function smaps a grid coordinate in discrete space
# This function maps a grid coordinate in discrete space
# to a configuration in the full configuration space
config = [0] * self.dimension
for i in range(0, len(coord)):
@@ -126,7 +128,8 @@ class RTree(object):
def node_id_to_real_world_coord(self, nid):
# This function maps a node in discrete space to a configuration
# in the full configuration space
return self.grid_coord_to_real_world_coord(self.node_id_to_grid_coord(nid))
return self.grid_coord_to_real_world_coord(
self.node_id_to_grid_coord(nid))
class BITStar(object):
@@ -137,9 +140,9 @@ class BITStar(object):
self.start = start
self.goal = goal
self.minrand = randArea[0]
self.maxrand = randArea[1]
self.maxIter = maxIter
self.min_rand = randArea[0]
self.max_rand = randArea[1]
self.max_iIter = maxIter
self.obstacleList = obstacleList
self.startId = None
self.goalId = None
@@ -186,18 +189,19 @@ class BITStar(object):
[(self.start[1] + self.goal[1]) / 2.0], [0]])
a1 = np.array([[(self.goal[0] - self.start[0]) / cMin],
[(self.goal[1] - self.start[1]) / cMin], [0]])
etheta = math.atan2(a1[1], a1[0])
# first column of idenity matrix transposed
eTheta = math.atan2(a1[1], a1[0])
# first column of identity matrix transposed
id1_t = np.array([1.0, 0.0, 0.0]).reshape(1, 3)
M = np.dot(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)
[1.0, 1.0, np.linalg.det(U) * np.linalg.det(np.transpose(Vh))])),
Vh)
self.samples.update(self.informed_sample(
200, cBest, cMin, xCenter, C))
return etheta, cMin, xCenter, C, cBest
return eTheta, cMin, xCenter, C, cBest
def setup_sample(self, iterations, foundGoal, cMin, xCenter, C, cBest):
@@ -228,18 +232,19 @@ class BITStar(object):
def plan(self, animation=True):
etheta, cMin, xCenter, C, cBest = self.setup_planning()
eTheta, cMin, xCenter, C, cBest = self.setup_planning()
iterations = 0
foundGoal = False
# run until done
while iterations < self.maxIter:
while iterations < self.max_iIter:
cBest = self.setup_sample(iterations,
foundGoal, cMin, xCenter, C, cBest)
# expand the best vertices until an edge is better than the vertex
# this is done because the vertex cost represents the lower bound
# on the edge cost
while self.best_vertex_queue_value() <= self.best_edge_queue_value():
while self.best_vertex_queue_value() <= \
self.best_edge_queue_value():
self.expand_vertex(self.best_in_vertex_queue())
# add the best edge to the tree
@@ -247,11 +252,17 @@ class BITStar(object):
self.edge_queue.remove(bestEdge)
# Check if this can improve the current solution
estimatedCostOfVertex = self.g_scores[bestEdge[0]] + self.compute_distance_cost(
bestEdge[0], bestEdge[1]) + self.compute_heuristic_cost(bestEdge[1], self.goalId)
estimatedCostOfEdge = self.compute_distance_cost(self.startId, bestEdge[0]) + self.compute_heuristic_cost(
bestEdge[0], bestEdge[1]) + self.compute_heuristic_cost(bestEdge[1], self.goalId)
actualCostOfEdge = self.g_scores[bestEdge[0]] + self.compute_distance_cost(bestEdge[0], bestEdge[1])
estimatedCostOfVertex = self.g_scores[bestEdge[
0]] + self.compute_distance_cost(
bestEdge[0], bestEdge[1]) + self.compute_heuristic_cost(
bestEdge[1], self.goalId)
estimatedCostOfEdge = self.compute_distance_cost(
self.startId, bestEdge[0]) + self.compute_heuristic_cost(
bestEdge[0], bestEdge[1]) + self.compute_heuristic_cost(
bestEdge[1], self.goalId)
actualCostOfEdge = self.g_scores[
bestEdge[0]] + self.compute_distance_cost(
bestEdge[0], bestEdge[1])
f1 = estimatedCostOfVertex < self.g_scores[self.goalId]
f2 = estimatedCostOfEdge < self.g_scores[self.goalId]
@@ -277,10 +288,12 @@ class BITStar(object):
try:
del self.samples[bestEdge[1]]
except KeyError:
# invalid sample key
pass
eid = self.tree.add_vertex(nextCoord)
self.vertex_queue.append(eid)
if eid == self.goalId or bestEdge[0] == self.goalId or bestEdge[1] == self.goalId:
if eid == self.goalId or bestEdge[0] == self.goalId or \
bestEdge[1] == self.goalId:
print("Goal found")
foundGoal = True
@@ -288,14 +301,18 @@ class BITStar(object):
g_score = self.compute_distance_cost(
bestEdge[0], bestEdge[1])
self.g_scores[bestEdge[1]] = g_score + self.g_scores[bestEdge[0]]
self.f_scores[bestEdge[1]] = g_score + self.compute_heuristic_cost(bestEdge[1], self.goalId)
self.g_scores[bestEdge[1]] = g_score + self.g_scores[
bestEdge[0]]
self.f_scores[
bestEdge[1]] = g_score + self.compute_heuristic_cost(
bestEdge[1], self.goalId)
self.update_graph()
# visualize new edge
if animation:
self.draw_graph(xCenter=xCenter, cBest=cBest,
cMin=cMin, etheta=etheta, samples=self.samples.values(),
cMin=cMin, eTheta=eTheta,
samples=self.samples.values(),
start=firstCoord, end=secondCoord)
self.remove_queue(lastEdge, bestEdge)
@@ -330,7 +347,8 @@ class BITStar(object):
for edge in self.edge_queue:
if edge[1] == bestEdge[1]:
dist_cost = self.compute_distance_cost(edge[1], bestEdge[1])
if self.g_scores[edge[1]] + dist_cost >= self.g_scores[self.goalId]:
if self.g_scores[edge[1]] + dist_cost >= \
self.g_scores[self.goalId]:
if (lastEdge, bestEdge[1]) in self.edge_queue:
self.edge_queue.remove(
(lastEdge, bestEdge[1]))
@@ -338,8 +356,9 @@ class BITStar(object):
def connect(self, start, end):
# A function which attempts to extend from a start coordinates
# to goal coordinates
steps = int(self.compute_distance_cost(self.tree.real_world_to_node_id(
start), self.tree.real_world_to_node_id(end)) * 10)
steps = int(self.compute_distance_cost(
self.tree.real_world_to_node_id(start),
self.tree.real_world_to_node_id(end)) * 10)
x = np.linspace(start[0], end[0], num=steps)
y = np.linspace(start[1], end[1], num=steps)
for i in range(len(x)):
@@ -409,8 +428,8 @@ class BITStar(object):
return np.array([[sample[0]], [sample[1]], [0]])
def sample_free_space(self):
rnd = [random.uniform(self.minrand, self.maxrand),
random.uniform(self.minrand, self.maxrand)]
rnd = [random.uniform(self.min_rand, self.max_rand),
random.uniform(self.min_rand, self.max_rand)]
return rnd
@@ -418,7 +437,8 @@ class BITStar(object):
if len(self.vertex_queue) == 0:
return float('inf')
values = [self.g_scores[v]
+ self.compute_heuristic_cost(v, self.goalId) for v in self.vertex_queue]
+ self.compute_heuristic_cost(v, self.goalId) for v in
self.vertex_queue]
values.sort()
return values[0]
@@ -427,21 +447,25 @@ class BITStar(object):
return float('inf')
# return the best value in the queue by score g_tau[v] + c(v,x) + h(x)
values = [self.g_scores[e[0]] + self.compute_distance_cost(e[0], e[1])
+ self.compute_heuristic_cost(e[1], self.goalId) for e in self.edge_queue]
+ self.compute_heuristic_cost(e[1], self.goalId) for e in
self.edge_queue]
values.sort(reverse=True)
return values[0]
def best_in_vertex_queue(self):
# return the best value in the vertex queue
v_plus_vals = [(v, self.g_scores[v] + self.compute_heuristic_cost(v, self.goalId))
for v in self.vertex_queue]
v_plus_vals = sorted(v_plus_vals, key=lambda x: x[1])
# print(v_plus_vals)
return v_plus_vals[0][0]
v_plus_values = [(v, self.g_scores[v] +
self.compute_heuristic_cost(v, self.goalId))
for v in self.vertex_queue]
v_plus_values = sorted(v_plus_values, key=lambda x: x[1])
# print(v_plus_values)
return v_plus_values[0][0]
def best_in_edge_queue(self):
e_and_values = [(e[0], e[1], self.g_scores[e[0]] + self.compute_distance_cost(
e[0], e[1]) + self.compute_heuristic_cost(e[1], self.goalId)) for e in self.edge_queue]
e_and_values = [
(e[0], e[1], self.g_scores[e[0]] + self.compute_distance_cost(
e[0], e[1]) + self.compute_heuristic_cost(e[1], self.goalId))
for e in self.edge_queue]
e_and_values = sorted(e_and_values, key=lambda x: x[2])
return e_and_values[0][0], e_and_values[0][1]
@@ -454,18 +478,19 @@ class BITStar(object):
# get the nearest value in vertex for every one in samples where difference is
# less than the radius
neigbors = []
for sid, scoord in self.samples.items():
scoord = np.array(scoord)
if np.linalg.norm(scoord - currCoord, 2) <= self.r and sid != vid:
neigbors.append((sid, scoord))
neighbors = []
for sid, s_coord in self.samples.items():
s_coord = np.array(s_coord)
if np.linalg.norm(s_coord - currCoord, 2) <= self.r and sid != vid:
neighbors.append((sid, s_coord))
# add an edge to the edge queue is the path might improve the solution
for neighbor in neigbors:
for neighbor in neighbors:
sid = neighbor[0]
h_cost = self.compute_heuristic_cost(sid, self.goalId)
estimated_f_score = self.compute_distance_cost(
self.startId, vid) + h_cost + self.compute_distance_cost(vid, sid)
self.startId, vid) + h_cost + self.compute_distance_cost(vid,
sid)
if estimated_f_score < self.g_scores[self.goalId]:
self.edge_queue.append((vid, sid))
@@ -476,17 +501,21 @@ class BITStar(object):
if vid not in self.old_vertices:
neighbors = []
for v, edges in self.tree.vertices.items():
if v != vid and (v, vid) not in self.edge_queue and (vid, v) not in self.edge_queue:
if v != vid and (v, vid) not in self.edge_queue and \
(vid, v) not in self.edge_queue:
v_coord = self.tree.node_id_to_real_world_coord(v)
if np.linalg.norm(currCoord - v_coord, 2) <= self.r:
neighbors.append((vid, v_coord))
for neighbor in neighbors:
sid = neighbor[0]
estimated_f_score = self.compute_distance_cost(self.startId, vid) + self.compute_distance_cost(
estimated_f_score = self.compute_distance_cost(
self.startId, vid) + self.compute_distance_cost(
vid, sid) + self.compute_heuristic_cost(sid, self.goalId)
if estimated_f_score < self.g_scores[self.goalId] and (
self.g_scores[vid] + self.compute_distance_cost(vid, sid)) < self.g_scores[sid]:
self.g_scores[vid] +
self.compute_distance_cost(vid, sid)) < \
self.g_scores[sid]:
self.edge_queue.append((vid, sid))
def update_graph(self):
@@ -511,37 +540,40 @@ class BITStar(object):
# find a non visited successor to the current node
successors = self.tree.vertices[currId]
for succesor in successors:
if succesor in closedSet:
for successor in successors:
if successor in closedSet:
continue
else:
# claculate tentative g score
# calculate tentative g score
g_score = self.g_scores[currId] + \
self.compute_distance_cost(currId, succesor)
if succesor not in openSet:
self.compute_distance_cost(currId, successor)
if successor not in openSet:
# add the successor to open set
openSet.append(succesor)
elif g_score >= self.g_scores[succesor]:
openSet.append(successor)
elif g_score >= self.g_scores[successor]:
continue
# update g and f scores
self.g_scores[succesor] = g_score
self.f_scores[succesor] = g_score + self.compute_heuristic_cost(succesor, self.goalId)
self.g_scores[successor] = g_score
self.f_scores[
successor] = g_score + self.compute_heuristic_cost(
successor, self.goalId)
# store the parent and child
self.nodes[succesor] = currId
self.nodes[successor] = currId
def draw_graph(self, xCenter=None, cBest=None, cMin=None, etheta=None,
def draw_graph(self, xCenter=None, cBest=None, cMin=None, eTheta=None,
samples=None, start=None, end=None):
plt.clf()
# for stopping simulation with the esc key.
plt.gcf().canvas.mpl_connect('key_release_event',
lambda event: [exit(0) if event.key == 'escape' else None])
plt.gcf().canvas.mpl_connect(
'key_release_event',
lambda event: [exit(0) if event.key == 'escape' else None])
for rnd in samples:
if rnd is not None:
plt.plot(rnd[0], rnd[1], "^k")
if cBest != float('inf'):
self.plot_ellipse(xCenter, cBest, cMin, etheta)
self.plot_ellipse(xCenter, cBest, cMin, eTheta)
if start is not None and end is not None:
plt.plot([start[0], start[1]], [end[0], end[1]], "-g")
@@ -556,11 +588,11 @@ class BITStar(object):
plt.pause(0.01)
@staticmethod
def plot_ellipse(xCenter, cBest, cMin, etheta): # pragma: no cover
def plot_ellipse(xCenter, cBest, cMin, eTheta): # pragma: no cover
a = math.sqrt(cBest ** 2 - cMin ** 2) / 2.0
b = cBest / 2.0
angle = math.pi / 2.0 - etheta
angle = math.pi / 2.0 - eTheta
cx = xCenter[0]
cy = xCenter[1]

View File

@@ -17,7 +17,7 @@ show_animation = True
class BidirectionalAStarPlanner:
def __init__(self, ox, oy, reso, rr):
def __init__(self, ox, oy, resolution, rr):
"""
Initialize grid map for a star planning
@@ -27,21 +27,24 @@ class BidirectionalAStarPlanner:
rr: robot radius[m]
"""
self.reso = reso
self.min_x, self.min_y = None, None
self.max_x, self.max_y = None, None
self.x_width, self.y_width, self.obstacle_map = None, None, None
self.resolution = resolution
self.rr = rr
self.calc_obstacle_map(ox, oy)
self.motion = self.get_motion_model()
class Node:
def __init__(self, x, y, cost, pind):
def __init__(self, x, y, cost, parent_index):
self.x = x # index of grid
self.y = y # index of grid
self.cost = cost
self.pind = pind
self.parent_index = parent_index
def __str__(self):
return str(self.x) + "," + str(self.y) + "," + str(
self.cost) + "," + str(self.pind)
self.cost) + "," + str(self.parent_index)
def planning(self, sx, sy, gx, gy):
"""
@@ -58,18 +61,19 @@ class BidirectionalAStarPlanner:
ry: y position list of the final path
"""
nstart = self.Node(self.calc_xyindex(sx, self.minx),
self.calc_xyindex(sy, self.miny), 0.0, -1)
ngoal = self.Node(self.calc_xyindex(gx, self.minx),
self.calc_xyindex(gy, self.miny), 0.0, -1)
start_node = self.Node(self.calc_xy_index(sx, self.min_x),
self.calc_xy_index(sy, self.min_y), 0.0, -1)
goal_node = self.Node(self.calc_xy_index(gx, self.min_x),
self.calc_xy_index(gy, self.min_y), 0.0, -1)
open_set_A, closed_set_A = dict(), dict()
open_set_B, closed_set_B = dict(), dict()
open_set_A[self.calc_grid_index(nstart)] = nstart
open_set_B[self.calc_grid_index(ngoal)] = ngoal
open_set_A[self.calc_grid_index(start_node)] = start_node
open_set_B[self.calc_grid_index(goal_node)] = goal_node
current_A = nstart
current_B = ngoal
current_A = start_node
current_B = goal_node
meet_point_A, meet_point_B = None, None
while 1:
if len(open_set_A) == 0:
@@ -94,22 +98,23 @@ class BidirectionalAStarPlanner:
# show graph
if show_animation: # pragma: no cover
plt.plot(self.calc_grid_position(current_A.x, self.minx),
self.calc_grid_position(current_A.y, self.miny), "xc")
plt.plot(self.calc_grid_position(current_B.x, self.minx),
self.calc_grid_position(current_B.y, self.miny), "xc")
plt.plot(self.calc_grid_position(current_A.x, self.min_x),
self.calc_grid_position(current_A.y, self.min_y),
"xc")
plt.plot(self.calc_grid_position(current_B.x, self.min_x),
self.calc_grid_position(current_B.y, self.min_y),
"xc")
# for stopping simulation with the esc key.
plt.gcf().canvas.mpl_connect('key_release_event',
lambda event:
[exit(0) if event.key == 'escape'
else None])
plt.gcf().canvas.mpl_connect(
'key_release_event',
lambda event: [exit(0) if event.key == 'escape' else None])
if len(closed_set_A.keys()) % 10 == 0:
plt.pause(0.001)
if current_A.x == current_B.x and current_A.y == current_B.y:
print("Found goal")
meetpointA = current_A
meetpointB = current_B
meet_point_A = current_A
meet_point_B = current_B
break
# Remove the item from the open set
@@ -158,7 +163,7 @@ class BidirectionalAStarPlanner:
open_set_B[n_ids[1]] = c_nodes[1]
rx, ry = self.calc_final_bidirectional_path(
meetpointA, meetpointB, closed_set_A, closed_set_B)
meet_point_A, meet_point_B, closed_set_A, closed_set_B)
return rx, ry
@@ -175,16 +180,16 @@ class BidirectionalAStarPlanner:
return rx, ry
def calc_final_path(self, ngoal, closedset):
def calc_final_path(self, goal_node, closed_set):
# generate final course
rx, ry = [self.calc_grid_position(ngoal.x, self.minx)], [
self.calc_grid_position(ngoal.y, self.miny)]
pind = ngoal.parent_index
while pind != -1:
n = closedset[pind]
rx.append(self.calc_grid_position(n.x, self.minx))
ry.append(self.calc_grid_position(n.y, self.miny))
pind = n.parent_index
rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], \
[self.calc_grid_position(goal_node.y, self.min_y)]
parent_index = goal_node.parent_index
while parent_index != -1:
n = closed_set[parent_index]
rx.append(self.calc_grid_position(n.x, self.min_x))
ry.append(self.calc_grid_position(n.y, self.min_y))
parent_index = n.parent_index
return rx, ry
@@ -210,69 +215,69 @@ class BidirectionalAStarPlanner:
f_cost = g_cost + h_cost
return f_cost
def calc_grid_position(self, index, minp):
def calc_grid_position(self, index, min_position):
"""
calc grid position
:param index:
:param minp:
:param min_position:
:return:
"""
pos = index * self.reso + minp
pos = index * self.resolution + min_position
return pos
def calc_xyindex(self, position, min_pos):
return round((position - min_pos) / self.reso)
def calc_xy_index(self, position, min_pos):
return round((position - min_pos) / self.resolution)
def calc_grid_index(self, node):
return (node.y - self.miny) * self.xwidth + (node.x - self.minx)
return (node.y - self.min_y) * self.x_width + (node.x - self.min_x)
def verify_node(self, node):
px = self.calc_grid_position(node.x, self.minx)
py = self.calc_grid_position(node.y, self.miny)
px = self.calc_grid_position(node.x, self.min_x)
py = self.calc_grid_position(node.y, self.min_y)
if px < self.minx:
if px < self.min_x:
return False
elif py < self.miny:
elif py < self.min_y:
return False
elif px >= self.maxx:
elif px >= self.max_x:
return False
elif py >= self.maxy:
elif py >= self.max_y:
return False
# collision check
if self.obmap[node.x][node.y]:
if self.obstacle_map[node.x][node.y]:
return False
return True
def calc_obstacle_map(self, ox, oy):
self.minx = round(min(ox))
self.miny = round(min(oy))
self.maxx = round(max(ox))
self.maxy = round(max(oy))
print("min_x:", self.minx)
print("min_y:", self.miny)
print("max_x:", self.maxx)
print("max_y:", self.maxy)
self.min_x = round(min(ox))
self.min_y = round(min(oy))
self.max_x = round(max(ox))
self.max_y = round(max(oy))
print("min_x:", self.min_x)
print("min_y:", self.min_y)
print("max_x:", self.max_x)
print("max_y:", self.max_y)
self.xwidth = round((self.maxx - self.minx) / self.reso)
self.ywidth = round((self.maxy - self.miny) / self.reso)
print("x_width:", self.xwidth)
print("y_width:", self.ywidth)
self.x_width = round((self.max_x - self.min_x) / self.resolution)
self.y_width = round((self.max_y - self.min_y) / self.resolution)
print("x_width:", self.x_width)
print("y_width:", self.y_width)
# obstacle map generation
self.obmap = [[False for _ in range(self.ywidth)]
for _ in range(self.xwidth)]
for ix in range(self.xwidth):
x = self.calc_grid_position(ix, self.minx)
for iy in range(self.ywidth):
y = self.calc_grid_position(iy, self.miny)
self.obstacle_map = [[False for _ in range(self.y_width)]
for _ in range(self.x_width)]
for ix in range(self.x_width):
x = self.calc_grid_position(ix, self.min_x)
for iy in range(self.y_width):
y = self.calc_grid_position(iy, self.min_y)
for iox, ioy in zip(ox, oy):
d = math.hypot(iox - x, ioy - y)
if d <= self.rr:
self.obmap[ix][iy] = True
self.obstacle_map[ix][iy] = True
break
@staticmethod

View File

@@ -17,7 +17,7 @@ show_animation = True
class BidirectionalBreadthFirstSearchPlanner:
def __init__(self, ox, oy, reso, rr):
def __init__(self, ox, oy, resolution, rr):
"""
Initialize grid map for bfs planning
@@ -27,22 +27,25 @@ class BidirectionalBreadthFirstSearchPlanner:
rr: robot radius[m]
"""
self.reso = reso
self.min_x, self.min_y = None, None
self.max_x, self.max_y = None, None
self.x_width, self.y_width, self.obstacle_map = None, None, None
self.resolution = resolution
self.rr = rr
self.calc_obstacle_map(ox, oy)
self.motion = self.get_motion_model()
class Node:
def __init__(self, x, y, cost, pind, parent):
def __init__(self, x, y, cost, parent_index, parent):
self.x = x # index of grid
self.y = y # index of grid
self.cost = cost
self.pind = pind
self.parent_index = parent_index
self.parent = parent
def __str__(self):
return str(self.x) + "," + str(self.y) + "," + str(
self.cost) + "," + str(self.pind)
self.cost) + "," + str(self.parent_index)
def planning(self, sx, sy, gx, gy):
"""
@@ -59,15 +62,19 @@ class BidirectionalBreadthFirstSearchPlanner:
ry: y position list of the final path
"""
nstart = self.Node(self.calc_xyindex(sx, self.minx),
self.calc_xyindex(sy, self.miny), 0.0, -1, None)
ngoal = self.Node(self.calc_xyindex(gx, self.minx),
self.calc_xyindex(gy, self.miny), 0.0, -1, None)
start_node = self.Node(self.calc_xy_index(sx, self.min_x),
self.calc_xy_index(sy, self.min_y), 0.0, -1,
None)
goal_node = self.Node(self.calc_xy_index(gx, self.min_x),
self.calc_xy_index(gy, self.min_y), 0.0, -1,
None)
open_set_A, closed_set_A = dict(), dict()
open_set_B, closed_set_B = dict(), dict()
open_set_B[self.calc_grid_index(ngoal)] = ngoal
open_set_A[self.calc_grid_index(nstart)] = nstart
open_set_B[self.calc_grid_index(goal_node)] = goal_node
open_set_A[self.calc_grid_index(start_node)] = start_node
meet_point_A, meet_point_B = None, None
while 1:
if len(open_set_A) == 0:
@@ -89,28 +96,29 @@ class BidirectionalBreadthFirstSearchPlanner:
# show graph
if show_animation: # pragma: no cover
plt.plot(self.calc_grid_position(current_A.x, self.minx),
self.calc_grid_position(current_A.y, self.miny), "xc")
plt.plot(self.calc_grid_position(current_B.x, self.minx),
self.calc_grid_position(current_B.y, self.miny), "xc")
plt.plot(self.calc_grid_position(current_A.x, self.min_x),
self.calc_grid_position(current_A.y, self.min_y),
"xc")
plt.plot(self.calc_grid_position(current_B.x, self.min_x),
self.calc_grid_position(current_B.y, self.min_y),
"xc")
# for stopping simulation with the esc key.
plt.gcf().canvas.mpl_connect('key_release_event',
lambda event:
[exit(0) if
event.key == 'escape' else None])
plt.gcf().canvas.mpl_connect(
'key_release_event',
lambda event: [exit(0) if event.key == 'escape' else None])
if len(closed_set_A.keys()) % 10 == 0:
plt.pause(0.001)
if c_id_A in closed_set_B:
print("Find goal")
meetpointA = closed_set_A[c_id_A]
meetpointB = closed_set_B[c_id_A]
meet_point_A = closed_set_A[c_id_A]
meet_point_B = closed_set_B[c_id_A]
break
elif c_id_B in closed_set_A:
print("Find goal")
meetpointA = closed_set_A[c_id_B]
meetpointB = closed_set_B[c_id_B]
meet_point_A = closed_set_A[c_id_B]
meet_point_B = closed_set_B[c_id_B]
break
# expand_grid search grid based on motion model
@@ -137,20 +145,18 @@ class BidirectionalBreadthFirstSearchPlanner:
if not self.verify_node(node_B):
breakB = True
if (n_id_A not in closed_set_A) and (n_id_A not in
open_set_A) and (not
breakA):
if (n_id_A not in closed_set_A) and \
(n_id_A not in open_set_A) and (not breakA):
node_A.parent = current_A
open_set_A[n_id_A] = node_A
if (n_id_B not in closed_set_B) and (n_id_B not in
open_set_B) and (not
breakB):
if (n_id_B not in closed_set_B) and \
(n_id_B not in open_set_B) and (not breakB):
node_B.parent = current_B
open_set_B[n_id_B] = node_B
rx, ry = self.calc_final_path_bidir(
meetpointA, meetpointB, closed_set_A, closed_set_B)
meet_point_A, meet_point_B, closed_set_A, closed_set_B)
return rx, ry
# takes both set and meeting nodes and calculate optimal path
@@ -166,81 +172,81 @@ class BidirectionalBreadthFirstSearchPlanner:
return rx, ry
def calc_final_path(self, ngoal, closedset):
def calc_final_path(self, goal_node, closed_set):
# generate final course
rx, ry = [self.calc_grid_position(ngoal.x, self.minx)], [
self.calc_grid_position(ngoal.y, self.miny)]
n = closedset[ngoal.parent_index]
rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], [
self.calc_grid_position(goal_node.y, self.min_y)]
n = closed_set[goal_node.parent_index]
while n is not None:
rx.append(self.calc_grid_position(n.x, self.minx))
ry.append(self.calc_grid_position(n.y, self.miny))
rx.append(self.calc_grid_position(n.x, self.min_x))
ry.append(self.calc_grid_position(n.y, self.min_y))
n = n.parent
return rx, ry
def calc_grid_position(self, index, minp):
def calc_grid_position(self, index, min_position):
"""
calc grid position
:param index:
:param minp:
:param min_position:
:return:
"""
pos = index * self.reso + minp
pos = index * self.resolution + min_position
return pos
def calc_xyindex(self, position, min_pos):
return round((position - min_pos) / self.reso)
def calc_xy_index(self, position, min_pos):
return round((position - min_pos) / self.resolution)
def calc_grid_index(self, node):
return (node.y - self.miny) * self.xwidth + (node.x - self.minx)
return (node.y - self.min_y) * self.x_width + (node.x - self.min_x)
def verify_node(self, node):
px = self.calc_grid_position(node.x, self.minx)
py = self.calc_grid_position(node.y, self.miny)
px = self.calc_grid_position(node.x, self.min_x)
py = self.calc_grid_position(node.y, self.min_y)
if px < self.minx:
if px < self.min_x:
return False
elif py < self.miny:
elif py < self.min_y:
return False
elif px >= self.maxx:
elif px >= self.max_x:
return False
elif py >= self.maxy:
elif py >= self.max_y:
return False
# collision check
if self.obmap[node.x][node.y]:
if self.obstacle_map[node.x][node.y]:
return False
return True
def calc_obstacle_map(self, ox, oy):
self.minx = round(min(ox))
self.miny = round(min(oy))
self.maxx = round(max(ox))
self.maxy = round(max(oy))
print("min_x:", self.minx)
print("min_y:", self.miny)
print("max_x:", self.maxx)
print("max_y:", self.maxy)
self.min_x = round(min(ox))
self.min_y = round(min(oy))
self.max_x = round(max(ox))
self.max_y = round(max(oy))
print("min_x:", self.min_x)
print("min_y:", self.min_y)
print("max_x:", self.max_x)
print("max_y:", self.max_y)
self.xwidth = round((self.maxx - self.minx) / self.reso)
self.ywidth = round((self.maxy - self.miny) / self.reso)
print("x_width:", self.xwidth)
print("y_width:", self.ywidth)
self.x_width = round((self.max_x - self.min_x) / self.resolution)
self.y_width = round((self.max_y - self.min_y) / self.resolution)
print("x_width:", self.x_width)
print("y_width:", self.y_width)
# obstacle map generation
self.obmap = [[False for _ in range(self.ywidth)]
for _ in range(self.xwidth)]
for ix in range(self.xwidth):
x = self.calc_grid_position(ix, self.minx)
for iy in range(self.ywidth):
y = self.calc_grid_position(iy, self.miny)
self.obstacle_map = [[False for _ in range(self.y_width)]
for _ in range(self.x_width)]
for ix in range(self.x_width):
x = self.calc_grid_position(ix, self.min_x)
for iy in range(self.y_width):
y = self.calc_grid_position(iy, self.min_y)
for iox, ioy in zip(ox, oy):
d = math.hypot(iox - x, ioy - y)
if d <= self.rr:
self.obmap[ix][iy] = True
self.obstacle_map[ix][iy] = True
break
@staticmethod

View File

@@ -125,6 +125,7 @@ class DijkstraSearch:
if self.is_same_node_with_xy(node_x_list[i], node_y_list[i],
target_node):
return i
return None
@staticmethod
def is_same_node_with_xy(node_x, node_y, node_b):