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 Mon May 25 18:18:54 2015
4
5
@author: rlabbe
6
"""
7
8
9
from math import cos, sin, sqrt, atan2
10
import matplotlib.pyplot as plt
11
import numpy as np
12
from numpy import array, dot
13
from numpy.linalg import pinv
14
from numpy.random import randn
15
from filterpy.common import plot_covariance_ellipse
16
from filterpy.kalman import ExtendedKalmanFilter as EKF
17
18
19
def print_x(x):
20
print(x[0, 0], x[1, 0], np.degrees(x[2, 0]))
21
22
23
def normalize_angle(x, index):
24
if x[index] > np.pi:
25
x[index] -= 2*np.pi
26
if x[index] < -np.pi:
27
x[index] = 2*np.pi
28
29
def residual(a,b):
30
y = a - b
31
normalize_angle(y, 1)
32
return y
33
34
35
def control_update(x, u, dt):
36
""" x is [x, y, hdg], u is [vel, omega] """
37
38
v = u[0]
39
w = u[1]
40
if w == 0:
41
# approximate straight line with huge radius
42
w = 1.e-30
43
r = v/w # radius
44
45
46
return x + np.array([[-r*sin(x[2]) + r*sin(x[2] + w*dt)],
47
[ r*cos(x[2]) - r*cos(x[2] + w*dt)],
48
[w*dt]])
49
50
a1 = 0.001
51
a2 = 0.001
52
a3 = 0.001
53
a4 = 0.001
54
55
sigma_r = 0.1
56
sigma_h = a_error = np.radians(1)
57
sigma_s = 0.00001
58
59
def normalize_angle(x, index):
60
if x[index] > np.pi:
61
x[index] -= 2*np.pi
62
if x[index] < -np.pi:
63
x[index] = 2*np.pi
64
65
66
67
class RobotEKF(EKF):
68
def __init__(self, dt):
69
EKF.__init__(self, 3, 2, 2)
70
self.dt = dt
71
72
def predict_x(self, u):
73
self.x = self.move(self.x, u, self.dt)
74
75
76
def move(self, x, u, dt):
77
h = x[2, 0]
78
v = u[0]
79
w = u[1]
80
81
if w == 0:
82
# approximate straight line with huge radius
83
w = 1.e-30
84
r = v/w # radius
85
86
sinh = sin(h)
87
sinhwdt = sin(h + w*dt)
88
cosh = cos(h)
89
coshwdt = cos(h + w*dt)
90
91
return x + array([[-r*sinh + r*sinhwdt],
92
[r*cosh - r*coshwdt],
93
[w*dt]])
94
95
96
def H_of(x, landmark_pos):
97
""" compute Jacobian of H matrix for state x """
98
99
mx = landmark_pos[0]
100
my = landmark_pos[1]
101
q = (mx - x[0, 0])**2 + (my - x[1, 0])**2
102
103
H = array(
104
[[-(mx - x[0, 0]) / sqrt(q), -(my - x[1, 0]) / sqrt(q), 0],
105
[ (my - x[1, 0]) / q, -(mx - x[0, 0]) / q, -1]])
106
return H
107
108
109
def Hx(x, landmark_pos):
110
""" takes a state variable and returns the measurement that would
111
correspond to that state.
112
"""
113
mx = landmark_pos[0]
114
my = landmark_pos[1]
115
q = (mx - x[0, 0])**2 + (my - x[1, 0])**2
116
117
Hx = array([[sqrt(q)],
118
[atan2(my - x[1, 0], mx - x[0, 0]) - x[2, 0]]])
119
return Hx
120
121
dt = 1.0
122
ekf = RobotEKF(dt)
123
124
#np.random.seed(1234)
125
126
m = array([[5, 10],
127
[10, 5],
128
[15, 15]])
129
130
ekf.x = array([[2, 6, .3]]).T
131
u = array([.5, .01])
132
ekf.P = np.diag([1., 1., 1.])
133
ekf.R = np.diag([sigma_r**2, sigma_h**2])
134
c = [0, 1, 2]
135
136
xp = ekf.x.copy()
137
138
plt.scatter(m[:, 0], m[:, 1])
139
for i in range(300):
140
xp = ekf.move(xp, u, dt/10.) # simulate robot
141
plt.plot(xp[0], xp[1], ',', color='g')
142
143
if i % 10 == 0:
144
h = ekf.x[2, 0]
145
v = u[0]
146
w = u[1]
147
148
if w == 0:
149
# approximate straight line with huge radius
150
w = 1.e-30
151
r = v/w # radius
152
153
sinh = sin(h)
154
sinhwdt = sin(h + w*dt)
155
cosh = cos(h)
156
coshwdt = cos(h + w*dt)
157
158
ekf.F = array(
159
[[1, 0, -r*cosh + r*coshwdt],
160
[0, 1, -r*sinh + r*sinhwdt],
161
[0, 0, 1]])
162
163
V = array(
164
[[(-sinh + sinhwdt)/w, v*(sin(h)-sinhwdt)/(w**2) + v*coshwdt*dt/w],
165
[(cosh - coshwdt)/w, -v*(cosh-coshwdt)/(w**2) + v*sinhwdt*dt/w],
166
[0, dt]])
167
168
# covariance of motion noise in control space
169
M = array([[a1*v**2 + a2*w**2, 0],
170
[0, a3*v**2 + a4*w**2]])
171
172
ekf.Q = dot(V, M).dot(V.T)
173
174
ekf.predict(u=u)
175
176
for lmark in m:
177
d = sqrt((lmark[0] - xp[0, 0])**2 + (lmark[1] - xp[1, 0])**2) + randn()*sigma_r
178
a = atan2(lmark[1] - xp[1, 0], lmark[0] - xp[0, 0]) - xp[2, 0] + randn()*sigma_h
179
z = np.array([[d], [a]])
180
181
ekf.update(z, HJacobian=H_of, Hx=Hx, residual=residual,
182
args=(lmark), hx_args=(lmark))
183
184
plot_covariance_ellipse((ekf.x[0,0], ekf.x[1,0]), ekf.P[0:2, 0:2], std=10,
185
facecolor='g', alpha=0.3)
186
187
#plt.plot(ekf.x[0], ekf.x[1], 'x', color='r')
188
189
plt.axis('equal')
190
plt.show()
191
192
193