1212
1313import matplotlib .pyplot as plt
1414
15- sys .path .append (os .path .dirname (os .path .abspath (__file__ )) +
16- "/../RRT/" )
15+ sys .path .append (os .path .dirname (os .path .abspath (__file__ )) + "/../RRT/" )
1716
1817try :
1918 from rrt import RRT
@@ -33,15 +32,17 @@ def __init__(self, x, y):
3332 super ().__init__ (x , y )
3433 self .cost = 0.0
3534
36- def __init__ (self , start , goal , obstacle_list , rand_area ,
35+ def __init__ (self ,
36+ start ,
37+ goal ,
38+ obstacle_list ,
39+ rand_area ,
3740 expand_dis = 30.0 ,
3841 path_resolution = 1.0 ,
3942 goal_sample_rate = 20 ,
4043 max_iter = 300 ,
41- connect_circle_dist = 50.0
42- ):
43- super ().__init__ (start , goal , obstacle_list ,
44- rand_area , expand_dis , path_resolution , goal_sample_rate , max_iter )
44+ connect_circle_dist = 50.0 ,
45+ search_until_max_iter = False ):
4546 """
4647 Setting Parameter
4748
@@ -51,35 +52,46 @@ def __init__(self, start, goal, obstacle_list, rand_area,
5152 randArea:Random Sampling Area [min,max]
5253
5354 """
55+ super ().__init__ (start , goal , obstacle_list , rand_area , expand_dis ,
56+ path_resolution , goal_sample_rate , max_iter )
5457 self .connect_circle_dist = connect_circle_dist
5558 self .goal_node = self .Node (goal [0 ], goal [1 ])
59+ self .search_until_max_iter = search_until_max_iter
5660
57- def planning (self , animation = True , search_until_max_iter = True ):
61+ def planning (self , animation = True ):
5862 """
5963 rrt star path planning
6064
61- animation: flag for animation on or off
62- search_until_max_iter: search until max iteration for path improving or not
65+ animation: flag for animation on or off .
6366 """
6467
6568 self .node_list = [self .start ]
6669 for i in range (self .max_iter ):
6770 print ("Iter:" , i , ", number of nodes:" , len (self .node_list ))
6871 rnd = self .get_random_node ()
6972 nearest_ind = self .get_nearest_node_index (self .node_list , rnd )
70- new_node = self .steer (self .node_list [nearest_ind ], rnd , self .expand_dis )
73+ new_node = self .steer (self .node_list [nearest_ind ], rnd ,
74+ self .expand_dis )
75+ near_node = self .node_list [nearest_ind ]
76+ new_node .cost = near_node .cost + \
77+ math .hypot (new_node .x - near_node .x ,
78+ new_node .y - near_node .y )
7179
7280 if self .check_collision (new_node , self .obstacle_list ):
7381 near_inds = self .find_near_nodes (new_node )
74- new_node = self .choose_parent (new_node , near_inds )
75- if new_node :
82+ node_with_updated_parent = self .choose_parent (
83+ new_node , near_inds )
84+ if node_with_updated_parent :
85+ self .rewire (node_with_updated_parent , near_inds )
86+ self .node_list .append (node_with_updated_parent )
87+ else :
7688 self .node_list .append (new_node )
77- self .rewire (new_node , near_inds )
7889
79- if animation and i % 5 == 0 :
90+ if animation :
8091 self .draw_graph (rnd )
8192
82- if (not search_until_max_iter ) and new_node : # check reaching the goal
93+ if ((not self .search_until_max_iter )
94+ and new_node ): # if reaches goal
8395 last_index = self .search_best_goal_node ()
8496 if last_index is not None :
8597 return self .generate_final_course (last_index )
@@ -93,6 +105,21 @@ def planning(self, animation=True, search_until_max_iter=True):
93105 return None
94106
95107 def choose_parent (self , new_node , near_inds ):
108+ """
109+ Computes the cheapest point to new_node contained in the list
110+ near_inds and set such a node as the parent of new_node.
111+ Arguments:
112+ --------
113+ new_node, Node
114+ randomly generated node with a path from its neared point
115+ There are not coalitions between this node and th tree.
116+ near_inds: list
117+ Indices of indices of the nodes what are near to new_node
118+
119+ Returns.
120+ ------
121+ Node, a copy of new_node
122+ """
96123 if not near_inds :
97124 return None
98125
@@ -113,14 +140,18 @@ def choose_parent(self, new_node, near_inds):
113140
114141 min_ind = near_inds [costs .index (min_cost )]
115142 new_node = self .steer (self .node_list [min_ind ], new_node )
116- new_node .parent = self .node_list [min_ind ]
117143 new_node .cost = min_cost
118144
119145 return new_node
120146
121147 def search_best_goal_node (self ):
122- dist_to_goal_list = [self .calc_dist_to_goal (n .x , n .y ) for n in self .node_list ]
123- goal_inds = [dist_to_goal_list .index (i ) for i in dist_to_goal_list if i <= self .expand_dis ]
148+ dist_to_goal_list = [
149+ self .calc_dist_to_goal (n .x , n .y ) for n in self .node_list
150+ ]
151+ goal_inds = [
152+ dist_to_goal_list .index (i ) for i in dist_to_goal_list
153+ if i <= self .expand_dis
154+ ]
124155
125156 safe_goal_inds = []
126157 for goal_ind in goal_inds :
@@ -139,17 +170,48 @@ def search_best_goal_node(self):
139170 return None
140171
141172 def find_near_nodes (self , new_node ):
173+ """
174+ 1) defines a ball centered on new_node
175+ 2) Returns all nodes of the three that are inside this ball
176+ Arguments:
177+ ---------
178+ new_node: Node
179+ new randomly generated node, without collisions between
180+ its nearest node
181+ Returns:
182+ -------
183+ list
184+ List with the indices of the nodes inside the ball of
185+ radius r
186+ """
142187 nnode = len (self .node_list ) + 1
143188 r = self .connect_circle_dist * math .sqrt ((math .log (nnode ) / nnode ))
144- # if expand_dist exists, search vertices in a range no more than expand_dist
145- if hasattr (self , 'expand_dis' ):
189+ # if expand_dist exists, search vertices in a range no more than
190+ # expand_dist
191+ if hasattr (self , 'expand_dis' ):
146192 r = min (r , self .expand_dis )
147- dist_list = [(node .x - new_node .x ) ** 2 +
148- ( node . y - new_node . y ) ** 2 for node in self .node_list ]
149- near_inds = [dist_list .index (i ) for i in dist_list if i <= r ** 2 ]
193+ dist_list = [(node .x - new_node .x )** 2 + ( node . y - new_node . y ) ** 2
194+ for node in self .node_list ]
195+ near_inds = [dist_list .index (i ) for i in dist_list if i <= r ** 2 ]
150196 return near_inds
151197
152198 def rewire (self , new_node , near_inds ):
199+ """
200+ For each node in near_inds, this will check if it is cheaper to
201+ arrive to them from new_node.
202+ In such a case, this will re-assign the parent of the nodes in
203+ near_inds to new_node.
204+ Parameters:
205+ ----------
206+ new_node, Node
207+ Node randomly added which can be joined to the tree
208+
209+ near_inds, list of uints
210+ A list of indices of the self.new_node which contains
211+ nodes within a circle of a given radius.
212+ Remark: parent is designated in choose_parent.
213+
214+ """
153215 for i in near_inds :
154216 near_node = self .node_list [i ]
155217 edge_node = self .steer (new_node , near_node )
@@ -161,7 +223,12 @@ def rewire(self, new_node, near_inds):
161223 improved_cost = near_node .cost > edge_node .cost
162224
163225 if no_collision and improved_cost :
164- self .node_list [i ] = edge_node
226+ near_node .x = edge_node .x
227+ near_node .y = edge_node .y
228+ near_node .cost = edge_node .cost
229+ near_node .path_x = edge_node .path_x
230+ near_node .path_y = edge_node .path_y
231+ near_node .parent = edge_node .parent
165232 self .propagate_cost_to_leaves (new_node )
166233
167234 def calc_new_cost (self , from_node , to_node ):
@@ -192,10 +259,12 @@ def main():
192259 ] # [x,y,size(radius)]
193260
194261 # Set Initial parameters
195- rrt_star = RRTStar (start = [0 , 0 ],
196- goal = [6 , 10 ],
197- rand_area = [- 2 , 15 ],
198- obstacle_list = obstacle_list )
262+ rrt_star = RRTStar (
263+ start = [0 , 0 ],
264+ goal = [6 , 10 ],
265+ rand_area = [- 2 , 15 ],
266+ obstacle_list = obstacle_list ,
267+ expand_dis = 1 )
199268 path = rrt_star .planning (animation = show_animation )
200269
201270 if path is None :
@@ -206,10 +275,9 @@ def main():
206275 # Draw final path
207276 if show_animation :
208277 rrt_star .draw_graph ()
209- plt .plot ([x for (x , y ) in path ], [y for (x , y ) in path ], '-r ' )
278+ plt .plot ([x for (x , y ) in path ], [y for (x , y ) in path ], 'r-- ' )
210279 plt .grid (True )
211- plt .pause (0.01 ) # Need for Mac
212- plt .show ()
280+ plt .show ()
213281
214282
215283if __name__ == '__main__' :
0 commit comments