blob: 92b7c7a6ad8ea70a44e5b2d4059ab6ff48d717ff [file] [log] [blame]
Austin Schuh085eab92020-11-26 13:54:51 -08001#!/usr/bin/python3
Michael Schuh10dd1e02018-01-20 13:19:44 -08002
Austin Schuhf173eb82018-01-20 23:32:30 -08003from frc971.control_loops.python import control_loop
4from frc971.control_loops.python import controls
Michael Schuh10dd1e02018-01-20 13:19:44 -08005import numpy
Austin Schuhf173eb82018-01-20 23:32:30 -08006import sys
Austin Schuhf173eb82018-01-20 23:32:30 -08007from matplotlib import pylab
8import gflags
9import glog
Michael Schuh10dd1e02018-01-20 13:19:44 -080010
Austin Schuhf173eb82018-01-20 23:32:30 -080011FLAGS = gflags.FLAGS
Michael Schuh10dd1e02018-01-20 13:19:44 -080012
Austin Schuhf173eb82018-01-20 23:32:30 -080013try:
Austin Schuh17dd0892018-03-02 20:06:31 -080014 gflags.DEFINE_bool('plot', False, 'If true, plot the loop response.')
Austin Schuhf173eb82018-01-20 23:32:30 -080015except gflags.DuplicateFlagError:
Austin Schuh17dd0892018-03-02 20:06:31 -080016 pass
17
Michael Schuh10dd1e02018-01-20 13:19:44 -080018
Austin Schuhf173eb82018-01-20 23:32:30 -080019class Intake(control_loop.ControlLoop):
Tyler Chatow6738c362019-02-16 14:12:30 -080020
Austin Schuh17dd0892018-03-02 20:06:31 -080021 def __init__(self, name="Intake"):
22 super(Intake, self).__init__(name)
23 self.motor = control_loop.BAG()
24 # Stall Torque in N m
25 self.stall_torque = self.motor.stall_torque
26 # Stall Current in Amps
27 self.stall_current = self.motor.stall_current
28 # Free Speed in RPM
29 self.free_speed = self.motor.free_speed
30 # Free Current in Amps
31 self.free_current = self.motor.free_current
Michael Schuh10dd1e02018-01-20 13:19:44 -080032
Austin Schuh17dd0892018-03-02 20:06:31 -080033 # Resistance of the motor
34 self.resistance = self.motor.resistance
35 # Motor velocity constant
36 self.Kv = self.motor.Kv
37 # Torque constant
38 self.Kt = self.motor.Kt
39 # Gear ratio
40 self.G = 1.0 / 102.6
Michael Schuh10dd1e02018-01-20 13:19:44 -080041
Austin Schuh17dd0892018-03-02 20:06:31 -080042 self.motor_inertia = 0.00000589 * 1.2
Michael Schuh10dd1e02018-01-20 13:19:44 -080043
Austin Schuh17dd0892018-03-02 20:06:31 -080044 # Series elastic moment of inertia
45 self.Je = self.motor_inertia / (self.G * self.G)
46 # Grabber moment of inertia
47 self.Jo = 0.0363
Michael Schuh10dd1e02018-01-20 13:19:44 -080048
Austin Schuh17dd0892018-03-02 20:06:31 -080049 # Bot has a time constant of 0.22
50 # Current physics has a time constant of 0.18
Michael Schuh10dd1e02018-01-20 13:19:44 -080051
Austin Schuh17dd0892018-03-02 20:06:31 -080052 # Spring constant (N m / radian)
53 self.Ks = 32.74
Michael Schuh10dd1e02018-01-20 13:19:44 -080054
Michael Schuhd77b08c2018-02-27 22:15:07 -080055 # Damper constant (N m s/ radian)
56 # 0.01 is small and 1 is big
57 self.b = 0.1
58
Austin Schuh17dd0892018-03-02 20:06:31 -080059 # Control loop time step
60 self.dt = 0.00505
Michael Schuh10dd1e02018-01-20 13:19:44 -080061
Austin Schuh17dd0892018-03-02 20:06:31 -080062 # State is [output_position, output_velocity,
63 # elastic_position, elastic_velocity]
64 # The output position is the absolute position of the intake arm.
65 # The elastic position is the absolute position of the motor side of the
66 # series elastic.
67 # Input is [voltage]
Michael Schuh10dd1e02018-01-20 13:19:44 -080068
Austin Schuh17dd0892018-03-02 20:06:31 -080069 self.A_continuous = numpy.matrix(
70 [[0.0, 1.0, 0.0, 0.0],
Tyler Chatow6738c362019-02-16 14:12:30 -080071 [(-self.Ks / self.Jo), (-self.b / self.Jo), (self.Ks / self.Jo),
72 (self.b / self.Jo)], [0.0, 0.0, 0.0, 1.0],
73 [(self.Ks / self.Je), (self.b / self.Je), (-self.Ks / self.Je),
74 (-self.b / self.Je) - self.Kt /
75 (self.Je * self.resistance * self.Kv * self.G * self.G)]])
Michael Schuh10dd1e02018-01-20 13:19:44 -080076
Austin Schuh17dd0892018-03-02 20:06:31 -080077 # Start with the unmodified input
78 self.B_continuous = numpy.matrix(
79 [[0.0], [0.0], [0.0],
80 [self.Kt / (self.G * self.Je * self.resistance)]])
Michael Schuh10dd1e02018-01-20 13:19:44 -080081
Austin Schuh17dd0892018-03-02 20:06:31 -080082 self.C = numpy.matrix([[1.0, 0.0, -1.0, 0.0], [0.0, 0.0, 1.0, 0.0]])
83 self.D = numpy.matrix([[0.0], [0.0]])
Michael Schuh10dd1e02018-01-20 13:19:44 -080084
Austin Schuh17dd0892018-03-02 20:06:31 -080085 self.A, self.B = self.ContinuousToDiscrete(self.A_continuous,
86 self.B_continuous, self.dt)
Michael Schuh10dd1e02018-01-20 13:19:44 -080087
Austin Schuh17dd0892018-03-02 20:06:31 -080088 #controllability = controls.ctrb(self.A, self.B)
89 #glog.debug('ctrb: ' + repr(numpy.linalg.matrix_rank(controllability)))
Michael Schuh10dd1e02018-01-20 13:19:44 -080090
Austin Schuh17dd0892018-03-02 20:06:31 -080091 #observability = controls.ctrb(self.A.T, self.C.T)
92 #glog.debug('obs: ' + repr(numpy.linalg.matrix_rank(observability)))
Michael Schuh10dd1e02018-01-20 13:19:44 -080093
Austin Schuh17dd0892018-03-02 20:06:31 -080094 glog.debug('A_continuous ' + repr(self.A_continuous))
95 glog.debug('B_continuous ' + repr(self.B_continuous))
Michael Schuh10dd1e02018-01-20 13:19:44 -080096
Austin Schuh17dd0892018-03-02 20:06:31 -080097 self.K = numpy.matrix(numpy.zeros((1, 4)))
Austin Schuhf173eb82018-01-20 23:32:30 -080098
Austin Schuh17dd0892018-03-02 20:06:31 -080099 q_pos = 0.05
100 q_vel = 2.65
101 self.Q = numpy.matrix(
Tyler Chatow6738c362019-02-16 14:12:30 -0800102 numpy.diag([(q_pos**2.0), (q_vel**2.0), (q_pos**2.0),
103 (q_vel**2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800104
Austin Schuh17dd0892018-03-02 20:06:31 -0800105 r_nm = 0.025
106 self.R = numpy.matrix(numpy.diag([(r_nm**2.0), (r_nm**2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800107
Ravago Jones5127ccc2022-07-31 16:32:45 -0700108 self.KalmanGain, self.Q_steady = controls.kalman(A=self.A,
109 B=self.B,
110 C=self.C,
111 Q=self.Q,
112 R=self.R)
Austin Schuhf173eb82018-01-20 23:32:30 -0800113
Austin Schuh17dd0892018-03-02 20:06:31 -0800114 # The box formed by U_min and U_max must encompass all possible values,
115 # or else Austin's code gets angry.
116 self.U_max = numpy.matrix([[12.0]])
117 self.U_min = numpy.matrix([[-12.0]])
118
119 self.InitializeState()
Austin Schuhf173eb82018-01-20 23:32:30 -0800120
121
122class DelayedIntake(Intake):
Tyler Chatow6738c362019-02-16 14:12:30 -0800123
Austin Schuh17dd0892018-03-02 20:06:31 -0800124 def __init__(self, name="DelayedIntake"):
125 super(DelayedIntake, self).__init__(name=name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800126
Austin Schuh17dd0892018-03-02 20:06:31 -0800127 self.A_undelayed = self.A
128 self.B_undelayed = self.B
Austin Schuhf173eb82018-01-20 23:32:30 -0800129
Austin Schuh17dd0892018-03-02 20:06:31 -0800130 self.C_unaugmented = self.C
131 self.C = numpy.matrix(numpy.zeros((2, 5)))
132 self.C[0:2, 0:4] = self.C_unaugmented
Austin Schuhf173eb82018-01-20 23:32:30 -0800133
Austin Schuh17dd0892018-03-02 20:06:31 -0800134 # Model this as X[4] is the last power. And then B applies to the last
135 # power. This lets us model the 1 cycle PWM delay accurately.
136 self.A = numpy.matrix(numpy.zeros((5, 5)))
137 self.A[0:4, 0:4] = self.A_undelayed
138 self.A[0:4, 4] = self.B_undelayed
139 self.B = numpy.matrix(numpy.zeros((5, 1)))
140 self.B[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800141
Austin Schuh17dd0892018-03-02 20:06:31 -0800142 # Coordinate transform fom absolute angles to relative angles.
143 # [output_position, output_velocity, spring_angle, spring_velocity, voltage]
Tyler Chatow6738c362019-02-16 14:12:30 -0800144 abs_to_rel = numpy.matrix([[1.0, 0.0, 0.0, 0.0, 0.0],
145 [0.0, 1.0, 0.0, 0.0, 0.0],
146 [1.0, 0.0, -1.0, 0.0, 0.0],
147 [0.0, 1.0, 0.0, -1.0, 0.0],
148 [0.0, 0.0, 0.0, 0.0, 1.0]])
Austin Schuh17dd0892018-03-02 20:06:31 -0800149 # and back again.
150 rel_to_abs = numpy.matrix(numpy.linalg.inv(abs_to_rel))
Austin Schuhf173eb82018-01-20 23:32:30 -0800151
Austin Schuh17dd0892018-03-02 20:06:31 -0800152 # Now, get A and B in the relative coordinate system.
153 self.A_transformed_full = numpy.matrix(numpy.zeros((5, 5)))
154 self.B_transformed_full = numpy.matrix(numpy.zeros((5, 1)))
155 (self.A_transformed_full[0:4, 0:4],
156 self.A_transformed_full[0:4, 4]) = self.ContinuousToDiscrete(
157 abs_to_rel[0:4, 0:4] * self.A_continuous * rel_to_abs[0:4, 0:4],
158 abs_to_rel[0:4, 0:4] * self.B_continuous, self.dt)
159 self.B_transformed_full[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800160
Austin Schuh17dd0892018-03-02 20:06:31 -0800161 # Pull out the components of the dynamics which don't include the spring
162 # output position so we can do partial state feedback on what we care about.
163 self.A_transformed = self.A_transformed_full[1:5, 1:5]
164 self.B_transformed = self.B_transformed_full[1:5, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800165
Austin Schuh17dd0892018-03-02 20:06:31 -0800166 glog.debug('A_transformed_full ' + str(self.A_transformed_full))
167 glog.debug('B_transformed_full ' + str(self.B_transformed_full))
168 glog.debug('A_transformed ' + str(self.A_transformed))
169 glog.debug('B_transformed ' + str(self.B_transformed))
Austin Schuhf173eb82018-01-20 23:32:30 -0800170
Austin Schuh17dd0892018-03-02 20:06:31 -0800171 # Now, let's design a controller in
172 # [output_velocity, spring_position, spring_velocity, delayed_voltage]
173 # space.
Austin Schuhf173eb82018-01-20 23:32:30 -0800174
Austin Schuh17dd0892018-03-02 20:06:31 -0800175 q_output_vel = 1.0
Austin Schuhede47322018-07-08 16:04:36 -0700176 q_spring_pos = 0.10
Austin Schuh17dd0892018-03-02 20:06:31 -0800177 q_spring_vel = 2.0
178 q_voltage = 1000000000000.0
179 self.Q_lqr = numpy.matrix(
180 numpy.diag([
181 1.0 / (q_output_vel**2.0), 1.0 / (q_spring_pos**2.0),
182 1.0 / (q_spring_vel**2.0), 1.0 / (q_voltage**2.0)
183 ]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800184
Austin Schuh17dd0892018-03-02 20:06:31 -0800185 self.R = numpy.matrix([[(1.0 / (12.0**2.0))]])
Austin Schuhf173eb82018-01-20 23:32:30 -0800186
Ravago Jones5127ccc2022-07-31 16:32:45 -0700187 self.K_transformed = controls.dlqr(self.A_transformed,
188 self.B_transformed, self.Q_lqr,
189 self.R)
Austin Schuhf173eb82018-01-20 23:32:30 -0800190
Austin Schuh17dd0892018-03-02 20:06:31 -0800191 # Write the controller back out in the absolute coordinate system.
Tyler Chatow6738c362019-02-16 14:12:30 -0800192 self.K = numpy.hstack(
193 (numpy.matrix([[0.0]]), self.K_transformed)) * abs_to_rel
Austin Schuhf173eb82018-01-20 23:32:30 -0800194
Austin Schuh17dd0892018-03-02 20:06:31 -0800195 controllability = controls.ctrb(self.A_transformed, self.B_transformed)
196 glog.debug('ctrb: ' + repr(numpy.linalg.matrix_rank(controllability)))
Austin Schuhf173eb82018-01-20 23:32:30 -0800197
Tyler Chatow6738c362019-02-16 14:12:30 -0800198 w, v = numpy.linalg.eig(self.A_transformed -
199 self.B_transformed * self.K_transformed)
Austin Schuh17dd0892018-03-02 20:06:31 -0800200 glog.debug('Poles are %s, for %s', repr(w), self._name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800201
Austin Schuh17dd0892018-03-02 20:06:31 -0800202 for i in range(len(w)):
203 glog.debug(' Pole %s -> %s', repr(w[i]), v[:, i])
Austin Schuhf173eb82018-01-20 23:32:30 -0800204
Austin Schuh17dd0892018-03-02 20:06:31 -0800205 glog.debug('K is %s', repr(self.K_transformed))
Austin Schuhf173eb82018-01-20 23:32:30 -0800206
Austin Schuh17dd0892018-03-02 20:06:31 -0800207 # Design a kalman filter here as well.
208 q_pos = 0.05
209 q_vel = 2.65
210 q_volts = 0.005
211 self.Q = numpy.matrix(
212 numpy.diag([(q_pos**2.0), (q_vel**2.0), (q_pos**2.0), (q_vel**2.0),
213 (q_volts**2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800214
Austin Schuh17dd0892018-03-02 20:06:31 -0800215 r_nm = 0.025
216 self.R = numpy.matrix(numpy.diag([(r_nm**2.0), (r_nm**2.0)]))
217
218 glog.debug('Overall poles are %s, for %s',
219 repr(numpy.linalg.eig(self.A - self.B * self.K)[0]),
220 self._name)
221
Ravago Jones5127ccc2022-07-31 16:32:45 -0700222 self.KalmanGain, self.Q_steady = controls.kalman(A=self.A,
223 B=self.B,
224 C=self.C,
225 Q=self.Q,
226 R=self.R)
Austin Schuh17dd0892018-03-02 20:06:31 -0800227
228 self.InitializeState()
Austin Schuhf173eb82018-01-20 23:32:30 -0800229
230
231class ScenarioPlotter(object):
Tyler Chatow6738c362019-02-16 14:12:30 -0800232
Austin Schuh17dd0892018-03-02 20:06:31 -0800233 def __init__(self):
234 # Various lists for graphing things.
235 self.t = []
236 self.x_motor = []
237 self.x_output = []
238 self.v = []
239 self.goal_v = []
240 self.a = []
241 self.spring = []
242 self.x_hat = []
243 self.u = []
Austin Schuhf173eb82018-01-20 23:32:30 -0800244
Austin Schuh17dd0892018-03-02 20:06:31 -0800245 def run_test(self,
246 intake,
247 iterations=400,
248 controller_intake=None,
249 observer_intake=None):
250 """Runs the intake plant with an initial condition and goal.
Austin Schuhf173eb82018-01-20 23:32:30 -0800251
252 Test for whether the goal has been reached and whether the separation
253 goes outside of the initial and goal values by more than
254 max_separation_error.
255
256 Prints out something for a failure of either condition and returns
257 False if tests fail.
258 Args:
259 intake: intake object to use.
260 iterations: Number of timesteps to run the model for.
261 controller_intake: Intake object to get K from, or None if we should
262 use intake.
263 observer_intake: Intake object to use for the observer, or None if we
264 should use the actual state.
265 """
266
Austin Schuh17dd0892018-03-02 20:06:31 -0800267 if controller_intake is None:
268 controller_intake = intake
Austin Schuhf173eb82018-01-20 23:32:30 -0800269
Austin Schuh17dd0892018-03-02 20:06:31 -0800270 vbat = 12.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800271
Austin Schuh17dd0892018-03-02 20:06:31 -0800272 if self.t:
273 initial_t = self.t[-1] + intake.dt
274 else:
275 initial_t = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800276
Austin Schuh17dd0892018-03-02 20:06:31 -0800277 # Delay U by 1 cycle in our simulation to make it more realistic.
278 last_U = numpy.matrix([[0.0]])
279 intake.Y = intake.C * intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800280
Michael Schuhd77b08c2018-02-27 22:15:07 -0800281 # Start with the intake deflected by 0.2 radians
282 # intake.X[0,0] = 0.2
283 # intake.Y[0,0] = intake.X[0,0]
284 # observer_intake.X_hat[0,0] = intake.X[0,0]
285
Austin Schuh5ea48472021-02-02 20:46:41 -0800286 for i in range(iterations):
Austin Schuh17dd0892018-03-02 20:06:31 -0800287 X_hat = intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800288
Austin Schuh17dd0892018-03-02 20:06:31 -0800289 if observer_intake is not None:
290 X_hat = observer_intake.X_hat
291 self.x_hat.append(observer_intake.X_hat[0, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800292
Austin Schuh17dd0892018-03-02 20:06:31 -0800293 goal_angle = 3.0
294 goal_velocity = numpy.clip((goal_angle - X_hat[0, 0]) * 6.0, -1.0,
295 1.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800296
Austin Schuh17dd0892018-03-02 20:06:31 -0800297 self.goal_v.append(goal_velocity)
Austin Schuhf173eb82018-01-20 23:32:30 -0800298
Austin Schuh17dd0892018-03-02 20:06:31 -0800299 # Nominal: 1.8 N at 0.25 m -> 0.45 N m
300 # Nominal: 13 N at 0.25 m at 0.5 radians -> 3.25 N m -> 6 N m / radian
Austin Schuhf173eb82018-01-20 23:32:30 -0800301
Austin Schuh17dd0892018-03-02 20:06:31 -0800302 R = numpy.matrix([[0.0], [goal_velocity], [0.0], [goal_velocity],
303 [goal_velocity / (intake.G * intake.Kv)]])
304 U = controller_intake.K * (R - X_hat) + R[4, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800305
Tyler Chatow6738c362019-02-16 14:12:30 -0800306 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat) # * 0.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800307
Austin Schuh17dd0892018-03-02 20:06:31 -0800308 self.x_output.append(intake.X[0, 0])
309 self.x_motor.append(intake.X[2, 0])
310 self.spring.append(intake.X[0, 0] - intake.X[2, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800311
Austin Schuh17dd0892018-03-02 20:06:31 -0800312 if self.v:
313 last_v = self.v[-1]
314 else:
315 last_v = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800316
Austin Schuh17dd0892018-03-02 20:06:31 -0800317 self.v.append(intake.X[1, 0])
318 self.a.append((self.v[-1] - last_v) / intake.dt)
Austin Schuhf173eb82018-01-20 23:32:30 -0800319
Austin Schuh17dd0892018-03-02 20:06:31 -0800320 if observer_intake is not None:
321 observer_intake.Y = intake.Y
322 observer_intake.CorrectObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800323
Austin Schuh17dd0892018-03-02 20:06:31 -0800324 intake.Update(last_U + 0.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800325
Austin Schuh17dd0892018-03-02 20:06:31 -0800326 if observer_intake is not None:
327 observer_intake.PredictObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800328
Austin Schuh17dd0892018-03-02 20:06:31 -0800329 self.t.append(initial_t + i * intake.dt)
330 self.u.append(U[0, 0])
331 last_U = U
Austin Schuhf173eb82018-01-20 23:32:30 -0800332
Austin Schuh17dd0892018-03-02 20:06:31 -0800333 def Plot(self):
334 pylab.subplot(3, 1, 1)
335 pylab.plot(self.t, self.x_output, label='x output')
336 pylab.plot(self.t, self.x_motor, label='x motor')
337 pylab.plot(self.t, self.x_hat, label='x_hat')
338 pylab.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800339
Austin Schuh17dd0892018-03-02 20:06:31 -0800340 spring_ax1 = pylab.subplot(3, 1, 2)
341 spring_ax1.plot(self.t, self.u, 'k', label='u')
342 spring_ax2 = spring_ax1.twinx()
343 spring_ax2.plot(self.t, self.spring, label='spring_angle')
344 spring_ax1.legend(loc=2)
345 spring_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800346
Austin Schuh17dd0892018-03-02 20:06:31 -0800347 accel_ax1 = pylab.subplot(3, 1, 3)
348 accel_ax1.plot(self.t, self.a, 'r', label='a')
Austin Schuhf173eb82018-01-20 23:32:30 -0800349
Austin Schuh17dd0892018-03-02 20:06:31 -0800350 accel_ax2 = accel_ax1.twinx()
351 accel_ax2.plot(self.t, self.v, label='v')
352 accel_ax2.plot(self.t, self.goal_v, label='goal_v')
353 accel_ax1.legend(loc=2)
354 accel_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800355
Austin Schuh17dd0892018-03-02 20:06:31 -0800356 pylab.show()
Austin Schuhf173eb82018-01-20 23:32:30 -0800357
358
359def main(argv):
Austin Schuh17dd0892018-03-02 20:06:31 -0800360 scenario_plotter = ScenarioPlotter()
Austin Schuhf173eb82018-01-20 23:32:30 -0800361
Austin Schuh17dd0892018-03-02 20:06:31 -0800362 intake = Intake()
363 intake.X[0, 0] = 0.0
364 intake_controller = DelayedIntake()
365 observer_intake = DelayedIntake()
366 observer_intake.X_hat[0, 0] = intake.X[0, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800367
Austin Schuh17dd0892018-03-02 20:06:31 -0800368 # Test moving the intake with constant separation.
Ravago Jones5127ccc2022-07-31 16:32:45 -0700369 scenario_plotter.run_test(intake,
370 controller_intake=intake_controller,
371 observer_intake=observer_intake,
372 iterations=200)
Austin Schuhf173eb82018-01-20 23:32:30 -0800373
Austin Schuh17dd0892018-03-02 20:06:31 -0800374 if FLAGS.plot:
375 scenario_plotter.Plot()
Austin Schuhf173eb82018-01-20 23:32:30 -0800376
Austin Schuh17dd0892018-03-02 20:06:31 -0800377 # Write the generated constants out to a file.
378 if len(argv) != 5:
379 glog.fatal(
380 'Expected .h file name and .cc file name for intake and delayed_intake.'
381 )
382 else:
383 namespaces = ['y2018', 'control_loops', 'superstructure', 'intake']
384 intake = Intake('Intake')
Ravago Jones5127ccc2022-07-31 16:32:45 -0700385 loop_writer = control_loop.ControlLoopWriter('Intake', [intake],
386 namespaces=namespaces)
Austin Schuh17dd0892018-03-02 20:06:31 -0800387 loop_writer.AddConstant(
388 control_loop.Constant('kGearRatio', '%f', intake.G))
389 loop_writer.AddConstant(
390 control_loop.Constant('kMotorVelocityConstant', '%f', intake.Kv))
391 loop_writer.AddConstant(
392 control_loop.Constant('kFreeSpeed', '%f', intake.free_speed))
393 loop_writer.Write(argv[1], argv[2])
Austin Schuhf173eb82018-01-20 23:32:30 -0800394
Austin Schuh17dd0892018-03-02 20:06:31 -0800395 delayed_intake = DelayedIntake('DelayedIntake')
Ravago Jones5127ccc2022-07-31 16:32:45 -0700396 loop_writer = control_loop.ControlLoopWriter('DelayedIntake',
397 [delayed_intake],
398 namespaces=namespaces)
Austin Schuh17dd0892018-03-02 20:06:31 -0800399 loop_writer.Write(argv[3], argv[4])
400
Sabina Davis3922dfa2018-02-10 23:10:05 -0800401
Michael Schuh10dd1e02018-01-20 13:19:44 -0800402if __name__ == '__main__':
Austin Schuh17dd0892018-03-02 20:06:31 -0800403 argv = FLAGS(sys.argv)
404 glog.init()
405 sys.exit(main(argv))