pathplanning 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CurvesGenerator/__init__.py +1 -0
- CurvesGenerator/bezier_path.py +145 -0
- CurvesGenerator/bspline_curve.py +80 -0
- CurvesGenerator/cubic_spline.py +262 -0
- CurvesGenerator/draw.py +66 -0
- CurvesGenerator/dubins_path.py +351 -0
- CurvesGenerator/quartic_polynomial.py +43 -0
- CurvesGenerator/quintic_polynomial.py +143 -0
- CurvesGenerator/reeds_shepp.py +720 -0
- Sampling_based_Planning/__init__.py +1 -0
- Sampling_based_Planning/rrt_2D/__init__.py +1 -0
- Sampling_based_Planning/rrt_2D/adaptively_informed_trees.py +0 -0
- Sampling_based_Planning/rrt_2D/advanced_batch_informed_trees.py +0 -0
- Sampling_based_Planning/rrt_2D/batch_informed_trees.py +402 -0
- Sampling_based_Planning/rrt_2D/dubins_rrt_star.py +321 -0
- Sampling_based_Planning/rrt_2D/dynamic_rrt.py +342 -0
- Sampling_based_Planning/rrt_2D/env.py +45 -0
- Sampling_based_Planning/rrt_2D/extended_rrt.py +251 -0
- Sampling_based_Planning/rrt_2D/fast_marching_trees.py +220 -0
- Sampling_based_Planning/rrt_2D/informed_rrt_star.py +305 -0
- Sampling_based_Planning/rrt_2D/plotting.py +115 -0
- Sampling_based_Planning/rrt_2D/queue.py +62 -0
- Sampling_based_Planning/rrt_2D/rrt.py +114 -0
- Sampling_based_Planning/rrt_2D/rrt_connect.py +156 -0
- Sampling_based_Planning/rrt_2D/rrt_sharp.py +0 -0
- Sampling_based_Planning/rrt_2D/rrt_star.py +184 -0
- Sampling_based_Planning/rrt_2D/rrt_star_smart.py +311 -0
- Sampling_based_Planning/rrt_2D/utils.py +138 -0
- Sampling_based_Planning/rrt_3D/ABIT_star3D.py +148 -0
- Sampling_based_Planning/rrt_3D/BIT_star3D.py +353 -0
- Sampling_based_Planning/rrt_3D/FMT_star3D.py +192 -0
- Sampling_based_Planning/rrt_3D/__init__.py +1 -0
- Sampling_based_Planning/rrt_3D/dynamic_rrt3D.py +239 -0
- Sampling_based_Planning/rrt_3D/env3D.py +148 -0
- Sampling_based_Planning/rrt_3D/extend_rrt3D.py +102 -0
- Sampling_based_Planning/rrt_3D/informed_rrt_star3D.py +234 -0
- Sampling_based_Planning/rrt_3D/plot_util3D.py +167 -0
- Sampling_based_Planning/rrt_3D/queue.py +86 -0
- Sampling_based_Planning/rrt_3D/rrt3D.py +72 -0
- Sampling_based_Planning/rrt_3D/rrt_connect3D.py +187 -0
- Sampling_based_Planning/rrt_3D/rrt_star3D.py +107 -0
- Sampling_based_Planning/rrt_3D/rrt_star_smart3D.py +0 -0
- Sampling_based_Planning/rrt_3D/utils3D.py +416 -0
- Search_based_Planning/Search_3D/Anytime_Dstar3D.py +245 -0
- Search_based_Planning/Search_3D/Astar3D.py +119 -0
- Search_based_Planning/Search_3D/Dstar3D.py +192 -0
- Search_based_Planning/Search_3D/DstarLite3D.py +219 -0
- Search_based_Planning/Search_3D/LP_Astar3D.py +194 -0
- Search_based_Planning/Search_3D/LRT_Astar3D.py +87 -0
- Search_based_Planning/Search_3D/RTA_Astar3D.py +78 -0
- Search_based_Planning/Search_3D/__init__.py +1 -0
- Search_based_Planning/Search_3D/bidirectional_Astar3D.py +115 -0
- Search_based_Planning/Search_3D/env3D.py +147 -0
- Search_based_Planning/Search_3D/plot_util3D.py +155 -0
- Search_based_Planning/Search_3D/queue.py +154 -0
- Search_based_Planning/Search_3D/utils3D.py +359 -0
- Search_based_Planning/__init__.py +1 -0
- Search_based_Planning/plan2d/__init__.py +17 -0
- Search_based_Planning/plan2d/anytime_dstar.py +314 -0
- Search_based_Planning/plan2d/anytime_repairing_astar.py +220 -0
- Search_based_Planning/plan2d/astar.py +225 -0
- Search_based_Planning/plan2d/best_first_search.py +67 -0
- Search_based_Planning/plan2d/bidirectional_astar.py +229 -0
- Search_based_Planning/plan2d/breadth_first_search.py +69 -0
- Search_based_Planning/plan2d/depth_first_search.py +69 -0
- Search_based_Planning/plan2d/dijkstra.py +68 -0
- Search_based_Planning/plan2d/dstar.py +304 -0
- Search_based_Planning/plan2d/dstar_lite.py +239 -0
- Search_based_Planning/plan2d/learning_realtime_astar.py +230 -0
- Search_based_Planning/plan2d/lifelong_planning_astar.py +254 -0
- Search_based_Planning/plan2d/plan2d_facade.py +494 -0
- Search_based_Planning/plan2d/realtime_adaptive_astar.py +234 -0
- Search_based_Planning/plan2d/run.py +55 -0
- Search_based_Planning/plan2d/utils/__init__.py +1 -0
- Search_based_Planning/plan2d/utils/env.py +48 -0
- Search_based_Planning/plan2d/utils/plotting.py +258 -0
- Search_based_Planning/plan2d/utils/queue.py +62 -0
- pathplanning-0.1.0.dist-info/LICENSE +21 -0
- pathplanning-0.1.0.dist-info/METADATA +354 -0
- pathplanning-0.1.0.dist-info/RECORD +86 -0
- pathplanning-0.1.0.dist-info/WHEEL +5 -0
- pathplanning-0.1.0.dist-info/top_level.txt +4 -0
- pathplanningv2/__init__.py +29 -0
- pathplanningv2/api.py +18 -0
- pathplanningv2/registry.py +107 -0
- pathplanningv2/search2d.py +15 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EXTENDED_RRT_2D
|
|
3
|
+
@author: damminhtien
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import math
|
|
9
|
+
import numpy as np
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
import matplotlib.patches as patches
|
|
12
|
+
|
|
13
|
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
|
|
14
|
+
"/../../Sampling_based_Planning/")
|
|
15
|
+
|
|
16
|
+
from Sampling_based_Planning.rrt_2D import env, plotting, utils
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Node:
|
|
20
|
+
def __init__(self, n):
|
|
21
|
+
self.x = n[0]
|
|
22
|
+
self.y = n[1]
|
|
23
|
+
self.parent = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ExtendedRrt:
|
|
27
|
+
def __init__(self, s_start, s_goal, step_len, goal_sample_rate, waypoint_sample_rate, iter_max):
|
|
28
|
+
self.s_start = Node(s_start)
|
|
29
|
+
self.s_goal = Node(s_goal)
|
|
30
|
+
self.step_len = step_len
|
|
31
|
+
self.goal_sample_rate = goal_sample_rate
|
|
32
|
+
self.waypoint_sample_rate = waypoint_sample_rate
|
|
33
|
+
self.iter_max = iter_max
|
|
34
|
+
self.vertex = [self.s_start]
|
|
35
|
+
|
|
36
|
+
self.env = env.Env()
|
|
37
|
+
self.plotting = plotting.Plotting(s_start, s_goal)
|
|
38
|
+
self.utils = utils.Utils()
|
|
39
|
+
self.fig, self.ax = plt.subplots()
|
|
40
|
+
|
|
41
|
+
self.x_range = self.env.x_range
|
|
42
|
+
self.y_range = self.env.y_range
|
|
43
|
+
self.obs_circle = self.env.obs_circle
|
|
44
|
+
self.obs_rectangle = self.env.obs_rectangle
|
|
45
|
+
self.obs_boundary = self.env.obs_boundary
|
|
46
|
+
|
|
47
|
+
self.path = []
|
|
48
|
+
self.waypoint = []
|
|
49
|
+
|
|
50
|
+
def planning(self):
|
|
51
|
+
for i in range(self.iter_max):
|
|
52
|
+
node_rand = self.generate_random_node(self.goal_sample_rate)
|
|
53
|
+
node_near = self.nearest_neighbor(self.vertex, node_rand)
|
|
54
|
+
node_new = self.new_state(node_near, node_rand)
|
|
55
|
+
|
|
56
|
+
if node_new and not self.utils.is_collision(node_near, node_new):
|
|
57
|
+
self.vertex.append(node_new)
|
|
58
|
+
dist, _ = self.get_distance_and_angle(node_new, self.s_goal)
|
|
59
|
+
|
|
60
|
+
if dist <= self.step_len:
|
|
61
|
+
self.new_state(node_new, self.s_goal)
|
|
62
|
+
|
|
63
|
+
path = self.extract_path(node_new)
|
|
64
|
+
self.plot_grid("Extended_RRT")
|
|
65
|
+
self.plot_visited()
|
|
66
|
+
self.plot_path(path)
|
|
67
|
+
self.path = path
|
|
68
|
+
self.waypoint = self.extract_waypoint(node_new)
|
|
69
|
+
self.fig.canvas.mpl_connect('button_press_event', self.on_press)
|
|
70
|
+
plt.show()
|
|
71
|
+
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
def on_press(self, event):
|
|
77
|
+
x, y = event.xdata, event.ydata
|
|
78
|
+
if x < 0 or x > 50 or y < 0 or y > 30:
|
|
79
|
+
print("Please choose right area!")
|
|
80
|
+
else:
|
|
81
|
+
x, y = int(x), int(y)
|
|
82
|
+
print("Add circle obstacle at: s =", x, ",", "y =", y)
|
|
83
|
+
self.obs_circle.append([x, y, 2])
|
|
84
|
+
self.utils.update_obs(self.obs_circle, self.obs_boundary, self.obs_rectangle)
|
|
85
|
+
path, waypoint = self.replanning()
|
|
86
|
+
|
|
87
|
+
plt.cla()
|
|
88
|
+
self.plot_grid("Extended_RRT")
|
|
89
|
+
self.plot_path(self.path, color='blue')
|
|
90
|
+
self.plot_visited()
|
|
91
|
+
self.plot_path(path)
|
|
92
|
+
self.path = path
|
|
93
|
+
self.waypoint = waypoint
|
|
94
|
+
self.fig.canvas.draw_idle()
|
|
95
|
+
|
|
96
|
+
def replanning(self):
|
|
97
|
+
self.vertex = [self.s_start]
|
|
98
|
+
|
|
99
|
+
for i in range(self.iter_max):
|
|
100
|
+
node_rand = self.generate_random_node_replanning(self.goal_sample_rate, self.waypoint_sample_rate)
|
|
101
|
+
node_near = self.nearest_neighbor(self.vertex, node_rand)
|
|
102
|
+
node_new = self.new_state(node_near, node_rand)
|
|
103
|
+
|
|
104
|
+
if node_new and not self.utils.is_collision(node_near, node_new):
|
|
105
|
+
self.vertex.append(node_new)
|
|
106
|
+
dist, _ = self.get_distance_and_angle(node_new, self.s_goal)
|
|
107
|
+
|
|
108
|
+
if dist <= self.step_len:
|
|
109
|
+
self.new_state(node_new, self.s_goal)
|
|
110
|
+
path = self.extract_path(node_new)
|
|
111
|
+
waypoint = self.extract_waypoint(node_new)
|
|
112
|
+
|
|
113
|
+
return path, waypoint
|
|
114
|
+
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
def generate_random_node(self, goal_sample_rate):
|
|
118
|
+
delta = self.utils.delta
|
|
119
|
+
|
|
120
|
+
if np.random.random() > goal_sample_rate:
|
|
121
|
+
return Node((np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta),
|
|
122
|
+
np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)))
|
|
123
|
+
|
|
124
|
+
return self.s_goal
|
|
125
|
+
|
|
126
|
+
def generate_random_node_replanning(self, goal_sample_rate, waypoint_sample_rate):
|
|
127
|
+
delta = self.utils.delta
|
|
128
|
+
p = np.random.random()
|
|
129
|
+
|
|
130
|
+
if p < goal_sample_rate:
|
|
131
|
+
return self.s_goal
|
|
132
|
+
elif goal_sample_rate < p < goal_sample_rate + waypoint_sample_rate:
|
|
133
|
+
return self.waypoint[np.random.randint(0, len(self.path) - 1)]
|
|
134
|
+
else:
|
|
135
|
+
return Node((np.random.uniform(self.x_range[0] + delta, self.x_range[1] - delta),
|
|
136
|
+
np.random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def nearest_neighbor(node_list, n):
|
|
141
|
+
return node_list[int(np.argmin([math.hypot(nd.x - n.x, nd.y - n.y)
|
|
142
|
+
for nd in node_list]))]
|
|
143
|
+
|
|
144
|
+
def new_state(self, node_start, node_end):
|
|
145
|
+
dist, theta = self.get_distance_and_angle(node_start, node_end)
|
|
146
|
+
|
|
147
|
+
dist = min(self.step_len, dist)
|
|
148
|
+
node_new = Node((node_start.x + dist * math.cos(theta),
|
|
149
|
+
node_start.y + dist * math.sin(theta)))
|
|
150
|
+
node_new.parent = node_start
|
|
151
|
+
|
|
152
|
+
return node_new
|
|
153
|
+
|
|
154
|
+
def extract_path(self, node_end):
|
|
155
|
+
path = [(self.s_goal.x, self.s_goal.y)]
|
|
156
|
+
node_now = node_end
|
|
157
|
+
|
|
158
|
+
while node_now.parent is not None:
|
|
159
|
+
node_now = node_now.parent
|
|
160
|
+
path.append((node_now.x, node_now.y))
|
|
161
|
+
|
|
162
|
+
return path
|
|
163
|
+
|
|
164
|
+
def extract_waypoint(self, node_end):
|
|
165
|
+
waypoint = [self.s_goal]
|
|
166
|
+
node_now = node_end
|
|
167
|
+
|
|
168
|
+
while node_now.parent is not None:
|
|
169
|
+
node_now = node_now.parent
|
|
170
|
+
waypoint.append(node_now)
|
|
171
|
+
|
|
172
|
+
return waypoint
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def get_distance_and_angle(node_start, node_end):
|
|
176
|
+
dx = node_end.x - node_start.x
|
|
177
|
+
dy = node_end.y - node_start.y
|
|
178
|
+
return math.hypot(dx, dy), math.atan2(dy, dx)
|
|
179
|
+
|
|
180
|
+
def plot_grid(self, name):
|
|
181
|
+
|
|
182
|
+
for (ox, oy, w, h) in self.obs_boundary:
|
|
183
|
+
self.ax.add_patch(
|
|
184
|
+
patches.Rectangle(
|
|
185
|
+
(ox, oy), w, h,
|
|
186
|
+
edgecolor='black',
|
|
187
|
+
facecolor='black',
|
|
188
|
+
fill=True
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
for (ox, oy, w, h) in self.obs_rectangle:
|
|
193
|
+
self.ax.add_patch(
|
|
194
|
+
patches.Rectangle(
|
|
195
|
+
(ox, oy), w, h,
|
|
196
|
+
edgecolor='black',
|
|
197
|
+
facecolor='gray',
|
|
198
|
+
fill=True
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
for (ox, oy, r) in self.obs_circle:
|
|
203
|
+
self.ax.add_patch(
|
|
204
|
+
patches.Circle(
|
|
205
|
+
(ox, oy), r,
|
|
206
|
+
edgecolor='black',
|
|
207
|
+
facecolor='gray',
|
|
208
|
+
fill=True
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
plt.plot(self.s_start.x, self.s_start.y, "bs", linewidth=3)
|
|
213
|
+
plt.plot(self.s_goal.x, self.s_goal.y, "gs", linewidth=3)
|
|
214
|
+
|
|
215
|
+
plt.title(name)
|
|
216
|
+
plt.axis("equal")
|
|
217
|
+
|
|
218
|
+
def plot_visited(self):
|
|
219
|
+
animation = True
|
|
220
|
+
if animation:
|
|
221
|
+
count = 0
|
|
222
|
+
for node in self.vertex:
|
|
223
|
+
count += 1
|
|
224
|
+
if node.parent:
|
|
225
|
+
plt.plot([node.parent.x, node.x], [node.parent.y, node.y], "-g")
|
|
226
|
+
plt.gcf().canvas.mpl_connect('key_release_event',
|
|
227
|
+
lambda event:
|
|
228
|
+
[exit(0) if event.key == 'escape' else None])
|
|
229
|
+
if count % 10 == 0:
|
|
230
|
+
plt.pause(0.001)
|
|
231
|
+
else:
|
|
232
|
+
for node in self.vertex:
|
|
233
|
+
if node.parent:
|
|
234
|
+
plt.plot([node.parent.x, node.x], [node.parent.y, node.y], "-g")
|
|
235
|
+
|
|
236
|
+
@staticmethod
|
|
237
|
+
def plot_path(path, color='red'):
|
|
238
|
+
plt.plot([x[0] for x in path], [x[1] for x in path], linewidth=2, color=color)
|
|
239
|
+
plt.pause(0.01)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def main():
|
|
243
|
+
x_start = (2, 2) # Starting node
|
|
244
|
+
x_goal = (49, 24) # Goal node
|
|
245
|
+
|
|
246
|
+
errt = ExtendedRrt(x_start, x_goal, 0.5, 0.1, 0.6, 5000)
|
|
247
|
+
errt.planning()
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
if __name__ == '__main__':
|
|
251
|
+
main()
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Fast Marching Trees (FMT*)
|
|
3
|
+
@author: damminhtien
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import math
|
|
9
|
+
import random
|
|
10
|
+
import numpy as np
|
|
11
|
+
import matplotlib.pyplot as plt
|
|
12
|
+
import matplotlib.patches as patches
|
|
13
|
+
|
|
14
|
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
|
|
15
|
+
"/../../Sampling_based_Planning/")
|
|
16
|
+
|
|
17
|
+
from Sampling_based_Planning.rrt_2D import env, plotting, utils
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Node:
|
|
21
|
+
def __init__(self, n):
|
|
22
|
+
self.x = n[0]
|
|
23
|
+
self.y = n[1]
|
|
24
|
+
self.parent = None
|
|
25
|
+
self.cost = np.inf
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FMT:
|
|
29
|
+
def __init__(self, x_start, x_goal, search_radius):
|
|
30
|
+
self.x_init = Node(x_start)
|
|
31
|
+
self.x_goal = Node(x_goal)
|
|
32
|
+
self.search_radius = search_radius
|
|
33
|
+
|
|
34
|
+
self.env = env.Env()
|
|
35
|
+
self.plotting = plotting.Plotting(x_start, x_goal)
|
|
36
|
+
self.utils = utils.Utils()
|
|
37
|
+
|
|
38
|
+
self.fig, self.ax = plt.subplots()
|
|
39
|
+
self.delta = self.utils.delta
|
|
40
|
+
self.x_range = self.env.x_range
|
|
41
|
+
self.y_range = self.env.y_range
|
|
42
|
+
self.obs_circle = self.env.obs_circle
|
|
43
|
+
self.obs_rectangle = self.env.obs_rectangle
|
|
44
|
+
self.obs_boundary = self.env.obs_boundary
|
|
45
|
+
|
|
46
|
+
self.V = set()
|
|
47
|
+
self.V_unvisited = set()
|
|
48
|
+
self.V_open = set()
|
|
49
|
+
self.V_closed = set()
|
|
50
|
+
self.sample_numbers = 1000
|
|
51
|
+
|
|
52
|
+
def Init(self):
|
|
53
|
+
samples = self.SampleFree()
|
|
54
|
+
|
|
55
|
+
self.x_init.cost = 0.0
|
|
56
|
+
self.V.add(self.x_init)
|
|
57
|
+
self.V.update(samples)
|
|
58
|
+
self.V_unvisited.update(samples)
|
|
59
|
+
self.V_unvisited.add(self.x_goal)
|
|
60
|
+
self.V_open.add(self.x_init)
|
|
61
|
+
|
|
62
|
+
def Planning(self):
|
|
63
|
+
self.Init()
|
|
64
|
+
z = self.x_init
|
|
65
|
+
n = self.sample_numbers
|
|
66
|
+
rn = self.search_radius * math.sqrt((math.log(n) / n))
|
|
67
|
+
Visited = []
|
|
68
|
+
|
|
69
|
+
while z is not self.x_goal:
|
|
70
|
+
V_open_new = set()
|
|
71
|
+
X_near = self.Near(self.V_unvisited, z, rn)
|
|
72
|
+
Visited.append(z)
|
|
73
|
+
|
|
74
|
+
for x in X_near:
|
|
75
|
+
Y_near = self.Near(self.V_open, x, rn)
|
|
76
|
+
cost_list = {y: y.cost + self.Cost(y, x) for y in Y_near}
|
|
77
|
+
y_min = min(cost_list, key=cost_list.get)
|
|
78
|
+
|
|
79
|
+
if not self.utils.is_collision(y_min, x):
|
|
80
|
+
x.parent = y_min
|
|
81
|
+
V_open_new.add(x)
|
|
82
|
+
self.V_unvisited.remove(x)
|
|
83
|
+
x.cost = y_min.cost + self.Cost(y_min, x)
|
|
84
|
+
|
|
85
|
+
self.V_open.update(V_open_new)
|
|
86
|
+
self.V_open.remove(z)
|
|
87
|
+
self.V_closed.add(z)
|
|
88
|
+
|
|
89
|
+
if not self.V_open:
|
|
90
|
+
print("open set empty!")
|
|
91
|
+
break
|
|
92
|
+
|
|
93
|
+
cost_open = {y: y.cost for y in self.V_open}
|
|
94
|
+
z = min(cost_open, key=cost_open.get)
|
|
95
|
+
|
|
96
|
+
# node_end = self.ChooseGoalPoint()
|
|
97
|
+
path_x, path_y = self.ExtractPath()
|
|
98
|
+
self.animation(path_x, path_y, Visited[1: len(Visited)])
|
|
99
|
+
|
|
100
|
+
def ChooseGoalPoint(self):
|
|
101
|
+
Near = self.Near(self.V, self.x_goal, 2.0)
|
|
102
|
+
cost = {y: y.cost + self.Cost(y, self.x_goal) for y in Near}
|
|
103
|
+
|
|
104
|
+
return min(cost, key=cost.get)
|
|
105
|
+
|
|
106
|
+
def ExtractPath(self):
|
|
107
|
+
path_x, path_y = [], []
|
|
108
|
+
node = self.x_goal
|
|
109
|
+
|
|
110
|
+
while node.parent:
|
|
111
|
+
path_x.append(node.x)
|
|
112
|
+
path_y.append(node.y)
|
|
113
|
+
node = node.parent
|
|
114
|
+
|
|
115
|
+
path_x.append(self.x_init.x)
|
|
116
|
+
path_y.append(self.x_init.y)
|
|
117
|
+
|
|
118
|
+
return path_x, path_y
|
|
119
|
+
|
|
120
|
+
def Cost(self, x_start, x_end):
|
|
121
|
+
if self.utils.is_collision(x_start, x_end):
|
|
122
|
+
return np.inf
|
|
123
|
+
else:
|
|
124
|
+
return self.calc_dist(x_start, x_end)
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def calc_dist(x_start, x_end):
|
|
128
|
+
return math.hypot(x_start.x - x_end.x, x_start.y - x_end.y)
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def Near(nodelist, z, rn):
|
|
132
|
+
return {nd for nd in nodelist
|
|
133
|
+
if 0 < (nd.x - z.x) ** 2 + (nd.y - z.y) ** 2 <= rn ** 2}
|
|
134
|
+
|
|
135
|
+
def SampleFree(self):
|
|
136
|
+
n = self.sample_numbers
|
|
137
|
+
delta = self.utils.delta
|
|
138
|
+
Sample = set()
|
|
139
|
+
|
|
140
|
+
ind = 0
|
|
141
|
+
while ind < n:
|
|
142
|
+
node = Node((random.uniform(self.x_range[0] + delta, self.x_range[1] - delta),
|
|
143
|
+
random.uniform(self.y_range[0] + delta, self.y_range[1] - delta)))
|
|
144
|
+
if self.utils.is_inside_obs(node):
|
|
145
|
+
continue
|
|
146
|
+
else:
|
|
147
|
+
Sample.add(node)
|
|
148
|
+
ind += 1
|
|
149
|
+
|
|
150
|
+
return Sample
|
|
151
|
+
|
|
152
|
+
def animation(self, path_x, path_y, visited):
|
|
153
|
+
self.plot_grid("Fast Marching Trees (FMT*)")
|
|
154
|
+
|
|
155
|
+
for node in self.V:
|
|
156
|
+
plt.plot(node.x, node.y, marker='.', color='lightgrey', markersize=3)
|
|
157
|
+
|
|
158
|
+
count = 0
|
|
159
|
+
for node in visited:
|
|
160
|
+
count += 1
|
|
161
|
+
plt.plot([node.x, node.parent.x], [node.y, node.parent.y], '-g')
|
|
162
|
+
plt.gcf().canvas.mpl_connect(
|
|
163
|
+
'key_release_event',
|
|
164
|
+
lambda event: [exit(0) if event.key == 'escape' else None])
|
|
165
|
+
if count % 10 == 0:
|
|
166
|
+
plt.pause(0.001)
|
|
167
|
+
|
|
168
|
+
plt.plot(path_x, path_y, linewidth=2, color='red')
|
|
169
|
+
plt.pause(0.01)
|
|
170
|
+
plt.show()
|
|
171
|
+
|
|
172
|
+
def plot_grid(self, name):
|
|
173
|
+
|
|
174
|
+
for (ox, oy, w, h) in self.obs_boundary:
|
|
175
|
+
self.ax.add_patch(
|
|
176
|
+
patches.Rectangle(
|
|
177
|
+
(ox, oy), w, h,
|
|
178
|
+
edgecolor='black',
|
|
179
|
+
facecolor='black',
|
|
180
|
+
fill=True
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
for (ox, oy, w, h) in self.obs_rectangle:
|
|
185
|
+
self.ax.add_patch(
|
|
186
|
+
patches.Rectangle(
|
|
187
|
+
(ox, oy), w, h,
|
|
188
|
+
edgecolor='black',
|
|
189
|
+
facecolor='gray',
|
|
190
|
+
fill=True
|
|
191
|
+
)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
for (ox, oy, r) in self.obs_circle:
|
|
195
|
+
self.ax.add_patch(
|
|
196
|
+
patches.Circle(
|
|
197
|
+
(ox, oy), r,
|
|
198
|
+
edgecolor='black',
|
|
199
|
+
facecolor='gray',
|
|
200
|
+
fill=True
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
plt.plot(self.x_init.x, self.x_init.y, "bs", linewidth=3)
|
|
205
|
+
plt.plot(self.x_goal.x, self.x_goal.y, "rs", linewidth=3)
|
|
206
|
+
|
|
207
|
+
plt.title(name)
|
|
208
|
+
plt.axis("equal")
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def main():
|
|
212
|
+
x_start = (18, 8) # Starting node
|
|
213
|
+
x_goal = (37, 18) # Goal node
|
|
214
|
+
|
|
215
|
+
fmt = FMT(x_start, x_goal, 40)
|
|
216
|
+
fmt.Planning()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if __name__ == '__main__':
|
|
220
|
+
main()
|