3
3
import math
4
4
import numpy as np
5
5
import argparse
6
+ import time
7
+ import sys
6
8
7
9
# Command line arguments
8
10
parser = argparse .ArgumentParser (description = 'Implements the RRT algorithm.' )
9
11
parser .add_argument ('-o' , '--obstacles' , type = bool , action = argparse .BooleanOptionalAction , metavar = '' , required = False , help = 'Obstacles on the map' )
10
12
parser .add_argument ('-n' , '--nodes' , type = int , metavar = '' , required = False , help = 'Maximum number of nodes' )
11
13
parser .add_argument ('-e' , '--epsilon' , type = float , metavar = '' , required = False , help = 'Step size' )
14
+ parser .add_argument ('-init' , '--x_init' , nargs = '+' , type = int , metavar = '' , required = False , help = 'Initial node position in x and y respectively' )
15
+ parser .add_argument ('-goal' , '--x_goal' , nargs = '+' , type = int , metavar = '' , required = False , help = 'Goal node position in x and y respectively' )
12
16
parser .add_argument ('-srn' , '--show_random_nodes' , type = bool , action = argparse .BooleanOptionalAction , metavar = '' , required = False , help = 'Show random nodes on screen' )
13
17
parser .add_argument ('-snn' , '--show_new_nodes' , type = bool , action = argparse .BooleanOptionalAction , metavar = '' , required = False , help = 'Show new nodes on screen' )
14
18
args = parser .parse_args ()
17
21
WIDTH , HEIGHT = 640 , 480
18
22
WINDOW = pygame .display .set_mode (size = (WIDTH , HEIGHT ))
19
23
pygame .display .set_caption ('RRT' )
20
- FPS = 0.1
24
+ FPS = 60
21
25
22
26
# Colors
23
27
WHITE = (255 , 255 , 255 )
28
32
BROWN = (189 , 154 , 122 )
29
33
30
34
# RRT parameters
31
- if not args .nodes == None :
32
- MAX_NODES = args .nodes
33
- else :
34
- MAX_NODES = 5000 # Default maximum number of nodes/vertices
35
-
36
- if not args .epsilon == None :
37
- EPSILON = args .epsilon
38
- else :
39
- EPSILON = 7.0 # Default step size
35
+ MAX_NODES = args .nodes if not args .nodes is None else 5000 # Default maximum number of nodes/vertices
36
+ EPSILON = args .epsilon if not args .epsilon is None else 7.0 # Default step size
40
37
41
38
def draw_window ():
42
39
"""Draw the window all white."""
@@ -55,10 +52,12 @@ def draw_obstacles():
55
52
All the rectangle obstacles.
56
53
"""
57
54
obstacles = []
58
- obstacle1 = pygame .Rect ((WIDTH // 2 + 10 , HEIGHT // 2 - 45 , 90 , 90 ))
59
- obstacle2 = pygame .Rect ((WIDTH // 2 - 100 , HEIGHT // 2 - 45 , 90 , 90 ))
55
+ obstacle1 = pygame .Rect ((WIDTH // 2 + 90 , HEIGHT // 2 - 45 , 90 , 90 ))
56
+ obstacle2 = pygame .Rect ((WIDTH // 2 - 180 , HEIGHT // 2 - 45 , 90 , 90 ))
60
57
pygame .draw .rect (surface = WINDOW , color = RED , rect = obstacle1 )
61
58
pygame .draw .rect (surface = WINDOW , color = RED , rect = obstacle2 )
59
+
60
+ # Just decoration borders in black
62
61
pygame .draw .rect (surface = WINDOW , color = BLACK , rect = obstacle1 , width = 2 )
63
62
pygame .draw .rect (surface = WINDOW , color = BLACK , rect = obstacle2 , width = 2 )
64
63
@@ -160,7 +159,7 @@ def nearest_neighbor(tree, x_rand):
160
159
161
160
return x_near
162
161
163
- def new_state (x_rand , x_near ):
162
+ def new_state (x_rand , x_near , x_goal ):
164
163
"""Advances a small step (EPSILON) towards the random node.
165
164
166
165
Takes small step (EPSILON) from the nearest node to the
@@ -174,20 +173,30 @@ def new_state(x_rand, x_near):
174
173
Coordinate of the random node generated.
175
174
x_near : tuple
176
175
Coordinate of the nearest neighbor node.
176
+ x_goal : tuple
177
+ Coordinate of the goal node.
177
178
178
179
Returns
179
180
-------
180
181
tuple
181
182
Coordinate of the new node generated between the nearest
182
183
and random nodes.
183
184
"""
185
+ global is_goal_reached
186
+
184
187
if euclidean_distance (x_near , x_rand ) < EPSILON :
188
+ if abs (x_rand [0 ] - x_goal [0 ]) < EPSILON and abs (x_rand [1 ] - x_goal [1 ]) < EPSILON : # Check if goal is reached
189
+ is_goal_reached = True
190
+
185
191
# Keep that shortest distance from x_near to x_rand
186
192
return x_rand
187
193
else :
188
194
px , py = x_rand [0 ] - x_near [0 ], x_rand [1 ] - x_near [1 ]
189
195
theta = math .atan2 (py , px )
190
- x_new = x_near [0 ] + EPSILON * math .cos (theta ), x_near [1 ] + EPSILON * math .sin (theta )
196
+ x_new = x_near [0 ] + EPSILON * math .cos (theta ), x_near [1 ] + EPSILON * math .sin (theta )
197
+
198
+ if abs (x_new [0 ] - x_goal [0 ]) < EPSILON and abs (x_new [1 ] - x_goal [1 ]) < EPSILON : # Check if goal is reached
199
+ is_goal_reached = True
191
200
192
201
return x_new
193
202
@@ -211,20 +220,29 @@ def generate_parents(values, parent):
211
220
parent : list
212
221
Ordered collection of the parents.
213
222
"""
214
- parent_value = values [min_distance ] # Value neares node
223
+ parent_value = values [min_distance ] # Value nearest node
215
224
parent_index = len (parent ) # Used to be the index of the parent list
216
225
parent .insert (parent_index , parent_value )
217
226
227
+ if is_goal_reached :
228
+ # Insert in the very last index the last value recorded plus one
229
+ parent .insert (parent_index + 1 , values [- 1 ]+ 1 )
230
+
218
231
return parent
219
232
220
233
221
234
def main (has_obstacles , show_random_nodes , show_new_nodes ):
235
+ global is_goal_reached
236
+
222
237
clock = pygame .time .Clock ()
223
238
run = True
239
+ is_goal_reached = False
240
+ is_simulation_finished = False
224
241
tree = [] # Tree list containing all the nodes/vertices
225
- parent = [] # Parent list of each each node/vertex
242
+ parent = [] # Parent list of each each node/vertex
226
243
values = [] # Values list of each node/vertex
227
- x_init = WINDOW .get_rect ().center # Initial node
244
+ x_init = args .x_init if not args .x_init is None else WINDOW .get_rect ().center # Initial node
245
+ x_goal = args .x_goal if not args .x_goal is None else (540 , 380 ) # Goal node
228
246
tree .append (x_init ) # Append initial node
229
247
parent .append (0 ) # Append initial parent
230
248
draw_window ()
@@ -243,13 +261,14 @@ def main(has_obstacles, show_random_nodes, show_new_nodes):
243
261
244
262
x_rand = generate_random_node () # Random node
245
263
x_near = nearest_neighbor (tree , x_rand ) # Nearest neighbor to the random node
246
- x_new = new_state (x_rand , x_near ) # New node
264
+ x_new = new_state (x_rand , x_near , x_goal ) # New node
247
265
tree .append (x_new )
248
266
249
267
# Draw points and lines to the visualization
250
268
pygame .draw .circle (surface = WINDOW , color = BLUE , center = x_init , radius = 3 )
269
+ pygame .draw .circle (surface = WINDOW , color = RED , center = x_goal , radius = 3 )
251
270
252
- if has_obstacles :
271
+ if has_obstacles and not is_simulation_finished :
253
272
collision_free = is_free (point = x_new , obstacles = obstacles , tree = tree ) # Check collision
254
273
if collision_free :
255
274
# Append current node value and place it in the parent list
@@ -262,8 +281,12 @@ def main(has_obstacles, show_random_nodes, show_new_nodes):
262
281
pygame .draw .circle (surface = WINDOW , color = BROWN , center = x_new , radius = 2 )
263
282
264
283
pygame .draw .line (surface = WINDOW , color = BLACK , start_pos = x_near , end_pos = x_new )
265
- node_value += 1 # Increment value for the next randomly generated node
266
- else :
284
+ node_value += 1 # Increment the value for the next randomly generated node
285
+
286
+ if is_goal_reached :
287
+ pygame .draw .line (surface = WINDOW , color = BLACK , start_pos = x_new , end_pos = x_goal )
288
+ is_simulation_finished = True
289
+ elif not is_simulation_finished :
267
290
# Append current node value and place it in the parent list
268
291
values .append (node_value )
269
292
parent = generate_parents (values , parent )
@@ -276,11 +299,15 @@ def main(has_obstacles, show_random_nodes, show_new_nodes):
276
299
pygame .draw .line (surface = WINDOW , color = BLACK , start_pos = x_near , end_pos = x_new )
277
300
node_value += 1 # Increment value for the next randomly generated node
278
301
302
+ if is_goal_reached :
303
+ pygame .draw .line (surface = WINDOW , color = BLACK , start_pos = x_new , end_pos = x_goal )
304
+ is_simulation_finished = True
305
+
279
306
pygame .display .update ()
280
-
281
307
k += 1
282
308
283
309
pygame .quit ()
310
+ sys .exit ()
284
311
285
312
if __name__ == '__main__' :
286
313
main (has_obstacles = args .obstacles , show_random_nodes = args .show_random_nodes , show_new_nodes = args .show_new_nodes )
0 commit comments