1+ """ 
2+ 
3+ A* grid based planning 
4+ 
5+ author: Atsushi Sakai(@Atsushi_twi) 
6+         Nikos Kanargias ([email protected] ) 7+ 
8+ See Wikipedia article (https://en.wikipedia.org/wiki/A*_search_algorithm) 
9+ 
10+ """ 
11+ 
12+ import  matplotlib .pyplot  as  plt 
13+ import  math 
14+ import  heapq 
15+ 
16+ _round  =  round 
17+ def  round (x ):
18+     return  int (_round (x ))
19+ 
20+ show_animation  =  False 
21+ 
22+ class  Node :
23+ 
24+     def  __init__ (self , x , y , cost , pind ):
25+         self .x  =  x 
26+         self .y  =  y 
27+         self .cost  =  cost 
28+         self .pind  =  pind 
29+ 
30+     def  __str__ (self ):
31+         return  str (self .x ) +  ","  +  str (self .y ) +  ","  +  str (self .cost ) +  ","  +  str (self .pind )
32+ 
33+ 
34+ def  calc_final_path (ngoal , closedset , reso ):
35+     # generate final course 
36+     rx , ry  =  [ngoal .x  *  reso ], [ngoal .y  *  reso ]
37+     pind  =  ngoal .pind 
38+     while  pind  !=  - 1 :
39+         n  =  closedset [pind ]
40+         rx .append (n .x  *  reso )
41+         ry .append (n .y  *  reso )
42+         pind  =  n .pind 
43+ 
44+     return  rx , ry 
45+ 
46+ 
47+ def  dp_planning (sx , sy , gx , gy , ox , oy , reso , rr ):
48+     """ 
49+     gx: goal x position [m] 
50+     gx: goal x position [m] 
51+     ox: x position list of Obstacles [m] 
52+     oy: y position list of Obstacles [m] 
53+     reso: grid resolution [m] 
54+     rr: robot radius[m] 
55+     """ 
56+ 
57+     nstart  =  Node (round (sx  /  reso ), round (sy  /  reso ), 0.0 , - 1 )
58+     ngoal  =  Node (round (gx  /  reso ), round (gy  /  reso ), 0.0 , - 1 )
59+     ox  =  [iox  /  reso  for  iox  in  ox ]
60+     oy  =  [ioy  /  reso  for  ioy  in  oy ]
61+ 
62+     obmap , minx , miny , maxx , maxy , xw , yw  =  calc_obstacle_map (ox , oy , reso , rr )
63+ 
64+     motion  =  get_motion_model ()
65+ 
66+     openset , closedset  =  dict (), dict ()
67+     openset [calc_index (ngoal , xw , minx , miny )] =  ngoal 
68+     pq  =  []
69+     pq .append ((0 , calc_index (ngoal , xw , minx , miny )))
70+     
71+ 
72+     while  1 :
73+         if  not  pq :
74+             break 
75+         cost , c_id  =  heapq .heappop (pq )
76+         if  openset .has_key (c_id ):
77+             current  =  openset [c_id ]
78+             closedset [c_id ] =  current 
79+             openset .pop (c_id )
80+         else :
81+             continue 
82+ 
83+         # show graph 
84+         if  show_animation :  # pragma: no cover 
85+             plt .plot (current .x  *  reso , current .y  *  reso , "xc" )
86+             if  len (closedset .keys ()) %  10  ==  0 :
87+                 plt .pause (0.001 )
88+ 
89+         # Remove the item from the open set 
90+         
91+ 
92+         # expand search grid based on motion model 
93+         for  i , _  in  enumerate (motion ):
94+             node  =  Node (current .x  +  motion [i ][0 ],
95+                         current .y  +  motion [i ][1 ],
96+                         current .cost  +  motion [i ][2 ], c_id )
97+             n_id  =  calc_index (node , xw , minx , miny )
98+ 
99+             if  n_id  in  closedset :
100+                 continue 
101+ 
102+             if  not  verify_node (node , obmap , minx , miny , maxx , maxy ):
103+                 continue 
104+ 
105+             if  n_id  not  in   openset :
106+                 openset [n_id ] =  node   # Discover a new node 
107+                 heapq .heappush (pq , (node .cost , calc_index (node , xw , minx , miny )))
108+             else :
109+                 if  openset [n_id ].cost  >=  node .cost :
110+                     # This path is the best until now. record it! 
111+                     openset [n_id ] =  node 
112+                     heapq .heappush (pq , (node .cost , calc_index (node , xw , minx , miny )))
113+ 
114+ 
115+     rx , ry  =  calc_final_path (closedset [calc_index (nstart , xw , minx , miny )], closedset , reso )
116+ 
117+     return  rx , ry , closedset 
118+ 
119+ 
120+ def  calc_heuristic (n1 , n2 ):
121+     w  =  1.0   # weight of heuristic 
122+     d  =  w  *  math .sqrt ((n1 .x  -  n2 .x )** 2  +  (n1 .y  -  n2 .y )** 2 )
123+     return  d 
124+ 
125+ 
126+ def  verify_node (node , obmap , minx , miny , maxx , maxy ):
127+ 
128+     if  node .x  <  minx :
129+         return  False 
130+     elif  node .y  <  miny :
131+         return  False 
132+     elif  node .x  >=  maxx :
133+         return  False 
134+     elif  node .y  >=  maxy :
135+         return  False 
136+ 
137+     if  obmap [node .x ][node .y ]:
138+         return  False 
139+ 
140+     return  True 
141+ 
142+ 
143+ def  calc_obstacle_map (ox , oy , reso , vr ):
144+ 
145+     minx  =  round (min (ox ))
146+     miny  =  round (min (oy ))
147+     maxx  =  round (max (ox ))
148+     maxy  =  round (max (oy ))
149+     #  print("minx:", minx) 
150+     #  print("miny:", miny) 
151+     #  print("maxx:", maxx) 
152+     #  print("maxy:", maxy) 
153+ 
154+     xwidth  =  round (maxx  -  minx )
155+     ywidth  =  round (maxy  -  miny )
156+     #  print("xwidth:", xwidth) 
157+     #  print("ywidth:", ywidth) 
158+ 
159+     # obstacle map generation 
160+     obmap  =  [[False  for  i  in  range (xwidth )] for  i  in  range (ywidth )]
161+     for  ix  in  range (xwidth ):
162+         x  =  ix  +  minx 
163+         for  iy  in  range (ywidth ):
164+             y  =  iy  +  miny 
165+             #  print(x, y) 
166+             for  iox , ioy  in  zip (ox , oy ):
167+                 d  =  math .sqrt ((iox  -  x )** 2  +  (ioy  -  y )** 2 )
168+                 if  d  <=  vr  /  reso :
169+                     obmap [ix ][iy ] =  True 
170+                     break 
171+ 
172+     return  obmap , minx , miny , maxx , maxy , xwidth , ywidth 
173+ 
174+ 
175+ def  calc_index (node , xwidth , xmin , ymin ):
176+     return  (node .y  -  ymin ) *  xwidth  +  (node .x  -  xmin )
177+ 
178+ 
179+ def  get_motion_model ():
180+     # dx, dy, cost 
181+     motion  =  [[1 , 0 , 1 ],
182+               [0 , 1 , 1 ],
183+               [- 1 , 0 , 1 ],
184+               [0 , - 1 , 1 ],
185+               [- 1 , - 1 , math .sqrt (2 )],
186+               [- 1 , 1 , math .sqrt (2 )],
187+               [1 , - 1 , math .sqrt (2 )],
188+               [1 , 1 , math .sqrt (2 )]]
189+ 
190+     return  motion 
191+ 
192+ 
193+ def  main ():
194+     print (__file__  +  " start!!" )
195+ 
196+     # start and goal position 
197+     sx  =  10.0   # [m] 
198+     sy  =  10.0   # [m] 
199+     gx  =  50.0   # [m] 
200+     gy  =  50.0   # [m] 
201+     grid_size  =  2.0   # [m] 
202+     robot_size  =  1.0   # [m] 
203+ 
204+     ox , oy  =  [], []
205+ 
206+     for  i  in  range (60 ):
207+         ox .append (i )
208+         oy .append (0.0 )
209+     for  i  in  range (60 ):
210+         ox .append (60.0 )
211+         oy .append (i )
212+     for  i  in  range (61 ):
213+         ox .append (i )
214+         oy .append (60.0 )
215+     for  i  in  range (61 ):
216+         ox .append (0.0 )
217+         oy .append (i )
218+     for  i  in  range (40 ):
219+         ox .append (20.0 )
220+         oy .append (i )
221+     for  i  in  range (40 ):
222+         ox .append (40.0 )
223+         oy .append (60.0  -  i )
224+ 
225+     if  show_animation :  # pragma: no cover 
226+         plt .plot (ox , oy , ".k" )
227+         plt .plot (sx , sy , "xr" )
228+         plt .plot (gx , gy , "xb" )
229+         plt .grid (True )
230+         plt .axis ("equal" )
231+ 
232+     rx , ry , _  =  dp_planning (sx , sy , gx , gy , ox , oy , grid_size , robot_size )
233+ 
234+     if  show_animation :  # pragma: no cover 
235+         plt .plot (rx , ry , "-r" )
236+         plt .show ()
237+ 
238+ 
239+ if  __name__  ==  '__main__' :
240+     show_animation  =  True 
241+     main ()
0 commit comments