-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathstate_estimation.py
More file actions
177 lines (143 loc) · 5.45 KB
/
Copy pathstate_estimation.py
File metadata and controls
177 lines (143 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import os
import numpy as np
import matplotlib.pyplot as plt
from scipy import io
from ukf_functions import *
from panorama import *
from transforms3d import taitbryan
def main():
''' modify this part accordingly '''
# flags
UKF = True # use UKF or just gyro data for estimate
Panorama = True # generate panorama or not
Estimate = True # the panorama is based on estimate or ground truth, must be set as True if no vicon data provided
# dataset idx
idx = 11
# mat file location+prefix
imu_prefix = "imu/imuRaw"
vicon_prefix = "vicon/viconRot"
cam_prefix = "cam/cam"
# load data
imu_ts, imu_vals, vicon_ts, vicon_euler = load_data(idx, imu_prefix, vicon_prefix)
# Unscented Kalman Filter
# init
qk = np.array([1,0,0,0]) # last mean in quaternion
Pk = np.identity(3) * 0.1 # last cov in vector
Q = np.identity(3) * 2 # process noise cov
R = np.identity(3) * 2 # measurement noise cov
time = imu_ts.shape[0]
ukf_euler = np.zeros((time, 3)) # represent orientation in euler angles
for t in range(time):
# extract sensor data
acc = imu_vals[t,:3]
gyro = imu_vals[t,3:]
# Prediction
X = compute_sigma_pts(qk, Pk, Q)
if t == time-1: # last iter
dt = np.mean(imu_ts[-10:] - imu_ts[-11:-1])
else:
dt = imu_ts[t+1] - imu_ts[t]
Y = process_model(X, gyro, dt)
q_pred, P_pred, W = prediction(Y, qk)
if UKF:
# Measurement
vk, Pvv, Pxz = measurement_model(Y, acc, W, R)
# Update
K = np.dot(Pxz,np.linalg.inv(Pvv)) # Kalman gain
qk, Pk = update(q_pred, P_pred, vk, Pvv, K)
else:
# estimate just based on control input gyro
qk, Pk = q_pred, P_pred
# save for visualization
ukf_euler[t, :] = taitbryan.quat2euler(qk)
np.save('result/'+'ukf'+str(idx),ukf_euler)
# orientation plot UKF + only gyro
orientation_plot(idx, imu_ts, ukf_euler, vicon_ts, vicon_euler)
# panoramic by image stitching
if Panorama:
if Estimate:
panorama(idx, cam_prefix, imu_ts, ukf_euler)
else:
panorama(idx, cam_prefix, vicon_ts, vicon_euler)
return 0
def load_data(idx, imu_prefix, vicon_prefix):
# load data from imu/vicon, calibrate and save
# load imu
imu = io.loadmat(imu_prefix+str(idx)+".mat")
imu_vals = np.array(imu['vals'])
imu_ts = np.array(imu['ts']).T
# scale and bias based on IMU reference
acc_x = -imu_vals[0,:]
acc_y = -imu_vals[1,:]
acc_z = imu_vals[2,:]
acc = np.array([acc_x, acc_y, acc_z]).T
Vref = 3300
acc_sensitivity = 330
acc_scale_factor = Vref/1023/acc_sensitivity
acc_bias = np.mean(acc[:10], axis = 0) - (np.array([0,0,1])/acc_scale_factor)
acc = (acc-acc_bias)*acc_scale_factor
gyro_x = imu_vals[4,:]
gyro_y = imu_vals[5,:]
gyro_z = imu_vals[3,:]
gyro = np.array([gyro_x, gyro_y, gyro_z]).T
gyro_sensitivity = 3.33
gyro_scale_factor = Vref/1023/gyro_sensitivity
gyro_bias = np.mean(gyro[:10], axis = 0)
gyro = (gyro-gyro_bias)*gyro_scale_factor*(np.pi/180)
imu_vals = np.hstack((acc,gyro))
# vicon not provided
if not os.path.exists(vicon_prefix+str(idx)+".mat"):
return imu_ts, imu_vals, None, None
# load vicon
vicon = io.loadmat(vicon_prefix+str(idx)+".mat")
vicon_vals = np.array(vicon['rots'])
vicon_ts = np.array(vicon['ts']).T
n = np.shape(vicon_vals)[2]
vicon_euler = np.zeros((n,3))
for i in range(n):
R = vicon_vals[:,:,i]
vicon_euler[i] = taitbryan.mat2euler(R)
return imu_ts, imu_vals, vicon_ts, vicon_euler
def orientation_plot(idx, imu_ts, ukf_euler, vicon_ts, vicon_euler):
# no vicon data
if vicon_ts is None and vicon_euler is None:
plt.figure(1)
plt.subplot(3, 1, 1)
ukf, = plt.plot(imu_ts, ukf_euler[:, 0], 'r', label='UKF Estimate')
plt.title('Z-Yaw')
plt.ylabel('Angle [rad]')
plt.legend(handles=[ukf])
plt.subplot(3, 1, 2)
ukf, = plt.plot(imu_ts, ukf_euler[:, 1], 'r', label='UKF Estimate')
plt.title('Y-Pitch')
plt.ylabel('Angle [rad]')
plt.legend(handles=[ukf])
plt.subplot(3, 1, 3)
ukf, = plt.plot(imu_ts, ukf_euler[:, 2], 'r', label='UKF Estimate')
plt.title('X-Roll')
plt.ylabel('Angle [rad]')
plt.legend(handles=[ukf])
plt.savefig('result/orientation' + str(idx) + '.png')
else:
plt.figure(1)
plt.subplot(3, 1, 1)
true, = plt.plot(vicon_ts, vicon_euler[:, 0], 'g', label='Ground Truth')
ukf, = plt.plot(imu_ts, ukf_euler[:, 0], 'r', label='UKF Estimate')
plt.title('Z-Yaw')
plt.ylabel('Angle [rad]')
plt.legend(handles=[true, ukf])
plt.subplot(3, 1, 2)
true, = plt.plot(vicon_ts, vicon_euler[:, 1], 'g', label='Ground Truth')
ukf, = plt.plot(imu_ts, ukf_euler[:, 1], 'r', label='UKF Estimate')
plt.title('Y-Pitch')
plt.ylabel('Angle [rad]')
plt.legend(handles=[true, ukf])
plt.subplot(3, 1, 3)
true, = plt.plot(vicon_ts, vicon_euler[:, 2], 'g', label='Ground Truth')
ukf, = plt.plot(imu_ts, ukf_euler[:, 2], 'r', label='UKF Estimate')
plt.title('X-Roll')
plt.ylabel('Angle [rad]')
plt.legend(handles=[true, ukf])
plt.savefig('result/orientation'+str(idx)+'.png')
if __name__ == '__main__':
main()