Skip to content

Commit bc03423

Browse files
committed
first release EKF SLAM
1 parent 577099c commit bc03423

File tree

1 file changed

+63
-63
lines changed

1 file changed

+63
-63
lines changed

SLAM/EKFSLAM/ekf_slam.py

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
3-
Extended Kalman Filter based SLAM example
3+
Extended Kalman Filter SLAM example
44
55
author: Atsushi Sakai (@Atsushi_twi)
66
@@ -14,21 +14,54 @@
1414
Cx = np.diag([0.5, 0.5, math.radians(30.0)])**2
1515

1616
# Simulation parameter
17-
Qsim = np.diag([0.2])**2
17+
Qsim = np.diag([0.2, math.radians(1.0)])**2
1818
Rsim = np.diag([1.0, math.radians(10.0)])**2
1919

2020
DT = 0.1 # time tick [s]
2121
SIM_TIME = 50.0 # simulation time [s]
2222
MAX_RANGE = 20.0 # maximum observation range
23-
24-
M_DIST_TH = 1.0 # Threshold of Mahalanobis distance for data association.
25-
23+
M_DIST_TH = 2.0 # Threshold of Mahalanobis distance for data association.
2624
STATE_SIZE = 3 # State size [x,y,yaw]
2725
LM_SIZE = 2 # LM srate size [x,y]
2826

2927
show_animation = True
3028

3129

30+
def ekf_slam(xEst, PEst, u, z):
31+
32+
# Predict
33+
S = STATE_SIZE
34+
xEst[0:S] = motion_model(xEst[0:S], u)
35+
G, Fx = jacob_motion(xEst[0:S], u)
36+
PEst[0:S, 0:S] = G.T * PEst[0:S, 0:S] * G + Fx.T * Cx * Fx
37+
initP = np.eye(2)
38+
39+
# Update
40+
for iz in range(len(z[:, 0])): # for each observation
41+
minid = search_correspond_LM_ID(xEst, PEst, z[iz, 0:2])
42+
43+
nLM = calc_n_LM(xEst)
44+
if minid == nLM:
45+
print("New LM")
46+
# Extend state and covariance matrix
47+
xAug = np.vstack((xEst, calc_LM_Pos(xEst, z[iz, :])))
48+
PAug = np.vstack((np.hstack((PEst, np.zeros((len(xEst), LM_SIZE)))),
49+
np.hstack((np.zeros((LM_SIZE, len(xEst))), initP))))
50+
xEst = xAug
51+
PEst = PAug
52+
53+
lm = get_LM_Pos_from_state(xEst, minid)
54+
y, S, H = calc_innovation(lm, xEst, PEst, z[iz, 0:2], minid)
55+
56+
K = PEst * H.T * np.linalg.inv(S)
57+
xEst = xEst + K * y
58+
PEst = (np.eye(len(xEst)) - K * H) * PEst
59+
60+
xEst[2] = pi_2_pi(xEst[2])
61+
62+
return xEst, PEst
63+
64+
3265
def calc_input():
3366
v = 1.0 # [m/s]
3467
yawrate = 0.1 # [rad/s]
@@ -50,8 +83,9 @@ def observation(xTrue, xd, u, RFID):
5083
d = math.sqrt(dx**2 + dy**2)
5184
angle = pi_2_pi(math.atan2(dy, dx))
5285
if d <= MAX_RANGE:
53-
# dn = d + np.random.randn() * Qsim[0, 0] # add noise
54-
zi = np.matrix([d, angle, i])
86+
dn = d + np.random.randn() * Qsim[0, 0] # add noise
87+
anglen = angle + np.random.randn() * Qsim[1, 1] # add noise
88+
zi = np.matrix([dn, anglen, i])
5589
z = np.vstack((z, zi))
5690

5791
# add noise to input
@@ -108,23 +142,32 @@ def calc_LM_Pos(x, z):
108142
return zp
109143

110144

111-
def calc_mahalanobis_dist(xAug, PAug, z, iz):
145+
def get_LM_Pos_from_state(x, ind):
146+
147+
lm = x[STATE_SIZE + LM_SIZE * ind: STATE_SIZE + LM_SIZE * (ind + 1), :]
148+
149+
return lm
150+
151+
152+
def search_correspond_LM_ID(xAug, PAug, zi):
153+
"""
154+
Landmark association with Mahalanobis distance
155+
"""
112156

113157
nLM = calc_n_LM(xAug)
114158

115159
mdist = []
116160

117161
for i in range(nLM):
162+
lm = get_LM_Pos_from_state(xAug, i)
163+
y, S, H = calc_innovation(lm, xAug, PAug, zi, i)
164+
mdist.append(y.T * np.linalg.inv(S) * y)
165+
166+
mdist.append(M_DIST_TH) # new landmark
118167

119-
if i == nLM - 1:
120-
mdist.append(M_DIST_TH)
121-
else:
122-
lm = xAug[STATE_SIZE + LM_SIZE *
123-
i: STATE_SIZE + LM_SIZE * (i + 1), :]
124-
y, S, H = calc_innovation(lm, xAug, PAug, z[iz, 0:2], i)
125-
mdist.append(y.T * np.linalg.inv(S) * y)
168+
minid = mdist.index(min(mdist))
126169

127-
return mdist
170+
return minid
128171

129172

130173
def calc_innovation(lm, xEst, PEst, z, LMid):
@@ -133,6 +176,7 @@ def calc_innovation(lm, xEst, PEst, z, LMid):
133176
zangle = math.atan2(delta[1], delta[0]) - xEst[2]
134177
zp = [math.sqrt(q), pi_2_pi(zangle)]
135178
y = (z - zp).T
179+
y[1] = pi_2_pi(y[1])
136180
H = jacobH(q, delta, xEst, LMid + 1)
137181
S = H * PEst * H.T + Cx[0:2, 0:2]
138182

@@ -167,56 +211,15 @@ def pi_2_pi(angle):
167211
return angle
168212

169213

170-
def ekf_slam(xEst, PEst, u, z):
171-
# Predict
172-
xEst[0:STATE_SIZE] = motion_model(xEst[0:STATE_SIZE], u)
173-
G, Fx = jacob_motion(xEst[0:STATE_SIZE], u)
174-
PEst[0:STATE_SIZE, 0:STATE_SIZE] = G.T * \
175-
PEst[0:STATE_SIZE, 0:STATE_SIZE] * G + Fx.T * Cx * Fx
176-
initP = np.eye(2)
177-
178-
# Update
179-
for iz in range(len(z[:, 0])): # for each observation
180-
zp = calc_LM_Pos(xEst, z[iz, :])
181-
182-
# Extend state and covariance matrix
183-
xAug = np.vstack((xEst, zp))
184-
PAug = np.vstack((np.hstack((PEst, np.zeros((len(xEst), LM_SIZE)))),
185-
np.hstack((np.zeros((LM_SIZE, len(xEst))), initP))))
186-
187-
mah_dists = calc_mahalanobis_dist(xAug, PAug, z, iz)
188-
minid = mah_dists.index(min(mah_dists))
189-
190-
nLM = calc_n_LM(xAug)
191-
if minid == (nLM - 1):
192-
print("New LM")
193-
xEst = xAug
194-
PEst = PAug
195-
else:
196-
print("Old LM")
197-
198-
lm = xEst[STATE_SIZE + LM_SIZE *
199-
minid: STATE_SIZE + LM_SIZE * (minid + 1), :]
200-
y, S, H = calc_innovation(lm, xEst, PEst, z[iz, 0:2], minid)
201-
202-
K = PEst * H.T * np.linalg.inv(S)
203-
xEst = xEst + K * y
204-
PEst = (np.eye(len(xEst)) - K * H) * PEst
205-
206-
xEst[2] = pi_2_pi(xEst[2])
207-
208-
return xEst, PEst
209-
210-
211214
def main():
212215
print(__file__ + " start!!")
213216

214217
time = 0.0
215218

216219
# RFID positions [x, y]
217-
RFID = np.array([[10.0, 0.0],
218-
[10.0, 10.0],
219-
[0.0, 15.0],
220+
RFID = np.array([[10.0, -2.0],
221+
[15.0, 10.0],
222+
[3.0, 15.0],
220223
[-5.0, 20.0]])
221224

222225
# State Vector [x y yaw v]'
@@ -246,8 +249,6 @@ def main():
246249
hxDR = np.hstack((hxDR, xDR))
247250
hxTrue = np.hstack((hxTrue, xTrue))
248251

249-
# print(xEst)
250-
251252
if show_animation:
252253
plt.cla()
253254

@@ -268,7 +269,6 @@ def main():
268269
plt.axis("equal")
269270
plt.grid(True)
270271
plt.pause(0.001)
271-
# input()
272272

273273

274274
if __name__ == '__main__':

0 commit comments

Comments
 (0)