27
27
STATE_SIZE = 3 # State size [x,y,yaw]
28
28
LM_SIZE = 2 # LM srate size [x,y]
29
29
N_PARTICLE = 100 # number of particle
30
- NTH = N_PARTICLE / 1.0 # Number of particle for re-sampling
30
+ NTH = N_PARTICLE / 1.5 # Number of particle for re-sampling
31
31
32
32
show_animation = True
33
33
@@ -41,9 +41,9 @@ def __init__(self, N_LM):
41
41
self .yaw = 0.0
42
42
self .P = np .eye (3 )
43
43
# landmark x-y positions
44
- self .lm = np .matrix ( np . zeros ((N_LM , LM_SIZE ) ))
44
+ self .lm = np .zeros ((N_LM , LM_SIZE ))
45
45
# landmark position covariance
46
- self .lmP = np .matrix ( np . zeros ((N_LM * LM_SIZE , LM_SIZE ) ))
46
+ self .lmP = np .zeros ((N_LM * LM_SIZE , LM_SIZE ))
47
47
48
48
49
49
def fast_slam2 (particles , u , z ):
@@ -97,7 +97,7 @@ def predict_particles(particles, u):
97
97
px [0 , 0 ] = particles [i ].x
98
98
px [1 , 0 ] = particles [i ].y
99
99
px [2 , 0 ] = particles [i ].yaw
100
- ud = u + (np .matrix ( np . random .randn (1 , 2 )) * R ).T # add noise
100
+ ud = u + (np .random .randn (1 , 2 ) @ R ).T # add noise
101
101
px = motion_model (px , ud )
102
102
particles [i ].x = px [0 , 0 ]
103
103
particles [i ].y = px [1 , 0 ]
@@ -108,9 +108,9 @@ def predict_particles(particles, u):
108
108
109
109
def add_new_lm (particle , z , Q ):
110
110
111
- r = z [0 , 0 ]
112
- b = z [0 , 1 ]
113
- lm_id = int (z [0 , 2 ])
111
+ r = z [0 ]
112
+ b = z [1 ]
113
+ lm_id = int (z [2 ])
114
114
115
115
s = math .sin (pi_2_pi (particle .yaw + b ))
116
116
c = math .cos (pi_2_pi (particle .yaw + b ))
@@ -119,10 +119,10 @@ def add_new_lm(particle, z, Q):
119
119
particle .lm [lm_id , 1 ] = particle .y + r * s
120
120
121
121
# covariance
122
- Gz = np .matrix ([[c , - r * s ],
123
- [s , r * c ]])
122
+ Gz = np .array ([[c , - r * s ],
123
+ [s , r * c ]])
124
124
125
- particle .lmP [2 * lm_id :2 * lm_id + 2 ] = Gz * Q * Gz .T
125
+ particle .lmP [2 * lm_id :2 * lm_id + 2 ] = Gz @ Q @ Gz .T
126
126
127
127
return particle
128
128
@@ -133,44 +133,45 @@ def compute_jacobians(particle, xf, Pf, Q):
133
133
d2 = dx ** 2 + dy ** 2
134
134
d = math .sqrt (d2 )
135
135
136
- zp = np .matrix ([[d , pi_2_pi (math .atan2 (dy , dx ) - particle .yaw )]]).T
136
+ zp = np .array (
137
+ [d , pi_2_pi (math .atan2 (dy , dx ) - particle .yaw )]).reshape (2 , 1 )
137
138
138
- Hv = np .matrix ([[- dx / d , - dy / d , 0.0 ],
139
- [dy / d2 , - dx / d2 , - 1.0 ]])
139
+ Hv = np .array ([[- dx / d , - dy / d , 0.0 ],
140
+ [dy / d2 , - dx / d2 , - 1.0 ]])
140
141
141
- Hf = np .matrix ([[dx / d , dy / d ],
142
- [- dy / d2 , dx / d2 ]])
142
+ Hf = np .array ([[dx / d , dy / d ],
143
+ [- dy / d2 , dx / d2 ]])
143
144
144
- Sf = Hf * Pf * Hf .T + Q
145
+ Sf = Hf @ Pf @ Hf .T + Q
145
146
146
147
return zp , Hv , Hf , Sf
147
148
148
149
149
150
def update_KF_with_cholesky (xf , Pf , v , Q , Hf ):
150
- PHt = Pf * Hf .T
151
- S = Hf * PHt + Q
151
+ PHt = Pf @ Hf .T
152
+ S = Hf @ PHt + Q
152
153
153
154
S = (S + S .T ) * 0.5
154
155
SChol = np .linalg .cholesky (S ).T
155
156
SCholInv = np .linalg .inv (SChol )
156
- W1 = PHt * SCholInv
157
- W = W1 * SCholInv .T
157
+ W1 = PHt @ SCholInv
158
+ W = W1 @ SCholInv .T
158
159
159
- x = xf + W * v
160
- P = Pf - W1 * W1 .T
160
+ x = xf + W @ v
161
+ P = Pf - W1 @ W1 .T
161
162
162
163
return x , P
163
164
164
165
165
166
def update_landmark (particle , z , Q ):
166
167
167
- lm_id = int (z [0 , 2 ])
168
- xf = np .matrix (particle .lm [lm_id , :]).T
169
- Pf = np .matrix (particle .lmP [2 * lm_id :2 * lm_id + 2 , : ])
168
+ lm_id = int (z [2 ])
169
+ xf = np .array (particle .lm [lm_id , :]).reshape ( 2 , 1 )
170
+ Pf = np .array (particle .lmP [2 * lm_id :2 * lm_id + 2 ])
170
171
171
172
zp , Hv , Hf , Sf = compute_jacobians (particle , xf , Pf , Q )
172
173
173
- dz = z [0 , 0 : 2 ].T - zp
174
+ dz = z [0 : 2 ].reshape ( 2 , 1 ) - zp
174
175
dz [1 , 0 ] = pi_2_pi (dz [1 , 0 ])
175
176
176
177
xf , Pf = update_KF_with_cholesky (xf , Pf , dz , Q , Hf )
@@ -183,21 +184,20 @@ def update_landmark(particle, z, Q):
183
184
184
185
def compute_weight (particle , z , Q ):
185
186
186
- lm_id = int (z [0 , 2 ])
187
- xf = np .matrix (particle .lm [lm_id , :]).T
188
- Pf = np .matrix (particle .lmP [2 * lm_id :2 * lm_id + 2 ])
187
+ lm_id = int (z [2 ])
188
+ xf = np .array (particle .lm [lm_id , :]).reshape ( 2 , 1 )
189
+ Pf = np .array (particle .lmP [2 * lm_id :2 * lm_id + 2 ])
189
190
zp , Hv , Hf , Sf = compute_jacobians (particle , xf , Pf , Q )
190
191
191
- dz = z [0 , 0 : 2 ].T - zp
192
+ dz = z [0 : 2 ].reshape ( 2 , 1 ) - zp
192
193
dz [1 , 0 ] = pi_2_pi (dz [1 , 0 ])
193
194
194
195
try :
195
196
invS = np .linalg .inv (Sf )
196
197
except np .linalg .linalg .LinAlgError :
197
- print ("singuler" )
198
198
return 1.0
199
199
200
- num = math .exp (- 0.5 * dz .T * invS * dz )
200
+ num = math .exp (- 0.5 * dz .T @ invS @ dz )
201
201
den = 2.0 * math .pi * math .sqrt (np .linalg .det (Sf ))
202
202
203
203
w = num / den
@@ -207,22 +207,22 @@ def compute_weight(particle, z, Q):
207
207
208
208
def proposal_sampling (particle , z , Q ):
209
209
210
- lm_id = int (z [0 , 2 ])
211
- xf = np . matrix ( particle .lm [lm_id , :]). T
212
- Pf = np . matrix ( particle .lmP [2 * lm_id :2 * lm_id + 2 ])
210
+ lm_id = int (z [2 ])
211
+ xf = particle .lm [lm_id , :]. reshape ( 2 , 1 )
212
+ Pf = particle .lmP [2 * lm_id :2 * lm_id + 2 ]
213
213
# State
214
- x = np .matrix ([[ particle .x , particle .y , particle .yaw ]]). T
214
+ x = np .array ([ particle .x , particle .y , particle .yaw ]). reshape ( 3 , 1 )
215
215
P = particle .P
216
216
zp , Hv , Hf , Sf = compute_jacobians (particle , xf , Pf , Q )
217
217
218
218
Sfi = np .linalg .inv (Sf )
219
- dz = z [0 , 0 : 2 ].T - zp
220
- dz [1 , 0 ] = pi_2_pi (dz [1 , 0 ])
219
+ dz = z [0 : 2 ].reshape ( 2 , 1 ) - zp
220
+ dz [1 ] = pi_2_pi (dz [1 ])
221
221
222
222
Pi = np .linalg .inv (P )
223
223
224
- particle .P = np .linalg .inv (Hv .T * Sfi * Hv + Pi ) # proposal covariance
225
- x += particle .P * Hv .T * Sfi * dz # proposal mean
224
+ particle .P = np .linalg .inv (Hv .T @ Sfi @ Hv + Pi ) # proposal covariance
225
+ x += particle .P @ Hv .T @ Sfi @ dz # proposal mean
226
226
227
227
particle .x = x [0 , 0 ]
228
228
particle .y = x [1 , 0 ]
@@ -233,21 +233,20 @@ def proposal_sampling(particle, z, Q):
233
233
234
234
def update_with_observation (particles , z ):
235
235
236
- for iz in range (len (z [:, 0 ])):
237
-
238
- lmid = int (z [iz , 2 ])
236
+ for iz in range (len (z [0 , :])):
237
+ lmid = int (z [2 , iz ])
239
238
240
239
for ip in range (N_PARTICLE ):
241
240
# new landmark
242
241
if abs (particles [ip ].lm [lmid , 0 ]) <= 0.01 :
243
- particles [ip ] = add_new_lm (particles [ip ], z [iz , : ], Q )
242
+ particles [ip ] = add_new_lm (particles [ip ], z [:, iz ], Q )
244
243
# known landmark
245
244
else :
246
- w = compute_weight (particles [ip ], z [iz , : ], Q )
245
+ w = compute_weight (particles [ip ], z [:, iz ], Q )
247
246
particles [ip ].w *= w
248
247
249
- particles [ip ] = update_landmark (particles [ip ], z [iz , : ], Q )
250
- particles [ip ] = proposal_sampling (particles [ip ], z [iz , : ], Q )
248
+ particles [ip ] = update_landmark (particles [ip ], z [:, iz ], Q )
249
+ particles [ip ] = proposal_sampling (particles [ip ], z [:, iz ], Q )
251
250
252
251
return particles
253
252
@@ -263,20 +262,20 @@ def resampling(particles):
263
262
for i in range (N_PARTICLE ):
264
263
pw .append (particles [i ].w )
265
264
266
- pw = np .matrix (pw )
265
+ pw = np .array (pw )
267
266
268
- Neff = 1.0 / (pw * pw .T )[ 0 , 0 ] # Effective particle number
267
+ Neff = 1.0 / (pw @ pw .T ) # Effective particle number
269
268
# print(Neff)
270
269
271
270
if Neff < NTH : # resampling
272
271
wcum = np .cumsum (pw )
273
272
base = np .cumsum (pw * 0.0 + 1 / N_PARTICLE ) - 1 / N_PARTICLE
274
- resampleid = base + np .random .rand (base .shape [1 ]) / N_PARTICLE
273
+ resampleid = base + np .random .rand (base .shape [0 ]) / N_PARTICLE
275
274
276
275
inds = []
277
276
ind = 0
278
277
for ip in range (N_PARTICLE ):
279
- while ((ind < wcum .shape [1 ] - 1 ) and (resampleid [0 , ip ] > wcum [0 , ind ])):
278
+ while ((ind < wcum .shape [0 ] - 1 ) and (resampleid [ip ] > wcum [ind ])):
280
279
ind += 1
281
280
inds .append (ind )
282
281
@@ -294,41 +293,42 @@ def resampling(particles):
294
293
295
294
def calc_input (time ):
296
295
297
- if time <= 3.0 :
296
+ if time <= 3.0 : # wait at first
298
297
v = 0.0
299
298
yawrate = 0.0
300
299
else :
301
300
v = 1.0 # [m/s]
302
301
yawrate = 0.1 # [rad/s]
303
302
304
- u = np .matrix ([v , yawrate ]).T
303
+ u = np .array ([v , yawrate ]).reshape ( 2 , 1 )
305
304
306
305
return u
307
306
308
307
309
308
def observation (xTrue , xd , u , RFID ):
310
309
310
+ # calc true state
311
311
xTrue = motion_model (xTrue , u )
312
312
313
- # add noise to gps x-y
314
- z = np .matrix ( np . zeros ((0 , 3 ) ))
313
+ # add noise to range observation
314
+ z = np .zeros ((3 , 0 ))
315
315
316
316
for i in range (len (RFID [:, 0 ])):
317
317
318
318
dx = RFID [i , 0 ] - xTrue [0 , 0 ]
319
319
dy = RFID [i , 1 ] - xTrue [1 , 0 ]
320
320
d = math .sqrt (dx ** 2 + dy ** 2 )
321
- angle = math .atan2 (dy , dx ) - xTrue [2 , 0 ]
321
+ angle = pi_2_pi ( math .atan2 (dy , dx ) - xTrue [2 , 0 ])
322
322
if d <= MAX_RANGE :
323
323
dn = d + np .random .randn () * Qsim [0 , 0 ] # add noise
324
324
anglen = angle + np .random .randn () * Qsim [1 , 1 ] # add noise
325
- zi = np .matrix ([dn , pi_2_pi (anglen ), i ])
326
- z = np .vstack ((z , zi ))
325
+ zi = np .array ([dn , pi_2_pi (anglen ), i ]). reshape ( 3 , 1 )
326
+ z = np .hstack ((z , zi ))
327
327
328
328
# add noise to input
329
329
ud1 = u [0 , 0 ] + np .random .randn () * Rsim [0 , 0 ]
330
330
ud2 = u [1 , 0 ] + np .random .randn () * Rsim [1 , 1 ] + OFFSET_YAWRATE_NOISE
331
- ud = np .matrix ([ud1 , ud2 ]).T
331
+ ud = np .array ([ud1 , ud2 ]).reshape ( 2 , 1 )
332
332
333
333
xd = motion_model (xd , ud )
334
334
@@ -337,15 +337,15 @@ def observation(xTrue, xd, u, RFID):
337
337
338
338
def motion_model (x , u ):
339
339
340
- F = np .matrix ([[1.0 , 0 , 0 ],
341
- [0 , 1.0 , 0 ],
342
- [0 , 0 , 1.0 ]])
340
+ F = np .array ([[1.0 , 0 , 0 ],
341
+ [0 , 1.0 , 0 ],
342
+ [0 , 0 , 1.0 ]])
343
343
344
- B = np .matrix ([[DT * math .cos (x [2 , 0 ]), 0 ],
345
- [DT * math .sin (x [2 , 0 ]), 0 ],
346
- [0.0 , DT ]])
344
+ B = np .array ([[DT * math .cos (x [2 , 0 ]), 0 ],
345
+ [DT * math .sin (x [2 , 0 ]), 0 ],
346
+ [0.0 , DT ]])
347
347
348
- x = F * x + B * u
348
+ x = F @ x + B @ u
349
349
350
350
x [2 , 0 ] = pi_2_pi (x [2 , 0 ])
351
351
@@ -374,10 +374,9 @@ def main():
374
374
N_LM = RFID .shape [0 ]
375
375
376
376
# State Vector [x y yaw v]'
377
- xEst = np .matrix (np .zeros ((STATE_SIZE , 1 )))
378
- xTrue = np .matrix (np .zeros ((STATE_SIZE , 1 )))
379
-
380
- xDR = np .matrix (np .zeros ((STATE_SIZE , 1 ))) # Dead reckoning
377
+ xEst = np .zeros ((STATE_SIZE , 1 )) # SLAM estimation
378
+ xTrue = np .zeros ((STATE_SIZE , 1 )) # True state
379
+ xDR = np .zeros ((STATE_SIZE , 1 )) # Dead reckoning
381
380
382
381
# history
383
382
hxEst = xEst
@@ -408,21 +407,17 @@ def main():
408
407
plt .plot (RFID [:, 0 ], RFID [:, 1 ], "*k" )
409
408
410
409
for iz in range (len (z [:, 0 ])):
411
- lmid = int (z [iz , 2 ])
412
- plt .plot ([xEst [0 , 0 ], RFID [lmid , 0 ]], [
413
- xEst [1 , 0 ], RFID [lmid , 1 ]], "-k" )
410
+ lmid = int (z [2 , iz ])
411
+ plt .plot ([xEst [0 ], RFID [lmid , 0 ]], [
412
+ xEst [1 ], RFID [lmid , 1 ]], "-k" )
414
413
415
414
for i in range (N_PARTICLE ):
416
415
plt .plot (particles [i ].x , particles [i ].y , ".r" )
417
416
plt .plot (particles [i ].lm [:, 0 ], particles [i ].lm [:, 1 ], "xb" )
418
417
419
- plt .plot (np .array (hxTrue [0 , :]).flatten (),
420
- np .array (hxTrue [1 , :]).flatten (), "-b" )
421
- plt .plot (np .array (hxDR [0 , :]).flatten (),
422
- np .array (hxDR [1 , :]).flatten (), "-k" )
423
- plt .plot (np .array (hxEst [0 , :]).flatten (),
424
- np .array (hxEst [1 , :]).flatten (), "-r" )
425
-
418
+ plt .plot (hxTrue [0 , :], hxTrue [1 , :], "-b" )
419
+ plt .plot (hxDR [0 , :], hxDR [1 , :], "-k" )
420
+ plt .plot (hxEst [0 , :], hxEst [1 , :], "-r" )
426
421
plt .plot (xEst [0 ], xEst [1 ], "xk" )
427
422
plt .axis ("equal" )
428
423
plt .grid (True )
0 commit comments