88
99import matplotlib .pyplot as plt
1010import math
11- import random
1211import numpy as np
1312import itertools
13+ import random
1414
1515show_animation = True
1616
1717
18+ class Rectangle ():
19+
20+ def __init__ (self ):
21+ self .a = [None ] * 4
22+ self .b = [None ] * 4
23+ self .c = [None ] * 4
24+
25+ self .rect_c_x = [None ] * 5
26+ self .rect_c_y = [None ] * 5
27+
28+ def plot (self ):
29+ self .calc_rect_contour ()
30+ plt .plot (self .rect_c_x , self .rect_c_y , "-r" )
31+
32+ def calc_rect_contour (self ):
33+
34+ self .rect_c_x [0 ], self .rect_c_y [0 ] = self .calc_cross_point (
35+ self .a [0 :2 ], self .b [0 :2 ], self .c [0 :2 ])
36+ self .rect_c_x [1 ], self .rect_c_y [1 ] = self .calc_cross_point (
37+ self .a [1 :3 ], self .b [1 :3 ], self .c [1 :3 ])
38+ self .rect_c_x [2 ], self .rect_c_y [2 ] = self .calc_cross_point (
39+ self .a [2 :4 ], self .b [2 :4 ], self .c [2 :4 ])
40+ self .rect_c_x [3 ], self .rect_c_y [3 ] = self .calc_cross_point (
41+ [self .a [3 ], self .a [0 ]], [self .b [3 ], self .b [0 ]], [self .c [3 ], self .c [0 ]])
42+ self .rect_c_x [4 ], self .rect_c_y [4 ] = self .rect_c_x [0 ], self .rect_c_y [0 ]
43+
44+ def calc_cross_point (self , a , b , c ):
45+ x = (b [0 ] * - c [1 ] - b [1 ] * - c [0 ]) / (a [0 ] * b [1 ] - a [1 ] * b [0 ])
46+ y = (a [1 ] * - c [0 ] - a [0 ] * - c [1 ]) / (a [0 ] * b [1 ] - a [1 ] * b [0 ])
47+ return x , y
48+
49+
1850class VehicleSimulator ():
1951
2052 def __init__ (self , ix , iy , iyaw , iv , max_v , w , L ):
@@ -36,11 +68,11 @@ def update(self, dt, a, omega):
3668 self .v = self .max_v
3769
3870 def plot (self ):
39- plt .plot (self .x , self .y , ".r " )
71+ plt .plot (self .x , self .y , ".b " )
4072
4173 # convert global coordinate
4274 gx , gy = self .calc_global_contour ()
43- plt .plot (gx , gy , "-r " )
75+ plt .plot (gx , gy , "--b " )
4476
4577 def calc_global_contour (self ):
4678 gx = [(ix * math .cos (self .yaw ) + iy * math .sin (self .yaw ))
@@ -99,7 +131,7 @@ def get_observation_points(vlist, angle_reso):
99131
100132 for vx , vy in zip (gx , gy ):
101133 vangle = math .atan2 (vy , vx )
102- vr = math .hypot (vx , vy ) # * random.uniform(0.95 , 1.05 )
134+ vr = math .hypot (vx , vy ) * random .uniform (0.99 , 1.01 )
103135
104136 x .append (vx )
105137 y .append (vy )
@@ -132,6 +164,84 @@ def ray_casting_filter(xl, yl, thetal, rangel, angle_reso):
132164 return rx , ry
133165
134166
167+ def calc_area_criterion (c1 , c2 ):
168+ c1_max = max (c1 )
169+ c2_max = max (c2 )
170+ c1_min = min (c1 )
171+ c2_min = min (c2 )
172+
173+ alpha = - (c1_max - c1_min ) * (c2_max - c2_min )
174+
175+ return alpha
176+
177+
178+ def calc_closeness_criterion (c1 , c2 ):
179+ c1_max = max (c1 )
180+ c2_max = max (c2 )
181+ c1_min = min (c1 )
182+ c2_min = min (c2 )
183+
184+ D1 = [min ([np .linalg .norm (c1_max - ic1 ),
185+ np .linalg .norm (ic1 - c1_min )]) for ic1 in c1 ]
186+ D2 = [min ([np .linalg .norm (c2_max - ic2 ),
187+ np .linalg .norm (ic2 - c2_min )]) for ic2 in c2 ]
188+
189+ d0 = 0.01
190+ beta = 0
191+ for i , _ in enumerate (D1 ):
192+ d = max (min ([D1 [i ], D2 [i ]]), d0 )
193+ beta += (1.0 / d )
194+
195+ return beta
196+
197+
198+ def rectangle_search (x , y ):
199+
200+ X = np .array ([x , y ]).T
201+
202+ dtheta = np .deg2rad (0.5 )
203+ minp = (- float ('inf' ), None )
204+ for theta in np .arange (0.0 , math .pi / 2.0 - dtheta , dtheta ):
205+
206+ e1 = np .array ([math .cos (theta ), math .sin (theta )])
207+ e2 = np .array ([- math .sin (theta ), math .cos (theta )])
208+
209+ c1 = X @ e1 .T
210+ c2 = X @ e2 .T
211+
212+ # alpha = calc_area_criterion(c1, c2)
213+ beta = calc_closeness_criterion (c1 , c2 )
214+
215+ # cost = alpha
216+ cost = beta
217+
218+ if minp [0 ] < cost :
219+ minp = (cost , theta )
220+
221+ # calc best rectangle
222+ sin_s = math .sin (minp [1 ])
223+ cos_s = math .cos (minp [1 ])
224+
225+ c1_s = X @ np .array ([cos_s , sin_s ]).T
226+ c2_s = X @ np .array ([- sin_s , cos_s ]).T
227+
228+ rect = Rectangle ()
229+ rect .a [0 ] = cos_s
230+ rect .b [0 ] = sin_s
231+ rect .c [0 ] = min (c1_s )
232+ rect .a [1 ] = - sin_s
233+ rect .b [1 ] = cos_s
234+ rect .c [1 ] = min (c2_s )
235+ rect .a [2 ] = cos_s
236+ rect .b [2 ] = sin_s
237+ rect .c [2 ] = max (c1_s )
238+ rect .a [3 ] = - sin_s
239+ rect .b [3 ] = cos_s
240+ rect .c [3 ] = max (c2_s )
241+
242+ return rect
243+
244+
135245def adoptive_range_segmentation (ox , oy ):
136246
137247 alpha = 0.2
@@ -167,7 +277,7 @@ def main():
167277 simtime = 30.0 # simulation time
168278 dt = 0.2 # time tick
169279
170- angle_reso = np .deg2rad (3 .0 ) # sensor angle resolution
280+ angle_reso = np .deg2rad (2 .0 ) # sensor angle resolution
171281
172282 v1 = VehicleSimulator (- 10.0 , 0.0 , np .deg2rad (90.0 ),
173283 0.0 , 50.0 / 3.6 , 3.0 , 5.0 )
@@ -186,20 +296,34 @@ def main():
186296 # step1: Adaptive Range Segmentation
187297 idsets = adoptive_range_segmentation (ox , oy )
188298
299+ # step2 Rectangle search
300+ rects = []
301+ for ids in idsets : # for each cluster
302+ cx = [ox [i ] for i in range (len (ox )) if i in ids ]
303+ cy = [oy [i ] for i in range (len (oy )) if i in ids ]
304+ rects .append (rectangle_search (cx , cy ))
305+
189306 if show_animation : # pragma: no cover
190307 plt .cla ()
191308 plt .axis ("equal" )
192309 plt .plot (0.0 , 0.0 , "*r" )
193310 v1 .plot ()
194311 v2 .plot ()
195312
196- # plt.plot(ox, oy, "ob")
313+ # Plot range observation
197314 for ids in idsets :
198- plt .plot ([ox [i ] for i in range (len (ox )) if i in ids ],
199- [oy [i ] for i in range (len (ox )) if i in ids ],
200- "o" )
201- # plt.plot(x, y, "xr")
202- # plot_circle(ex, ey, er, "-r")
315+ x = [ox [i ] for i in range (len (ox )) if i in ids ]
316+ y = [oy [i ] for i in range (len (ox )) if i in ids ]
317+
318+ for (ix , iy ) in zip (x , y ):
319+ plt .plot ([0.0 , ix ], [0.0 , iy ], "-og" )
320+
321+ # plt.plot([ox[i] for i in range(len(ox)) if i in ids],
322+ # [oy[i] for i in range(len(ox)) if i in ids],
323+ # "o")
324+ for rect in rects :
325+ rect .plot ()
326+
203327 plt .pause (0.1 )
204328
205329 print ("Done" )
0 commit comments