Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
96129 views
1
# -*- coding: utf-8 -*-
2
"""
3
Created on Mon Jun 1 18:13:23 2015
4
5
@author: rlabbe
6
"""
7
8
from filterpy.common import plot_covariance_ellipse
9
from filterpy.kalman import UnscentedKalmanFilter as UKF
10
from filterpy.kalman import MerweScaledSigmaPoints
11
from math import tan, sin, cos, sqrt, atan2, radians
12
import matplotlib.pyplot as plt
13
from numpy import array
14
import numpy as np
15
from numpy.random import randn, seed
16
17
18
19
def normalize_angle(x):
20
x = x % (2 * np.pi) # force in range [0, 2 pi)
21
if x > np.pi: # move to [-pi, pi]
22
x -= 2 * np.pi
23
return x
24
25
26
def residual_h(aa, bb):
27
y = aa - bb
28
for i in range(0, len(y), 2):
29
y[i + 1] = normalize_angle(y[i + 1])
30
return y
31
32
33
def residual_x(a, b):
34
y = a - b
35
y[2] = normalize_angle(y[2])
36
return y
37
38
39
def move(x, u, dt, wheelbase):
40
h = x[2]
41
v = u[0]
42
steering_angle = u[1]
43
44
dist = v*dt
45
46
if abs(steering_angle) > 0.001:
47
b = dist / wheelbase * tan(steering_angle)
48
r = wheelbase / tan(steering_angle) # radius
49
50
sinh = sin(h)
51
sinhb = sin(h + b)
52
cosh = cos(h)
53
coshb = cos(h + b)
54
55
return x + array([-r*sinh + r*sinhb, r*cosh - r*coshb, b])
56
else:
57
return x + array([dist*cos(h), dist*sin(h), 0])
58
59
60
def state_mean(sigmas, Wm):
61
x = np.zeros(3)
62
63
sum_sin = np.sum(np.dot(np.sin(sigmas[:, 2]), Wm))
64
sum_cos = np.sum(np.dot(np.cos(sigmas[:, 2]), Wm))
65
66
x[0] = np.sum(np.dot(sigmas[:, 0], Wm))
67
x[1] = np.sum(np.dot(sigmas[:, 1], Wm))
68
x[2] = atan2(sum_sin, sum_cos)
69
70
return x
71
72
73
def z_mean(sigmas, Wm):
74
z_count = sigmas.shape[1]
75
x = np.zeros(z_count)
76
77
for z in range(0, z_count, 2):
78
sum_sin = np.sum(np.dot(np.sin(sigmas[:, z+1]), Wm))
79
sum_cos = np.sum(np.dot(np.cos(sigmas[:, z+1]), Wm))
80
81
x[z] = np.sum(np.dot(sigmas[:,z], Wm))
82
x[z+1] = atan2(sum_sin, sum_cos)
83
return x
84
85
86
def fx(x, dt, u):
87
return move(x, u, dt, wheelbase)
88
89
90
def Hx(x, landmark):
91
""" takes a state variable and returns the measurement that would
92
correspond to that state.
93
"""
94
95
hx = []
96
for lmark in landmark:
97
px, py = lmark
98
dist = sqrt((px - x[0])**2 + (py - x[1])**2)
99
angle = atan2(py - x[1], px - x[0])
100
hx.extend([dist, normalize_angle(angle - x[2])])
101
return np.array(hx)
102
103
104
m = array([[5., 10], [10, 5], [15, 15], [20., 16], [0, 30], [50, 30], [40, 10]])
105
#m = array([[5, 10], [10, 5], [15, 15], [20, 5],[5,5], [8, 8.4]])#, [0, 30], [50, 30], [40, 10]])
106
#m = array([[5, 10], [10, 5]])#, [0, 30], [50, 30], [40, 10]])
107
#m = array([[5., 10], [10, 5]])
108
#m = array([[5., 10], [10, 5]])
109
110
111
sigma_r = .3
112
sigma_h = .1#radians(.5)#np.radians(1)
113
#sigma_steer = radians(10)
114
dt = 0.1
115
wheelbase = 0.5
116
117
points = MerweScaledSigmaPoints(n=3, alpha=.1, beta=2, kappa=0, subtract=residual_x)
118
#points = JulierSigmaPoints(n=3, kappa=3)
119
ukf= UKF(dim_x=3, dim_z=2*len(m), fx=fx, hx=Hx, dt=dt, points=points,
120
x_mean_fn=state_mean, z_mean_fn=z_mean,
121
residual_x=residual_x, residual_z=residual_h)
122
ukf.x = array([2, 6, .3])
123
ukf.P = np.diag([.1, .1, .05])
124
ukf.R = np.diag([sigma_r**2, sigma_h**2]* len(m))
125
ukf.Q =np.eye(3)*.00001
126
127
128
u = array([1.1, 0.])
129
130
xp = ukf.x.copy()
131
132
133
plt.cla()
134
plt.scatter(m[:, 0], m[:, 1])
135
136
cmds = [[v, .0] for v in np.linspace(0.001, 1.1, 30)]
137
cmds.extend([cmds[-1]]*50)
138
139
v = cmds[-1][0]
140
cmds.extend([[v, a] for a in np.linspace(0, np.radians(2), 15)])
141
cmds.extend([cmds[-1]]*100)
142
143
cmds.extend([[v, a] for a in np.linspace(np.radians(2), -np.radians(2), 15)])
144
cmds.extend([cmds[-1]]*200)
145
146
cmds.extend([[v, a] for a in np.linspace(-np.radians(2), 0, 15)])
147
cmds.extend([cmds[-1]]*150)
148
149
150
seed(12)
151
cmds = np.array(cmds)
152
153
cindex = 0
154
u = cmds[0]
155
156
track = []
157
158
std = 16
159
while cindex < len(cmds):
160
u = cmds[cindex]
161
xp = move(xp, u, dt, wheelbase) # simulate robot
162
track.append(xp)
163
164
ukf.predict(fx_args=u)
165
166
if cindex % 20 == 0:
167
plot_covariance_ellipse((ukf.x[0], ukf.x[1]), ukf.P[0:2, 0:2], std=std,
168
facecolor='b', alpha=0.58)
169
170
#print(cindex, ukf.P.diagonal())
171
#print(ukf.P.diagonal())
172
z = []
173
for lmark in m:
174
d = sqrt((lmark[0] - xp[0])**2 + (lmark[1] - xp[1])**2) + randn()*sigma_r
175
bearing = atan2(lmark[1] - xp[1], lmark[0] - xp[0])
176
a = normalize_angle(bearing - xp[2] + randn()*sigma_h)
177
z.extend([d, a])
178
179
#if cindex % 20 == 0:
180
# plt.plot([lmark[0], lmark[0] - d*cos(a+xp[2])], [lmark[1], lmark[1]-d*sin(a+xp[2])], color='r')
181
182
if cindex == 1197:
183
plt.plot([lmark[0], lmark[0] - d2*cos(a2+xp[2])],
184
[lmark[1], lmark[1] - d2*sin(a2+xp[2])], color='r')
185
plt.plot([lmark[0], lmark[0] - d*cos(a+xp[2])],
186
[lmark[1], lmark[1] - d*sin(a+xp[2])], color='k')
187
188
ukf.update(np.array(z), hx_args=(m,))
189
190
if cindex % 20 == 0:
191
plot_covariance_ellipse((ukf.x[0], ukf.x[1]), ukf.P[0:2, 0:2], std=std,
192
facecolor='g', alpha=0.5)
193
cindex += 1
194
195
196
track = np.array(track)
197
plt.plot(track[:, 0], track[:,1], color='k')
198
199
plt.axis('equal')
200
plt.title("UKF Robot localization")
201
plt.show()
202
203