ME 405 Romi
Loading...
Searching...
No Matches
observer.py
Go to the documentation of this file.
1from ulab import numpy as np
2import array
3
4
28
29
31
49 def __init__(self, left_pos, right_pos, yaw, yaw_velocity,
50 left_voltage, right_voltage, left_vel, right_vel,
51 total_dist):
52 self.left_pos = left_pos
53 self.right_pos = right_pos
54 self.yaw = yaw
55 self.yaw_velocity = yaw_velocity
56 self.left_voltage = left_voltage
57 self.right_voltage = right_voltage
58 self.left_vel = left_vel
59 self.right_vel = right_vel
60 self.total_dist = total_dist
61
62 # Allocating space for matrices
63 self.x = np.array([[0], [0], [0], [0]])
64 self.u = np.array([[0], [0]])
65 self.y = np.array([[0], [0], [0], [0]])
66 self.u_star = np.array([[0], [0], [0], [0], [0], [0]])
67
68 # Allocating space for the guessed state matrices
69 self.x_estimated = np.array([[0], [0], [0], [0]])
70 self.u_estimated = np.array([[0], [0]])
71 self.y_estimated = np.array([[0], [0], [0], [0]])
72 self.u_star_estimated = np.array([[0], [0], [0], [0], [0], [0]])
73
74 # Continuous model observer gain --> doesn't work fast enough
75 self.L = np.array([
76 [2.2683e+05, 2.2683e+05, 1.2069e-08, -1.9921e+03],
77 [2.2683e+05, 2.2683e+05, 1.2068e-08, 1.9921e+03],
78 [9.5000e+01, 9.5000e+01, -2.0531e-11, 9.8455e-10],
79 [-6.98061e+01, 6.98061e+01, 9.901573e+02, 1.0000]
80 ])
81
82 # Discretized model A matrix
83 self.A_d = np.array([
84 [0.1668, 0.1668, -659.9169, -0.0000],
85 [0.1668, 0.1668, -659.9169, 0.0000],
86 [0.0000, 0.0000, -0.1193, 0.0000],
87 [0.0000, 0.0000, 0.0000, 0.0000]
88 ])
89
90 # Discretized model B matrix
91 self.B_d = np.array([
92 [0.4216, 0.0363, 329.9584, 329.9584, 0.0000, -1.9941],
93 [0.3635, 0.0422, 329.9584, 329.9584, 0.0000, 1.9941],
94 [0.0001, 0.0000, 0.5597, 0.5597, 0.0000, 0.0000],
95 [0.0000, 0.0000, -0.0698, 0.0698, 0.9902, 0.0010]
96 ])
97
98 # Continuous/Discretized (Doesn't Change) model C matrix
99 self.C = np.array([
100 [0, 0, 1, -0.141 / 2],
101 [0, 0, 1, 0.141 / 2],
102 [0, 0, 0, 1],
103 [-0.035 / 0.141, 0.035 / 0.141, 0, 0]
104 ])
105
106 self.state = 0
107 self.feedback = 1 # 0 = continuous with no feedback, 1 = discrete with feedback
108
109
111 def update_x(self):
112 self.x[0, 0] = self.left_vel.get() / 0.035
113 self.x[1, 0] = self.right_vel.get() / 0.035
114 self.x[2, 0] = self.x_estimated[2, 0]
115 self.x[3, 0] = self.yaw.get()
116
117
119 def update_u(self):
120 self.u[0, 0] = self.left_voltage.get() * 12
121 self.u[1, 0] = self.right_voltage.get() * 12
122
123
124 def update_y(self):
125 self.y[0, 0] = self.left_pos.get()
126 self.y[1, 0] = self.right_pos.get()
127 self.y[2, 0] = self.yaw.get()
128 self.y[3, 0] = self.yaw_velocity.get()
129
130
131 def update_u_star(self):
132 self.u_star[0, 0] = self.left_voltage.get() * 12
133 self.u_star[1, 0] = self.right_voltage.get() * 12
134 self.u_star[2, 0] = self.left_pos.get()
135 self.u_star[3, 0] = self.right_pos.get()
136 self.u_star[4, 0] = self.yaw.get()
137 self.u_star[5, 0] = self.yaw_velocity.get()
138
139
148 def calc_derivative(self, x, u):
149 # x expected as a [4,1]
150 # u expected as a [2,1]
151
152 t_l = 0.1
153 t_r = 0.1
154 r = 0.35
155 w = 0.141
156 K_l = 5.81
157 K_r = 5.81
158
159 A = np.array([
160 [-1 / t_l, 0, 0, 0],
161 [0, -1 / t_r, 0, 0],
162 [r / 2, r / 2, 0, 0],
163 [-r / w, r / w, 0, 0]
164 ])
165
166 B = np.array([
167 [K_l / t_l, 0],
168 [0, K_r / t_r],
169 [0, 0],
170 [0, 0]
171 ])
172
173 dx = np.dot(A, x) + np.dot(B, u)
174
175 return dx
176
177
186 def calc_output(self, x, u):
187 # x expected as a [4,1]
188 # u expected as a [2,1]
189 r = 0.35
190 w = 0.141
191
192 C = np.array([
193 [0, 0, 1, -w / 2],
194 [0, 0, 1, w / 2],
195 [0, 0, 0, 1],
196 [-r / w, r / w, 0, 0]
197 ])
198
199 D = np.array([
200 [0, 0],
201 [0, 0],
202 [0, 0],
203 [0, 0]
204 ])
205
206 y = np.dot(C, x) + np.dot(D, u)
207
208 return y
209
210
218 def calc_discrete_state(self, x, u_star):
219 x_next = np.dot(self.A_d, x) + np.dot(self.B_d, u_star)
220 return x_next
221
222
230 y_next = np.dot(self.C, x)
231 return y_next
232
233
244 def RK4_solver(self, x, t_step, u):
245
246 k1 = self.calc_derivative(x, u)
247 y1 = self.calc_output(x, u)
248
249 k2 = self.calc_derivative(x + 0.5 * k1 * t_step, u)
250 y2 = self.calc_output(x + 0.5 * k1 * t_step, u)
251
252 k3 = self.calc_derivative(x + 0.5 * k2 * t_step, u)
253 y3 = self.calc_output(x + 0.5 * k2 * t_step, u)
254
255 k4 = self.calc_derivative(x + k3 * t_step, u)
256 y4 = self.calc_output(x + k3 * t_step, u)
257
258 x_next = x + (1.0 / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4) * t_step
259 y = (1.0 / 6.0) * (y1 + 2 * y2 + 2 * y3 + y4)
260
261 return x_next, y
262
263
285 def run(self):
286 while True:
287 # Run the observer
288 if self.state == 0:
289 self.update_x()
290 self.update_y()
291 self.update_u()
292 self.update_u_star()
293
294 if self.feedback == 0:
295 # Continuous
296 self.x_estimated, self.y_estimated = self.RK4_solver(
297 self.x, 0.02, self.u
298 )
299 print(self.x_estimated[2, 0])
300 # print(self.yaw.get())
301 else:
302 # Discretized
304 self.x, self.u_star
305 )
306 self.y_estimated = self.calc_discrete_output(self.x)
307 self.total_dist.put(self.x_estimated[2, 0] * -2.1)
308 # Debug prints (left for development)
309 # print(f"\rLeft Velocity: {self.x_estimated[0,0]}")
310 # print(f"Right Velocity: {self.x_estimated[1,0]}")
311 # print(f"Total Distance: {self.x_estimated[2,0]*(-2.1)}")
312 # print(f"Yaw: {self.x[3,0]}")
313 # print("\033[4A")
314 else:
315 raise ValueError("Not that many states")
316
317 yield self.state
Observer task object compatible with the cotask scheduler.
Definition observer.py:30
update_u_star(self)
Updates the discretized combined input and output vector.
Definition observer.py:131
update_y(self)
Updates the output vector with real values.
Definition observer.py:124
RK4_solver(self, x, t_step, u)
RK4_solver is an implementation of the RK4 algorithm used to estimate the state when using a continuo...
Definition observer.py:244
__init__(self, left_pos, right_pos, yaw, yaw_velocity, left_voltage, right_voltage, left_vel, right_vel, total_dist)
Observer object initializer.
Definition observer.py:51
update_x(self)
Updates the state vector with real values and the last guessed total distance.
Definition observer.py:111
update_u(self)
Updates the input vector with real values assuming full battery voltage.
Definition observer.py:119
calc_discrete_output(self, x)
Calculates the current output vector using the discretized model.
Definition observer.py:229
calc_discrete_state(self, x, u_star)
Calculates the next state vector using the discretized model.
Definition observer.py:218
calc_derivative(self, x, u)
Calculates the derivative state vector using the continuous model with no feedback.
Definition observer.py:148
calc_output(self, x, u)
Calculates the output vector using the continuous model with no feedback.
Definition observer.py:186
run(self)
Generator that the cotask scheduler will run since our tasks are objects.
Definition observer.py:285