mirror of
https://github.com/AtsushiSakai/PythonRobotics.git
synced 2026-02-11 04:45:24 -05:00
223 lines
5.1 KiB
Python
223 lines
5.1 KiB
Python
"""
|
|
|
|
Hybrid A* path planning
|
|
|
|
author: Atsushi Sakai (@Atsushi_twi)
|
|
|
|
"""
|
|
|
|
import sys
|
|
sys.path.append("../ReedsSheppPath/")
|
|
|
|
import math
|
|
import numpy as np
|
|
import scipy.spatial
|
|
import matplotlib.pyplot as plt
|
|
import reeds_shepp_path_planning as rs
|
|
import heapq
|
|
|
|
EXTEND_AREA = 5.0 # [m]
|
|
H_COST = 1.0
|
|
|
|
show_animation = True
|
|
|
|
|
|
class Node:
|
|
|
|
def __init__(self, xind, yind, yawind, direction, x, y, yaw, directions, steer, cost, pind):
|
|
# store kd-tree
|
|
self.xind = xind
|
|
self.yind = yind
|
|
self.yawind = yawind
|
|
self.direction = direction
|
|
self.xlist = x
|
|
self.ylist = y
|
|
self.yawlist = yaw
|
|
self.directionlist = directions
|
|
self.steer = steer
|
|
self.cost = cost
|
|
self.pind = pind
|
|
|
|
|
|
class KDTree:
|
|
"""
|
|
Nearest neighbor search class with KDTree
|
|
"""
|
|
|
|
def __init__(self, data):
|
|
# store kd-tree
|
|
self.tree = scipy.spatial.cKDTree(data)
|
|
|
|
def search(self, inp, k=1):
|
|
"""
|
|
Search NN
|
|
inp: input data, single frame or multi frame
|
|
"""
|
|
|
|
if len(inp.shape) >= 2: # multi input
|
|
index = []
|
|
dist = []
|
|
|
|
for i in inp.T:
|
|
idist, iindex = self.tree.query(i, k=k)
|
|
index.append(iindex)
|
|
dist.append(idist)
|
|
|
|
return index, dist
|
|
else:
|
|
dist, index = self.tree.query(inp, k=k)
|
|
return index, dist
|
|
|
|
def search_in_distance(self, inp, r):
|
|
"""
|
|
find points with in a distance r
|
|
"""
|
|
|
|
index = self.tree.query_ball_point(inp, r)
|
|
return index
|
|
|
|
|
|
class Config:
|
|
|
|
def __init__(self, ox, oy, xyreso, yawreso):
|
|
min_x_m = min(ox) - EXTEND_AREA
|
|
min_y_m = min(oy) - EXTEND_AREA
|
|
max_x_m = max(ox) + EXTEND_AREA
|
|
max_y_m = max(oy) + EXTEND_AREA
|
|
|
|
ox.append(min_x_m)
|
|
oy.append(min_y_m)
|
|
ox.append(max_x_m)
|
|
oy.append(max_y_m)
|
|
|
|
self.minx = int(min_x_m / xyreso)
|
|
self.miny = int(min_y_m / xyreso)
|
|
self.maxx = int(max_x_m / xyreso)
|
|
self.maxy = int(max_y_m / xyreso)
|
|
|
|
self.xw = int(self.maxx - self.minx)
|
|
self.yw = int(self.maxy - self.miny)
|
|
|
|
self.minyaw = int(- math.pi / yawreso) - 1
|
|
self.maxyaw = int(math.pi / yawreso)
|
|
self.yaww = int(self.maxyaw - self.minyaw)
|
|
|
|
|
|
def analytic_expantion(current, ngoal, c, ox, oy, kdtree):
|
|
|
|
return False, None # no update
|
|
|
|
|
|
def hybrid_a_star_planning(start, goal, ox, oy, xyreso, yawreso):
|
|
"""
|
|
start
|
|
goal
|
|
ox: x position list of Obstacles [m]
|
|
oy: y position list of Obstacles [m]
|
|
xyreso: grid resolution [m]
|
|
yawreso: yaw angle resolution [rad]
|
|
"""
|
|
|
|
start[2], goal[2] = rs.pi_2_pi(start[2]), rs.pi_2_pi(goal[2])
|
|
tox, toy = ox[:], oy[:]
|
|
|
|
obkdtree = KDTree(np.vstack((tox, toy)).T)
|
|
|
|
c = Config(tox, toy, xyreso, yawreso)
|
|
|
|
nstart = Node(int(start[0] / xyreso), int(start[1] / xyreso), int(start[2] / yawreso),
|
|
True, [start[0]], [start[1]], [start[2]], [True], 0.0, 0.0, -1)
|
|
ngoal = Node(int(goal[0] / xyreso), int(goal[1] / xyreso), int(goal[2] / yawreso),
|
|
True, [goal[0]], [goal[1]], [goal[2]], [True], 0.0, 0.0, -1)
|
|
|
|
openList, closedList = {}, {}
|
|
h = []
|
|
# goalqueue = queue.PriorityQueue()
|
|
pq = []
|
|
openList[calc_index(nstart, c)] = nstart
|
|
heapq.heappush(pq, (calc_index(nstart, c), calc_cost(nstart, h, ngoal, c)))
|
|
|
|
while True:
|
|
if not openList:
|
|
print("Error: Cannot find path, No open set")
|
|
return [], [], []
|
|
|
|
c_id, cost = heapq.heappop(pq)
|
|
current = openList.pop(c_id)
|
|
closedList[c_id] = current
|
|
|
|
isupdated, fpath = analytic_expantion(
|
|
current, ngoal, c, ox, oy, obkdtree)
|
|
|
|
# print(current)
|
|
|
|
rx, ry, ryaw = [], [], []
|
|
|
|
return rx, ry, ryaw
|
|
|
|
|
|
def calc_cost(n, h, ngoal, c):
|
|
|
|
hcost = 1.0
|
|
|
|
return (n.cost + H_COST * hcost)
|
|
|
|
|
|
def calc_index(node, c):
|
|
ind = (node.yawind - c.minyaw) * c.xw * c.yw + \
|
|
(node.yind - c.miny) * c.xw + (node.xind - c.minx)
|
|
|
|
if ind <= 0:
|
|
print("Error(calc_index):", ind)
|
|
|
|
return ind
|
|
|
|
|
|
def main():
|
|
print("Start Hybrid A* planning")
|
|
|
|
ox, oy = [], []
|
|
|
|
for i in range(60):
|
|
ox.append(i)
|
|
oy.append(0.0)
|
|
for i in range(60):
|
|
ox.append(60.0)
|
|
oy.append(i)
|
|
for i in range(61):
|
|
ox.append(i)
|
|
oy.append(60.0)
|
|
for i in range(61):
|
|
ox.append(0.0)
|
|
oy.append(i)
|
|
for i in range(40):
|
|
ox.append(20.0)
|
|
oy.append(i)
|
|
for i in range(40):
|
|
ox.append(40.0)
|
|
oy.append(60.0 - i)
|
|
|
|
# Set Initial parameters
|
|
start = [10.0, 10.0, np.deg2rad(90.0)]
|
|
goal = [50.0, 50.0, np.deg2rad(-90.0)]
|
|
|
|
xyreso = 2.0
|
|
yawreso = np.deg2rad(15.0)
|
|
|
|
rx, ry, ryaw = hybrid_a_star_planning(
|
|
start, goal, ox, oy, xyreso, yawreso)
|
|
|
|
plt.plot(ox, oy, ".k")
|
|
rs.plot_arrow(start[0], start[1], start[2])
|
|
rs.plot_arrow(goal[0], goal[1], goal[2])
|
|
|
|
plt.grid(True)
|
|
plt.axis("equal")
|
|
plt.show()
|
|
|
|
print(__file__ + " start!!")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|