CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download
Project: test
Views: 91872
1
# -*- coding: utf-8 -*-
2
"""
3
Created on Sat May 30 13:24:01 2015
4
5
@author: rlabbe
6
"""
7
8
# -*- coding: utf-8 -*-
9
"""
10
Created on Thu May 28 20:23:57 2015
11
12
@author: rlabbe
13
"""
14
15
16
from math import cos, sin, sqrt, atan2, tan
17
import matplotlib.pyplot as plt
18
import numpy as np
19
from numpy import array, dot
20
from numpy.random import randn
21
from filterpy.common import plot_covariance_ellipse
22
from filterpy.kalman import ExtendedKalmanFilter as EKF
23
from sympy import Matrix, symbols
24
import sympy
25
26
def print_x(x):
27
print(x[0, 0], x[1, 0], np.degrees(x[2, 0]))
28
29
30
def normalize_angle(x, index):
31
if x[index] > np.pi:
32
x[index] -= 2*np.pi
33
if x[index] < -np.pi:
34
x[index] = 2*np.pi
35
36
def residual(a,b):
37
y = a - b
38
normalize_angle(y, 1)
39
return y
40
41
42
sigma_r = 1
43
sigma_h = .1#np.radians(1)
44
sigma_steer = np.radians(1)
45
46
47
class RobotEKF(EKF):
48
def __init__(self, dt, wheelbase):
49
EKF.__init__(self, 3, 2, 2)
50
self.dt = dt
51
self.wheelbase = wheelbase
52
53
a, x, y, v, w, theta, time = symbols(
54
'a, x, y, v, w, theta, t')
55
56
d = v*time
57
beta = (d/w)*sympy.tan(a)
58
r = w/sympy.tan(a)
59
60
61
self.fxu = Matrix([[x-r*sympy.sin(theta)+r*sympy.sin(theta+beta)],
62
[y+r*sympy.cos(theta)-r*sympy.cos(theta+beta)],
63
[theta+beta]])
64
65
self.F_j = self.fxu.jacobian(Matrix([x, y, theta]))
66
self.V_j = self.fxu.jacobian(Matrix([v, a]))
67
68
self.subs = {x: 0, y: 0, v:0, a:0, time:dt, w:wheelbase, theta:0}
69
self.x_x = x
70
self.x_y = y
71
self.v = v
72
self.a = a
73
self.theta = theta
74
75
76
def predict(self, u=0):
77
78
79
self.x = self.move(self.x, u, self.dt)
80
81
self.subs[self.theta] = self.x[2, 0]
82
self.subs[self.v] = u[0]
83
self.subs[self.a] = u[1]
84
85
86
F = array(self.F_j.evalf(subs=self.subs)).astype(float)
87
V = array(self.V_j.evalf(subs=self.subs)).astype(float)
88
89
# covariance of motion noise in control space
90
M = array([[0.1*u[0]**2, 0],
91
[0, sigma_steer**2]])
92
93
self.P = dot(F, self.P).dot(F.T) + dot(V, M).dot(V.T)
94
95
96
def move(self, x, u, dt):
97
h = x[2, 0]
98
v = u[0]
99
steering_angle = u[1]
100
101
dist = v*dt
102
103
if abs(steering_angle) < 0.0001:
104
# approximate straight line with huge radius
105
r = 1.e-30
106
b = dist / self.wheelbase * tan(steering_angle)
107
r = self.wheelbase / tan(steering_angle) # radius
108
109
110
sinh = sin(h)
111
sinhb = sin(h + b)
112
cosh = cos(h)
113
coshb = cos(h + b)
114
115
return x + array([[-r*sinh + r*sinhb],
116
[r*cosh - r*coshb],
117
[b]])
118
119
120
def H_of(x, p):
121
""" compute Jacobian of H matrix where h(x) computes the range and
122
bearing to a landmark 'p' for state x """
123
124
px = p[0]
125
py = p[1]
126
hyp = (px - x[0, 0])**2 + (py - x[1, 0])**2
127
dist = np.sqrt(hyp)
128
129
H = array(
130
[[(-px + x[0, 0]) / dist, (-py + x[1, 0]) / dist, 0.],
131
[ -(-py + x[1, 0]) / hyp, -(px - x[0, 0]) / hyp, -1.]])
132
return H
133
134
135
def Hx(x, p):
136
""" takes a state variable and returns the measurement that would
137
correspond to that state.
138
"""
139
px = p[0]
140
py = p[1]
141
dist = np.sqrt((px - x[0, 0])**2 + (py - x[1, 0])**2)
142
143
Hx = array([[dist],
144
[atan2(py - x[1, 0], px - x[0, 0]) - x[2, 0]]])
145
return Hx
146
147
dt = 1.0
148
ekf = RobotEKF(dt, wheelbase=0.5)
149
150
#np.random.seed(1234)
151
152
m = array([[5, 10],
153
[10, 5],
154
[15, 15]])
155
156
ekf.x = array([[2, 6, .3]]).T
157
ekf.P = np.diag([.1, .1, .1])
158
ekf.R = np.diag([sigma_r**2, sigma_h**2])
159
160
u = array([1.1, .01])
161
162
xp = ekf.x.copy()
163
164
plt.figure()
165
plt.scatter(m[:, 0], m[:, 1])
166
for i in range(250):
167
xp = ekf.move(xp, u, dt/10.) # simulate robot
168
plt.plot(xp[0], xp[1], ',', color='g')
169
170
if i % 10 == 0:
171
172
ekf.predict(u=u)
173
174
plot_covariance_ellipse((ekf.x[0,0], ekf.x[1,0]), ekf.P[0:2, 0:2], std=3,
175
facecolor='b', alpha=0.08)
176
177
for lmark in m:
178
d = sqrt((lmark[0] - xp[0, 0])**2 + (lmark[1] - xp[1, 0])**2) + randn()*sigma_r
179
a = atan2(lmark[1] - xp[1, 0], lmark[0] - xp[0, 0]) - xp[2, 0] + randn()*sigma_h
180
z = np.array([[d], [a]])
181
182
ekf.update(z, HJacobian=H_of, Hx=Hx, residual=residual,
183
args=(lmark), hx_args=(lmark))
184
185
plot_covariance_ellipse((ekf.x[0,0], ekf.x[1,0]), ekf.P[0:2, 0:2], std=3,
186
facecolor='g', alpha=0.4)
187
188
#plt.plot(ekf.x[0], ekf.x[1], 'x', color='r')
189
190
plt.axis('equal')
191
plt.title("EKF Robot localization")
192
plt.show()
193
194
195