2
2
3
3
Histogram Filter 2D localization example
4
4
5
+
6
+ In this simulation, x,y are unknown, yaw is known.
7
+
8
+ Initial position is not needed.
9
+
5
10
author: Atsushi Sakai (@Atsushi_twi)
6
11
7
12
"""
11
16
import matplotlib .pyplot as plt
12
17
import copy
13
18
from scipy .stats import norm
19
+ from scipy .ndimage import gaussian_filter
20
+
21
+ # Parameters
22
+ NOISE_RANGE = 2.0 # [m] 1σ range noise parameter
23
+ NOISE_SPEED = 0.5 # [m/s] 1σ speed noise parameter
14
24
15
25
EXTEND_AREA = 10.0 # [m] grid map extention length
16
26
SIM_TIME = 50.0 # simulation time [s]
17
27
DT = 0.1 # time tick [s]
18
28
MAX_RANGE = 10.0 # maximum observation range
29
+ MOTION_STD = 1.0
30
+ RANGE_STD = 3.0 # standard diviation for gaussian distribution
19
31
20
32
show_animation = True
21
33
22
34
23
- def observation_update (gmap , z , std , xyreso , minx , miny ):
35
+ class grid_map ():
36
+
37
+ def __init__ (self ):
38
+ self .data = None
39
+ self .xyreso = None
40
+ self .minx = None
41
+ self .miny = None
42
+ self .maxx = None
43
+ self .maxx = None
44
+
45
+
46
+ def histogram_filter_localization (gmap , u , z , yaw , dx , dy ):
47
+
48
+ gmap , dx , dy = motion_update (gmap , u , yaw , dx , dy )
49
+
50
+ gmap = observation_update (gmap , z , RANGE_STD )
51
+
52
+ return gmap .data , dx , dy
53
+
54
+
55
+ def observation_update (gmap , z , std ):
24
56
25
57
for iz in range (z .shape [0 ]):
26
- for ix in range (len (gmap )):
27
- for iy in range (len (gmap [ix ])):
58
+ for ix in range (len (gmap . data )):
59
+ for iy in range (len (gmap . data [ix ])):
28
60
61
+ # observation range
29
62
zr = z [iz , 0 ]
30
- x = ix * xyreso + minx
31
- y = iy * xyreso + miny
32
63
64
+ # predicted range
65
+ x = ix * gmap .xyreso + gmap .minx
66
+ y = iy * gmap .xyreso + gmap .miny
33
67
d = math .sqrt ((x - z [iz , 1 ])** 2 + (y - z [iz , 2 ])** 2 )
34
68
69
+ # likelihood
35
70
pdf = (1.0 - norm .cdf (abs (d - zr ), 0.0 , std ))
36
- gmap [ix ][iy ] *= pdf
71
+ gmap . data [ix ][iy ] *= pdf
37
72
38
73
gmap = normalize_probability (gmap )
39
74
@@ -64,20 +99,16 @@ def motion_model(x, u):
64
99
return x
65
100
66
101
67
- def draw_heatmap (data , minx , maxx , miny , maxy , xyreso ):
68
- x , y = np .mgrid [slice (minx - xyreso / 2.0 , maxx + xyreso / 2.0 , xyreso ),
69
- slice (miny - xyreso / 2.0 , maxy + xyreso / 2.0 , xyreso )]
70
-
102
+ def draw_heatmap (data , mx , my ):
71
103
maxp = max ([max (igmap ) for igmap in data ])
72
- plt .pcolor (x , y , data , vmax = maxp , cmap = plt .cm .Blues )
104
+ plt .pcolor (mx , my , data , vmax = maxp , cmap = plt .cm .Blues )
73
105
plt .axis ("equal" )
74
106
75
107
76
108
def observation (xTrue , u , RFID ):
77
109
78
110
xTrue = motion_model (xTrue , u )
79
111
80
- # add noise to gps x-y
81
112
z = np .matrix (np .zeros ((0 , 3 )))
82
113
83
114
for i in range (len (RFID [:, 0 ])):
@@ -86,69 +117,79 @@ def observation(xTrue, u, RFID):
86
117
dy = xTrue [1 , 0 ] - RFID [i , 1 ]
87
118
d = math .sqrt (dx ** 2 + dy ** 2 )
88
119
if d <= MAX_RANGE :
89
- dn = d
120
+ # add noise to range observation
121
+ dn = d + np .random .randn () * NOISE_RANGE
90
122
zi = np .matrix ([dn , RFID [i , 0 ], RFID [i , 1 ]])
91
123
z = np .vstack ((z , zi ))
92
124
93
- return xTrue , z
125
+ # add noise to speed
126
+ ud = u [:, :]
127
+ ud [0 ] += np .random .randn () * NOISE_SPEED
128
+
129
+ return xTrue , z , ud
94
130
95
131
96
132
def normalize_probability (gmap ):
97
133
98
- sump = sum ([sum (igmap ) for igmap in gmap ])
134
+ sump = sum ([sum (igmap ) for igmap in gmap . data ])
99
135
100
- for i in range (len (gmap )):
101
- for ii in range (len (gmap [i ])):
102
- gmap [i ][ii ] /= sump
136
+ for i in range (len (gmap . data )):
137
+ for ii in range (len (gmap . data [i ])):
138
+ gmap . data [i ][ii ] /= sump
103
139
104
140
return gmap
105
141
106
142
107
143
def init_gmap (xyreso ):
108
144
109
- minx = - 15.0
110
- miny = - 5.0
111
- maxx = 15.0
112
- maxy = 25.0
113
- xw = int (round ((maxx - minx ) / xyreso ))
114
- yw = int (round ((maxy - miny ) / xyreso ))
145
+ gmap = grid_map ()
115
146
116
- gmap = [[1.0 for i in range (yw )] for i in range (xw )]
147
+ gmap .xyreso = xyreso
148
+ gmap .minx = - 15.0
149
+ gmap .miny = - 5.0
150
+ gmap .maxx = 15.0
151
+ gmap .maxy = 25.0
152
+ gmap .xw = int (round ((gmap .maxx - gmap .minx ) / gmap .xyreso ))
153
+ gmap .yw = int (round ((gmap .maxy - gmap .miny ) / gmap .xyreso ))
154
+
155
+ gmap .data = [[1.0 for i in range (gmap .yw )] for i in range (gmap .xw )]
117
156
gmap = normalize_probability (gmap )
118
157
119
- return gmap , minx , maxx , miny , maxy ,
158
+ return gmap
120
159
121
160
122
161
def map_shift (gmap , xshift , yshift ):
123
162
124
- tgmap = copy .deepcopy (gmap )
163
+ tgmap = copy .deepcopy (gmap . data )
125
164
126
- lenx = len (gmap )
127
- leny = len (gmap [0 ])
165
+ lenx = len (gmap . data )
166
+ leny = len (gmap . data [0 ])
128
167
129
168
for ix in range (lenx ):
130
169
for iy in range (leny ):
131
170
nix = ix + xshift
132
171
niy = iy + yshift
133
172
134
173
if nix >= 0 and nix < lenx and niy >= 0 and niy < leny :
135
- gmap [ix + xshift ][iy + yshift ] = tgmap [ix ][iy ]
174
+ gmap . data [ix + xshift ][iy + yshift ] = tgmap [ix ][iy ]
136
175
137
176
return gmap
138
177
139
178
140
- def motion_update (gmap , u , yaw , dx , dy , xyreso , minx , miny ):
179
+ def motion_update (gmap , u , yaw , dx , dy ):
141
180
142
181
dx += DT * math .cos (yaw ) * u [0 ]
143
182
dy += DT * math .sin (yaw ) * u [0 ]
144
183
145
- xshift = dx // xyreso
146
- yshift = dy // xyreso
184
+ xshift = dx // gmap . xyreso
185
+ yshift = dy // gmap . xyreso
147
186
148
187
if abs (xshift ) >= 1.0 or abs (yshift ) >= 1.0 :
149
188
gmap = map_shift (gmap , int (xshift ), int (yshift ))
150
- dx -= xshift * xyreso
151
- dy -= yshift * xyreso
189
+ dx -= xshift * gmap .xyreso
190
+ dy -= yshift * gmap .xyreso
191
+
192
+ gmap .data = gaussian_filter (gmap .data , sigma = MOTION_STD )
152
193
153
194
return gmap , dx , dy
154
195
@@ -157,7 +198,6 @@ def main():
157
198
print (__file__ + " start!!" )
158
199
159
200
xyreso = 0.5 # xy grid resolution
160
- STD = 1.0 # standard diviation for gaussian distribution
161
201
162
202
# RFID positions [x, y]
163
203
RFID = np .array ([[10.0 , 0.0 ],
@@ -169,24 +209,28 @@ def main():
169
209
170
210
xTrue = np .matrix (np .zeros ((4 , 1 )))
171
211
172
- gmap , minx , maxx , miny , maxy = init_gmap (xyreso )
212
+ gmap = init_gmap (xyreso )
173
213
174
214
dx , dy = 0.0 , 0.0
175
215
216
+ mx , my = np .mgrid [slice (gmap .minx - gmap .xyreso / 2.0 , gmap .maxx + gmap .xyreso / 2.0 , gmap .xyreso ),
217
+ slice (gmap .miny - gmap .xyreso / 2.0 , gmap .maxy + gmap .xyreso / 2.0 , gmap .xyreso )]
218
+
176
219
while SIM_TIME >= time :
177
220
time += DT
178
221
179
222
u = calc_input ()
180
- xTrue , z = observation (xTrue , u , RFID )
181
223
182
- gmap , dx , dy = motion_update (
183
- gmap , u , xTrue [2 , 0 ], dx , dy , xyreso , minx , miny )
224
+ # Orientation is known in this simulation
225
+ yaw = xTrue [2 , 0 ]
226
+ xTrue , z , ud = observation (xTrue , u , RFID )
184
227
185
- gmap = observation_update (gmap , z , STD , xyreso , minx , miny )
228
+ gmap .data , dx , dy = histogram_filter_localization (
229
+ gmap , u , z , yaw , dx , dy )
186
230
187
231
if show_animation :
188
232
plt .cla ()
189
- draw_heatmap (gmap , minx , maxx , miny , maxy , xyreso )
233
+ draw_heatmap (gmap . data , mx , my )
190
234
plt .plot (xTrue [0 , :], xTrue [1 , :], "xr" )
191
235
plt .plot (RFID [:, 0 ], RFID [:, 1 ], ".k" )
192
236
for i in range (z .shape [0 ]):
0 commit comments