Skip to content

Commit c2335f0

Browse files
authored
Add files via upload
1 parent f75f1e7 commit c2335f0

9 files changed

+2255
-0
lines changed

Diff for: Astar_heuristic.py

+298
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
import math
2+
import heapq
3+
import matplotlib.pyplot as plt
4+
import time
5+
6+
show_animation = False
7+
8+
9+
class Node:
10+
11+
def __init__(self, x, y, cost, pind):
12+
self.x = x
13+
self.y = y
14+
self.cost = cost
15+
self.pind = pind
16+
17+
def __str__(self):
18+
return str(self.x) + "," + str(self.y) + "," + str(self.cost) + "," + str(self.pind)
19+
20+
21+
def calc_final_path(ngoal, closedset, reso):
22+
# generate final course
23+
rx, ry = [ngoal.x * reso], [ngoal.y * reso]
24+
pind = ngoal.pind
25+
while pind != -1:
26+
n = closedset[pind]
27+
rx.append(n.x * reso)
28+
ry.append(n.y * reso)
29+
pind = n.pind
30+
31+
return rx, ry
32+
33+
34+
def dp_planning(sx, sy, gx, gy, ox, oy, reso, rr):
35+
"""
36+
sx: start x position [m]
37+
sy: start y position [m]
38+
gx: goal x position [m]
39+
gx: goal x position [m]
40+
ox: x position list of Obstacles [m]
41+
oy: y position list of Obstacles [m]
42+
reso: grid resolution [m]
43+
rr: robot radius[m]
44+
"""
45+
46+
nstart = Node(round(sx / reso), round(sy / reso), 0.0, -1)
47+
ngoal = Node(round(gx / reso), round(gy / reso), 0.0, -1)
48+
ox = [iox / reso for iox in ox] #divides all of ox by the resolution
49+
oy = [ioy / reso for ioy in oy] #divides all of oy by the resolution
50+
51+
obmap, minx, miny, maxx, maxy, xw, yw = calc_obstacle_map(ox, oy, reso, rr)
52+
#t1=time.perf_counter()
53+
#defines movement in terms of relative positions and gives the cost of each movement
54+
motion = get_motion_model()
55+
56+
#initialising both the yet to visit and visited list
57+
openset, closedset = dict(), dict()
58+
openset[calc_index(ngoal, xw, minx, miny)] = ngoal
59+
pq = []
60+
pq.append((0, calc_index(ngoal, xw, minx, miny)))
61+
62+
while 1:
63+
if not pq:
64+
break
65+
cost, c_id = heapq.heappop(pq) #c_id is the current index, heapop returns the smallest data element from the heap pq
66+
#popping current node out of openset into closed set
67+
if c_id in openset:
68+
current = openset[c_id]
69+
closedset[c_id] = current
70+
openset.pop(c_id)
71+
else:
72+
continue
73+
74+
# show graph
75+
if show_animation: # pragma: no cover
76+
plt.plot(current.x * reso, current.y * reso, "xc")
77+
# for stopping simulation with the esc key.
78+
plt.gcf().canvas.mpl_connect('key_release_event',
79+
lambda event: [exit(0) if event.key == 'escape' else None])
80+
if len(closedset.keys()) % 10 == 0:
81+
plt.pause(0.001)
82+
83+
# Remove the item from the open set
84+
85+
# expand search grid based on motion model, generates child nodes from adjacent squares
86+
for i, _ in enumerate(motion):
87+
node = Node(current.x + motion[i][0],
88+
current.y + motion[i][1],
89+
current.cost + motion[i][2], c_id)
90+
n_id = calc_index(node, xw, minx, miny)
91+
#making sure not to use nodes already visited
92+
if n_id in closedset:
93+
continue
94+
#checking node is within boundary and not in obstacle
95+
if not verify_node(node, obmap, minx, miny, maxx, maxy):
96+
continue
97+
98+
if n_id not in openset:
99+
openset[n_id] = node # Discover a new node
100+
heapq.heappush(
101+
pq, (node.cost, calc_index(node, xw, minx, miny)))
102+
else:
103+
if openset[n_id].cost >= node.cost:
104+
# This path is the best until now. record it!
105+
openset[n_id] = node
106+
heapq.heappush(
107+
pq, (node.cost, calc_index(node, xw, minx, miny)))
108+
109+
rx, ry = calc_final_path(closedset[calc_index(
110+
nstart, xw, minx, miny)], closedset, reso)
111+
#t2=time.perf_counter()
112+
#print(f"Path Planner in {t2 - t1:0.4f} seconds")
113+
return rx, ry, closedset
114+
115+
116+
def calc_heuristic(n1, n2):
117+
w = 1.0 # weight of heuristic
118+
d = w * math.sqrt((n1.x - n2.x)**2 + (n1.y - n2.y)**2)
119+
return d
120+
121+
#Making sure the node is within range and not in an obstacle
122+
def verify_node(node, obmap, minx, miny, maxx, maxy):
123+
124+
if node.x < minx:
125+
return False
126+
elif node.y < miny:
127+
return False
128+
elif node.x >= maxx:
129+
return False
130+
elif node.y >= maxy:
131+
return False
132+
#Need to subtract minx and miny to scale to the obmap indicies correctly
133+
if obmap[int(round(node.x-minx))][int(round(node.y-miny))]:
134+
return False
135+
136+
return True
137+
138+
#function determines whether position would cause a collision with an obstacle
139+
def calc_obstacle_map(ox, oy, reso, vr):
140+
141+
minx = int(round(min(ox)))
142+
miny = int(round(min(oy)))
143+
maxx = int(round(max(ox)))
144+
maxy = int(round(max(oy)))
145+
146+
xwidth = round(maxx - minx)
147+
ywidth = round(maxy - miny)
148+
# obstacle map generation, determines which positions would cause a collision
149+
# with an obstacle given the device's radius
150+
obmap = [[False for i in range(ywidth)] for i in range(xwidth)]
151+
#for ix in range(xwidth):
152+
# x = ix + minx #the current x position
153+
# for iy in range(ywidth):
154+
# y = iy + miny #the current y position
155+
# # print(x, y)
156+
# for iox, ioy in zip(ox, oy):
157+
# d = math.sqrt((iox - x)**2 + (ioy - y)**2) #distance from current x and y position to obstacle
158+
# if d <= vr / reso:
159+
# obmap[ix][iy] = True
160+
# break
161+
obmap_motion = obmap_motion_model()
162+
163+
for iox, ioy in zip(ox, oy):
164+
rox=iox
165+
roy=ioy
166+
iox=int(round(iox))
167+
ioy=int(round(ioy))
168+
169+
for i, _ in enumerate(obmap_motion):
170+
adjind = [iox + obmap_motion[i][0],
171+
ioy + obmap_motion[i][1]]
172+
173+
if not verify_obmap(adjind, minx, miny, maxx, maxy):
174+
continue
175+
176+
d = math.sqrt((rox - adjind[0])**2 + (roy - adjind[1])**2)
177+
if d <= vr / reso:
178+
ix = adjind[0] - minx
179+
iy = adjind[1] - miny
180+
obmap[ix][iy] = True
181+
182+
183+
return obmap, minx, miny, maxx, maxy, xwidth, ywidth
184+
185+
186+
def calc_index(node, xwidth, xmin, ymin):
187+
return (node.y - ymin) * xwidth + (node.x - xmin)
188+
189+
#function just giving the option to move in 8 directions(up, down, diagonally, etc..)
190+
#and the costs of moving in those directions
191+
def get_motion_model():
192+
# dx, dy, cost
193+
motion = [[1, 0, 1],
194+
[0, 1, 1],
195+
[-1, 0, 1],
196+
[0, -1, 1],
197+
[-1, -1, math.sqrt(2)],
198+
[-1, 1, math.sqrt(2)],
199+
[1, -1, math.sqrt(2)],
200+
[1, 1, math.sqrt(2)]]
201+
202+
return motion
203+
204+
# function needs to be changed depending on how the resolution and car radius change
205+
def obmap_motion_model():
206+
# dx, dy
207+
obmap_motion = [[0, 0],
208+
[1, 0],
209+
[2, 0],
210+
[0, 1],
211+
[0, 2],
212+
[-1, 0],
213+
[-2, 0],
214+
[0, -1],
215+
[0, -2],
216+
[-1, -1],
217+
[-1, 1],
218+
[1, -1],
219+
[1, 1],
220+
[1, 2],
221+
[2, 1],
222+
[2, 2],
223+
[-1, 2],
224+
[-2, 1],
225+
[-2, 2],
226+
[1, -2],
227+
[2, -1],
228+
[2, -2],
229+
[-1, -2],
230+
[-2, -1],
231+
[-2, -2]]
232+
233+
return obmap_motion
234+
235+
236+
def verify_obmap(adjind, minx, miny, maxx, maxy):
237+
238+
if adjind[0] < minx:
239+
return False
240+
elif adjind[1] < miny:
241+
return False
242+
elif adjind[0] >= maxx:
243+
return False
244+
elif adjind[1] >= maxy:
245+
return False
246+
247+
return True
248+
249+
250+
def main():
251+
print(__file__ + " start!!")
252+
253+
# start and goal position
254+
sx = 10.0 # [m]
255+
sy = 10.0 # [m]
256+
gx = 50.0 # [m]
257+
gy = 50.0 # [m]
258+
grid_size = 2.0 # [m]
259+
robot_size = 1.0 # [m]
260+
261+
ox, oy = [], []
262+
263+
for i in range(60):
264+
ox.append(i)
265+
oy.append(0.0)
266+
for i in range(60):
267+
ox.append(60.0)
268+
oy.append(i)
269+
for i in range(61):
270+
ox.append(i)
271+
oy.append(60.0)
272+
for i in range(61):
273+
ox.append(0.0)
274+
oy.append(i)
275+
for i in range(40):
276+
ox.append(20.0)
277+
oy.append(i)
278+
for i in range(40):
279+
ox.append(40.0)
280+
oy.append(60.0 - i)
281+
282+
if show_animation: # pragma: no cover
283+
plt.plot(ox, oy, ".k")
284+
plt.plot(sx, sy, "xr")
285+
plt.plot(gx, gy, "xb")
286+
plt.grid(True)
287+
plt.axis("equal")
288+
289+
rx, ry, _ = dp_planning(sx, sy, gx, gy, ox, oy, grid_size, robot_size)
290+
291+
if show_animation: # pragma: no cover
292+
plt.plot(rx, ry, "-r")
293+
plt.show()
294+
295+
296+
if __name__ == '__main__':
297+
show_animation = True
298+
main()

Diff for: Car.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import matplotlib.pyplot as plt
2+
from math import sqrt, cos, sin, tan, pi
3+
4+
WB = 0.33 # rear to front wheel
5+
W = 0.26 # width of car
6+
LF = 0.5 # distance from rear to vehicle front end
7+
LB = 0.15 # distance from rear to vehicle back end
8+
MAX_STEER = 0.5 # [rad] maximum steering angle
9+
10+
WBUBBLE_DIST = (LF - LB) / 2.0
11+
WBUBBLE_R = sqrt(((LF + LB) / 2.0)**2 + 1)
12+
13+
# vehicle rectangle verticles
14+
VRX = [LF, LF, -LB, -LB, LF]
15+
VRY = [W / 2, -W / 2, -W / 2, W / 2, W / 2]
16+
17+
18+
def check_car_collision(xlist, ylist, yawlist, ox, oy, kdtree):
19+
for x, y, yaw in zip(xlist, ylist, yawlist):
20+
cx = x + WBUBBLE_DIST * cos(yaw)
21+
cy = y + WBUBBLE_DIST * sin(yaw)
22+
23+
ids = kdtree.search_in_distance([cx, cy], WBUBBLE_R)
24+
25+
if not ids:
26+
continue
27+
28+
if not rectangle_check(x, y, yaw,
29+
[ox[i] for i in ids], [oy[i] for i in ids]):
30+
return False # collision
31+
32+
return True # no collision
33+
34+
35+
def rectangle_check(x, y, yaw, ox, oy):
36+
# transform obstacles to base link frame
37+
c, s = cos(-yaw), sin(-yaw)
38+
for iox, ioy in zip(ox, oy):
39+
tx = iox - x
40+
ty = ioy - y
41+
rx = c * tx - s * ty
42+
ry = s * tx + c * ty
43+
44+
if not (rx > LF or rx < -LB or ry > W / 2.0 or ry < -W / 2.0):
45+
return False # no collision
46+
47+
return True # collision
48+
49+
50+
def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"):
51+
"""Plot arrow."""
52+
if not isinstance(x, float):
53+
for (ix, iy, iyaw) in zip(x, y, yaw):
54+
plot_arrow(ix, iy, iyaw)
55+
else:
56+
plt.arrow(x, y, length * cos(yaw), length * sin(yaw),
57+
fc=fc, ec=ec, head_width=width, head_length=width, alpha=0.4)
58+
# plt.plot(x, y)
59+
60+
61+
def plot_car(x, y, yaw):
62+
car_color = '-k'
63+
c, s = cos(yaw), sin(yaw)
64+
65+
car_outline_x, car_outline_y = [], []
66+
for rx, ry in zip(VRX, VRY):
67+
tx = c * rx - s * ry + x
68+
ty = s * rx + c * ry + y
69+
car_outline_x.append(tx)
70+
car_outline_y.append(ty)
71+
72+
arrow_x, arrow_y, arrow_yaw = c * 1.5 + x, s * 1.5 + y, yaw
73+
plot_arrow(arrow_x, arrow_y, arrow_yaw)
74+
75+
plt.plot(car_outline_x, car_outline_y, car_color)
76+
77+
78+
def pi_2_pi(angle):
79+
return (angle + pi) % (2 * pi) - pi
80+
81+
82+
def move(x, y, yaw, distance, steer, L=WB):
83+
x += distance * cos(yaw)
84+
y += distance * sin(yaw)
85+
yaw += pi_2_pi(distance * tan(steer) / L) # distance/2
86+
87+
return x, y, yaw
88+
89+
90+
if __name__ == '__main__':
91+
x, y, yaw = 0., 0., 1.
92+
plt.axis('equal')
93+
plot_car(x, y, yaw)
94+
plt.show()

0 commit comments

Comments
 (0)