11"""
22
3- A* grid based planning
3+ A* grid planning
44
55author: Atsushi Sakai(@Atsushi_twi)
66 Nikos Kanargias ([email protected] ) 1414
1515show_animation = True
1616
17+
1718class AStarPlanner :
1819
1920 def __init__ (self , ox , oy , reso , rr ):
2021 """
21- Intialize map for a star planning
22+ Initialize grid map for a star planning
2223
2324 ox: x position list of Obstacles [m]
2425 oy: y position list of Obstacles [m]
@@ -61,19 +62,19 @@ def planning(self, sx, sy, gx, gy):
6162 ngoal = self .Node (self .calc_xyindex (gx , self .minx ),
6263 self .calc_xyindex (gy , self .miny ), 0.0 , - 1 )
6364
64- openset , closedset = dict (), dict ()
65- openset [self .calc_index (nstart )] = nstart
65+ open_set , closed_set = dict (), dict ()
66+ open_set [self .calc_grid_index (nstart )] = nstart
6667
6768 while 1 :
6869 c_id = min (
69- openset , key = lambda o : openset [o ].cost + self .calc_heuristic (ngoal , openset [o ]))
70- current = openset [c_id ]
70+ open_set , key = lambda o : open_set [o ].cost + self .calc_heuristic (ngoal , open_set [o ]))
71+ current = open_set [c_id ]
7172
7273 # show graph
7374 if show_animation : # pragma: no cover
74- plt .plot (self .calc_position (current .x , self .minx ),
75- self .calc_position (current .y , self .miny ), "xc" )
76- if len (closedset .keys ()) % 10 == 0 :
75+ plt .plot (self .calc_grid_position (current .x , self .minx ),
76+ self .calc_grid_position (current .y , self .miny ), "xc" )
77+ if len (closed_set .keys ()) % 10 == 0 :
7778 plt .pause (0.001 )
7879
7980 if current .x == ngoal .x and current .y == ngoal .y :
@@ -83,66 +84,76 @@ def planning(self, sx, sy, gx, gy):
8384 break
8485
8586 # Remove the item from the open set
86- del openset [c_id ]
87+ del open_set [c_id ]
8788
8889 # Add it to the closed set
89- closedset [c_id ] = current
90+ closed_set [c_id ] = current
9091
9192 # expand search grid based on motion model
9293 for i , _ in enumerate (self .motion ):
9394 node = self .Node (current .x + self .motion [i ][0 ],
9495 current .y + self .motion [i ][1 ],
9596 current .cost + self .motion [i ][2 ], c_id )
96- n_id = self .calc_index (node )
97+ n_id = self .calc_grid_index (node )
9798
98- if n_id in closedset :
99+ # If the node is in closed_set, do nothing
100+ if n_id in closed_set :
99101 continue
100102
103+ # If the node is not safe, do nothing
101104 if not self .verify_node (node ):
102105 continue
103106
104- if n_id not in openset :
105- openset [n_id ] = node # Discover a new node
107+ if n_id not in open_set :
108+ open_set [n_id ] = node # discovered a new node
106109 else :
107- if openset [n_id ].cost >= node .cost :
108- # This path is the best until now. record it!
109- openset [n_id ] = node
110+ if open_set [n_id ].cost >= node .cost :
111+ # This path is the best until now. record it
112+ open_set [n_id ] = node
110113
111- rx , ry = self .calc_final_path (ngoal , closedset )
114+ rx , ry = self .calc_final_path (ngoal , closed_set )
112115
113116 return rx , ry
114117
115118 def calc_final_path (self , ngoal , closedset ):
116119 # generate final course
117- rx , ry = [self .calc_position (ngoal .x , self .minx )], [
118- self .calc_position (ngoal .y , self .miny )]
120+ rx , ry = [self .calc_grid_position (ngoal .x , self .minx )], [
121+ self .calc_grid_position (ngoal .y , self .miny )]
119122 pind = ngoal .pind
120123 while pind != - 1 :
121124 n = closedset [pind ]
122- rx .append (self .calc_position (n .x , self .minx ))
123- ry .append (self .calc_position (n .y , self .miny ))
125+ rx .append (self .calc_grid_position (n .x , self .minx ))
126+ ry .append (self .calc_grid_position (n .y , self .miny ))
124127 pind = n .pind
125128
126129 return rx , ry
127130
128- def calc_heuristic (self , n1 , n2 ):
131+ @staticmethod
132+ def calc_heuristic (n1 , n2 ):
129133 w = 1.0 # weight of heuristic
130- d = w * math .sqrt ((n1 .x - n2 .x )** 2 + (n1 .y - n2 .y )** 2 )
134+ d = w * math .sqrt ((n1 .x - n2 .x ) ** 2 + (n1 .y - n2 .y ) ** 2 )
131135 return d
132136
133- def calc_position (self , index , minp ):
134- pos = index * self .reso + minp
137+ def calc_grid_position (self , index , minp ):
138+ """
139+ calc grid position
140+
141+ :param index:
142+ :param minp:
143+ :return:
144+ """
145+ pos = index * self .reso + minp
135146 return pos
136147
137- def calc_xyindex (self , position , minp ):
138- return round ((position - minp ) / self .reso )
148+ def calc_xyindex (self , position , min_pos ):
149+ return round ((position - min_pos ) / self .reso )
139150
140- def calc_index (self , node ):
151+ def calc_grid_index (self , node ):
141152 return (node .y - self .miny ) * self .xwidth + (node .x - self .minx )
142153
143154 def verify_node (self , node ):
144- px = self .calc_position (node .x , self .minx )
145- py = self .calc_position (node .y , self .miny )
155+ px = self .calc_grid_position (node .x , self .minx )
156+ py = self .calc_grid_position (node .y , self .miny )
146157
147158 if px < self .minx :
148159 return False
@@ -153,6 +164,7 @@ def verify_node(self, node):
153164 elif py >= self .maxy :
154165 return False
155166
167+ # collision check
156168 if self .obmap [node .x ][node .y ]:
157169 return False
158170
@@ -169,25 +181,26 @@ def calc_obstacle_map(self, ox, oy):
169181 print ("maxx:" , self .maxx )
170182 print ("maxy:" , self .maxy )
171183
172- self .xwidth = round ((self .maxx - self .minx )/ self .reso )
173- self .ywidth = round ((self .maxy - self .miny )/ self .reso )
184+ self .xwidth = round ((self .maxx - self .minx ) / self .reso )
185+ self .ywidth = round ((self .maxy - self .miny ) / self .reso )
174186 print ("xwidth:" , self .xwidth )
175187 print ("ywidth:" , self .ywidth )
176188
177189 # obstacle map generation
178190 self .obmap = [[False for i in range (self .ywidth )]
179191 for i in range (self .xwidth )]
180192 for ix in range (self .xwidth ):
181- x = self .calc_position (ix , self .minx )
193+ x = self .calc_grid_position (ix , self .minx )
182194 for iy in range (self .ywidth ):
183- y = self .calc_position (iy , self .miny )
195+ y = self .calc_grid_position (iy , self .miny )
184196 for iox , ioy in zip (ox , oy ):
185- d = math .sqrt ((iox - x )** 2 + (ioy - y )** 2 )
197+ d = math .sqrt ((iox - x ) ** 2 + (ioy - y ) ** 2 )
186198 if d <= self .rr :
187199 self .obmap [ix ][iy ] = True
188200 break
189201
190- def get_motion_model (self ):
202+ @staticmethod
203+ def get_motion_model ():
191204 # dx, dy, cost
192205 motion = [[1 , 0 , 1 ],
193206 [0 , 1 , 1 ],
0 commit comments