blob: 3802505ef760078b198d956d2310f0bbf3ffb993 [file] [log] [blame]
Austin Schuhf173eb82018-01-20 23:32:30 -08001#!/usr/bin/python
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
Austin Schuh17dd0892018-03-02 20:06:31 -0800108 self.KalmanGain, self.Q_steady = controls.kalman(
109 A=self.A, B=self.B, C=self.C, Q=self.Q, R=self.R)
Austin Schuhf173eb82018-01-20 23:32:30 -0800110
Austin Schuh17dd0892018-03-02 20:06:31 -0800111 # The box formed by U_min and U_max must encompass all possible values,
112 # or else Austin's code gets angry.
113 self.U_max = numpy.matrix([[12.0]])
114 self.U_min = numpy.matrix([[-12.0]])
115
116 self.InitializeState()
Austin Schuhf173eb82018-01-20 23:32:30 -0800117
118
119class DelayedIntake(Intake):
Tyler Chatow6738c362019-02-16 14:12:30 -0800120
Austin Schuh17dd0892018-03-02 20:06:31 -0800121 def __init__(self, name="DelayedIntake"):
122 super(DelayedIntake, self).__init__(name=name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800123
Austin Schuh17dd0892018-03-02 20:06:31 -0800124 self.A_undelayed = self.A
125 self.B_undelayed = self.B
Austin Schuhf173eb82018-01-20 23:32:30 -0800126
Austin Schuh17dd0892018-03-02 20:06:31 -0800127 self.C_unaugmented = self.C
128 self.C = numpy.matrix(numpy.zeros((2, 5)))
129 self.C[0:2, 0:4] = self.C_unaugmented
Austin Schuhf173eb82018-01-20 23:32:30 -0800130
Austin Schuh17dd0892018-03-02 20:06:31 -0800131 # Model this as X[4] is the last power. And then B applies to the last
132 # power. This lets us model the 1 cycle PWM delay accurately.
133 self.A = numpy.matrix(numpy.zeros((5, 5)))
134 self.A[0:4, 0:4] = self.A_undelayed
135 self.A[0:4, 4] = self.B_undelayed
136 self.B = numpy.matrix(numpy.zeros((5, 1)))
137 self.B[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800138
Austin Schuh17dd0892018-03-02 20:06:31 -0800139 # Coordinate transform fom absolute angles to relative angles.
140 # [output_position, output_velocity, spring_angle, spring_velocity, voltage]
Tyler Chatow6738c362019-02-16 14:12:30 -0800141 abs_to_rel = numpy.matrix([[1.0, 0.0, 0.0, 0.0, 0.0],
142 [0.0, 1.0, 0.0, 0.0, 0.0],
143 [1.0, 0.0, -1.0, 0.0, 0.0],
144 [0.0, 1.0, 0.0, -1.0, 0.0],
145 [0.0, 0.0, 0.0, 0.0, 1.0]])
Austin Schuh17dd0892018-03-02 20:06:31 -0800146 # and back again.
147 rel_to_abs = numpy.matrix(numpy.linalg.inv(abs_to_rel))
Austin Schuhf173eb82018-01-20 23:32:30 -0800148
Austin Schuh17dd0892018-03-02 20:06:31 -0800149 # Now, get A and B in the relative coordinate system.
150 self.A_transformed_full = numpy.matrix(numpy.zeros((5, 5)))
151 self.B_transformed_full = numpy.matrix(numpy.zeros((5, 1)))
152 (self.A_transformed_full[0:4, 0:4],
153 self.A_transformed_full[0:4, 4]) = self.ContinuousToDiscrete(
154 abs_to_rel[0:4, 0:4] * self.A_continuous * rel_to_abs[0:4, 0:4],
155 abs_to_rel[0:4, 0:4] * self.B_continuous, self.dt)
156 self.B_transformed_full[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800157
Austin Schuh17dd0892018-03-02 20:06:31 -0800158 # Pull out the components of the dynamics which don't include the spring
159 # output position so we can do partial state feedback on what we care about.
160 self.A_transformed = self.A_transformed_full[1:5, 1:5]
161 self.B_transformed = self.B_transformed_full[1:5, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800162
Austin Schuh17dd0892018-03-02 20:06:31 -0800163 glog.debug('A_transformed_full ' + str(self.A_transformed_full))
164 glog.debug('B_transformed_full ' + str(self.B_transformed_full))
165 glog.debug('A_transformed ' + str(self.A_transformed))
166 glog.debug('B_transformed ' + str(self.B_transformed))
Austin Schuhf173eb82018-01-20 23:32:30 -0800167
Austin Schuh17dd0892018-03-02 20:06:31 -0800168 # Now, let's design a controller in
169 # [output_velocity, spring_position, spring_velocity, delayed_voltage]
170 # space.
Austin Schuhf173eb82018-01-20 23:32:30 -0800171
Austin Schuh17dd0892018-03-02 20:06:31 -0800172 q_output_vel = 1.0
Austin Schuhede47322018-07-08 16:04:36 -0700173 q_spring_pos = 0.10
Austin Schuh17dd0892018-03-02 20:06:31 -0800174 q_spring_vel = 2.0
175 q_voltage = 1000000000000.0
176 self.Q_lqr = numpy.matrix(
177 numpy.diag([
178 1.0 / (q_output_vel**2.0), 1.0 / (q_spring_pos**2.0),
179 1.0 / (q_spring_vel**2.0), 1.0 / (q_voltage**2.0)
180 ]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800181
Austin Schuh17dd0892018-03-02 20:06:31 -0800182 self.R = numpy.matrix([[(1.0 / (12.0**2.0))]])
Austin Schuhf173eb82018-01-20 23:32:30 -0800183
Austin Schuh17dd0892018-03-02 20:06:31 -0800184 self.K_transformed = controls.dlqr(
185 self.A_transformed, self.B_transformed, self.Q_lqr, self.R)
Austin Schuhf173eb82018-01-20 23:32:30 -0800186
Austin Schuh17dd0892018-03-02 20:06:31 -0800187 # Write the controller back out in the absolute coordinate system.
Tyler Chatow6738c362019-02-16 14:12:30 -0800188 self.K = numpy.hstack(
189 (numpy.matrix([[0.0]]), self.K_transformed)) * abs_to_rel
Austin Schuhf173eb82018-01-20 23:32:30 -0800190
Austin Schuh17dd0892018-03-02 20:06:31 -0800191 controllability = controls.ctrb(self.A_transformed, self.B_transformed)
192 glog.debug('ctrb: ' + repr(numpy.linalg.matrix_rank(controllability)))
Austin Schuhf173eb82018-01-20 23:32:30 -0800193
Tyler Chatow6738c362019-02-16 14:12:30 -0800194 w, v = numpy.linalg.eig(self.A_transformed -
195 self.B_transformed * self.K_transformed)
Austin Schuh17dd0892018-03-02 20:06:31 -0800196 glog.debug('Poles are %s, for %s', repr(w), self._name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800197
Austin Schuh17dd0892018-03-02 20:06:31 -0800198 for i in range(len(w)):
199 glog.debug(' Pole %s -> %s', repr(w[i]), v[:, i])
Austin Schuhf173eb82018-01-20 23:32:30 -0800200
Austin Schuh17dd0892018-03-02 20:06:31 -0800201 glog.debug('K is %s', repr(self.K_transformed))
Austin Schuhf173eb82018-01-20 23:32:30 -0800202
Austin Schuh17dd0892018-03-02 20:06:31 -0800203 # Design a kalman filter here as well.
204 q_pos = 0.05
205 q_vel = 2.65
206 q_volts = 0.005
207 self.Q = numpy.matrix(
208 numpy.diag([(q_pos**2.0), (q_vel**2.0), (q_pos**2.0), (q_vel**2.0),
209 (q_volts**2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800210
Austin Schuh17dd0892018-03-02 20:06:31 -0800211 r_nm = 0.025
212 self.R = numpy.matrix(numpy.diag([(r_nm**2.0), (r_nm**2.0)]))
213
214 glog.debug('Overall poles are %s, for %s',
215 repr(numpy.linalg.eig(self.A - self.B * self.K)[0]),
216 self._name)
217
218 self.KalmanGain, self.Q_steady = controls.kalman(
219 A=self.A, B=self.B, C=self.C, Q=self.Q, R=self.R)
220
221 self.InitializeState()
Austin Schuhf173eb82018-01-20 23:32:30 -0800222
223
224class ScenarioPlotter(object):
Tyler Chatow6738c362019-02-16 14:12:30 -0800225
Austin Schuh17dd0892018-03-02 20:06:31 -0800226 def __init__(self):
227 # Various lists for graphing things.
228 self.t = []
229 self.x_motor = []
230 self.x_output = []
231 self.v = []
232 self.goal_v = []
233 self.a = []
234 self.spring = []
235 self.x_hat = []
236 self.u = []
Austin Schuhf173eb82018-01-20 23:32:30 -0800237
Austin Schuh17dd0892018-03-02 20:06:31 -0800238 def run_test(self,
239 intake,
240 iterations=400,
241 controller_intake=None,
242 observer_intake=None):
243 """Runs the intake plant with an initial condition and goal.
Austin Schuhf173eb82018-01-20 23:32:30 -0800244
245 Test for whether the goal has been reached and whether the separation
246 goes outside of the initial and goal values by more than
247 max_separation_error.
248
249 Prints out something for a failure of either condition and returns
250 False if tests fail.
251 Args:
252 intake: intake object to use.
253 iterations: Number of timesteps to run the model for.
254 controller_intake: Intake object to get K from, or None if we should
255 use intake.
256 observer_intake: Intake object to use for the observer, or None if we
257 should use the actual state.
258 """
259
Austin Schuh17dd0892018-03-02 20:06:31 -0800260 if controller_intake is None:
261 controller_intake = intake
Austin Schuhf173eb82018-01-20 23:32:30 -0800262
Austin Schuh17dd0892018-03-02 20:06:31 -0800263 vbat = 12.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800264
Austin Schuh17dd0892018-03-02 20:06:31 -0800265 if self.t:
266 initial_t = self.t[-1] + intake.dt
267 else:
268 initial_t = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800269
Austin Schuh17dd0892018-03-02 20:06:31 -0800270 # Delay U by 1 cycle in our simulation to make it more realistic.
271 last_U = numpy.matrix([[0.0]])
272 intake.Y = intake.C * intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800273
Michael Schuhd77b08c2018-02-27 22:15:07 -0800274 # Start with the intake deflected by 0.2 radians
275 # intake.X[0,0] = 0.2
276 # intake.Y[0,0] = intake.X[0,0]
277 # observer_intake.X_hat[0,0] = intake.X[0,0]
278
Austin Schuh5ea48472021-02-02 20:46:41 -0800279 for i in range(iterations):
Austin Schuh17dd0892018-03-02 20:06:31 -0800280 X_hat = intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800281
Austin Schuh17dd0892018-03-02 20:06:31 -0800282 if observer_intake is not None:
283 X_hat = observer_intake.X_hat
284 self.x_hat.append(observer_intake.X_hat[0, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800285
Austin Schuh17dd0892018-03-02 20:06:31 -0800286 goal_angle = 3.0
287 goal_velocity = numpy.clip((goal_angle - X_hat[0, 0]) * 6.0, -1.0,
288 1.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800289
Austin Schuh17dd0892018-03-02 20:06:31 -0800290 self.goal_v.append(goal_velocity)
Austin Schuhf173eb82018-01-20 23:32:30 -0800291
Austin Schuh17dd0892018-03-02 20:06:31 -0800292 # Nominal: 1.8 N at 0.25 m -> 0.45 N m
293 # 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 -0800294
Austin Schuh17dd0892018-03-02 20:06:31 -0800295 R = numpy.matrix([[0.0], [goal_velocity], [0.0], [goal_velocity],
296 [goal_velocity / (intake.G * intake.Kv)]])
297 U = controller_intake.K * (R - X_hat) + R[4, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800298
Tyler Chatow6738c362019-02-16 14:12:30 -0800299 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat) # * 0.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800300
Austin Schuh17dd0892018-03-02 20:06:31 -0800301 self.x_output.append(intake.X[0, 0])
302 self.x_motor.append(intake.X[2, 0])
303 self.spring.append(intake.X[0, 0] - intake.X[2, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800304
Austin Schuh17dd0892018-03-02 20:06:31 -0800305 if self.v:
306 last_v = self.v[-1]
307 else:
308 last_v = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800309
Austin Schuh17dd0892018-03-02 20:06:31 -0800310 self.v.append(intake.X[1, 0])
311 self.a.append((self.v[-1] - last_v) / intake.dt)
Austin Schuhf173eb82018-01-20 23:32:30 -0800312
Austin Schuh17dd0892018-03-02 20:06:31 -0800313 if observer_intake is not None:
314 observer_intake.Y = intake.Y
315 observer_intake.CorrectObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800316
Austin Schuh17dd0892018-03-02 20:06:31 -0800317 intake.Update(last_U + 0.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800318
Austin Schuh17dd0892018-03-02 20:06:31 -0800319 if observer_intake is not None:
320 observer_intake.PredictObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800321
Austin Schuh17dd0892018-03-02 20:06:31 -0800322 self.t.append(initial_t + i * intake.dt)
323 self.u.append(U[0, 0])
324 last_U = U
Austin Schuhf173eb82018-01-20 23:32:30 -0800325
Austin Schuh17dd0892018-03-02 20:06:31 -0800326 def Plot(self):
327 pylab.subplot(3, 1, 1)
328 pylab.plot(self.t, self.x_output, label='x output')
329 pylab.plot(self.t, self.x_motor, label='x motor')
330 pylab.plot(self.t, self.x_hat, label='x_hat')
331 pylab.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800332
Austin Schuh17dd0892018-03-02 20:06:31 -0800333 spring_ax1 = pylab.subplot(3, 1, 2)
334 spring_ax1.plot(self.t, self.u, 'k', label='u')
335 spring_ax2 = spring_ax1.twinx()
336 spring_ax2.plot(self.t, self.spring, label='spring_angle')
337 spring_ax1.legend(loc=2)
338 spring_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800339
Austin Schuh17dd0892018-03-02 20:06:31 -0800340 accel_ax1 = pylab.subplot(3, 1, 3)
341 accel_ax1.plot(self.t, self.a, 'r', label='a')
Austin Schuhf173eb82018-01-20 23:32:30 -0800342
Austin Schuh17dd0892018-03-02 20:06:31 -0800343 accel_ax2 = accel_ax1.twinx()
344 accel_ax2.plot(self.t, self.v, label='v')
345 accel_ax2.plot(self.t, self.goal_v, label='goal_v')
346 accel_ax1.legend(loc=2)
347 accel_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800348
Austin Schuh17dd0892018-03-02 20:06:31 -0800349 pylab.show()
Austin Schuhf173eb82018-01-20 23:32:30 -0800350
351
352def main(argv):
Austin Schuh17dd0892018-03-02 20:06:31 -0800353 scenario_plotter = ScenarioPlotter()
Austin Schuhf173eb82018-01-20 23:32:30 -0800354
Austin Schuh17dd0892018-03-02 20:06:31 -0800355 intake = Intake()
356 intake.X[0, 0] = 0.0
357 intake_controller = DelayedIntake()
358 observer_intake = DelayedIntake()
359 observer_intake.X_hat[0, 0] = intake.X[0, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800360
Austin Schuh17dd0892018-03-02 20:06:31 -0800361 # Test moving the intake with constant separation.
362 scenario_plotter.run_test(
363 intake,
364 controller_intake=intake_controller,
365 observer_intake=observer_intake,
366 iterations=200)
Austin Schuhf173eb82018-01-20 23:32:30 -0800367
Austin Schuh17dd0892018-03-02 20:06:31 -0800368 if FLAGS.plot:
369 scenario_plotter.Plot()
Austin Schuhf173eb82018-01-20 23:32:30 -0800370
Austin Schuh17dd0892018-03-02 20:06:31 -0800371 # Write the generated constants out to a file.
372 if len(argv) != 5:
373 glog.fatal(
374 'Expected .h file name and .cc file name for intake and delayed_intake.'
375 )
376 else:
377 namespaces = ['y2018', 'control_loops', 'superstructure', 'intake']
378 intake = Intake('Intake')
379 loop_writer = control_loop.ControlLoopWriter(
380 'Intake', [intake], namespaces=namespaces)
381 loop_writer.AddConstant(
382 control_loop.Constant('kGearRatio', '%f', intake.G))
383 loop_writer.AddConstant(
384 control_loop.Constant('kMotorVelocityConstant', '%f', intake.Kv))
385 loop_writer.AddConstant(
386 control_loop.Constant('kFreeSpeed', '%f', intake.free_speed))
387 loop_writer.Write(argv[1], argv[2])
Austin Schuhf173eb82018-01-20 23:32:30 -0800388
Austin Schuh17dd0892018-03-02 20:06:31 -0800389 delayed_intake = DelayedIntake('DelayedIntake')
390 loop_writer = control_loop.ControlLoopWriter(
391 'DelayedIntake', [delayed_intake], namespaces=namespaces)
392 loop_writer.Write(argv[3], argv[4])
393
Sabina Davis3922dfa2018-02-10 23:10:05 -0800394
Michael Schuh10dd1e02018-01-20 13:19:44 -0800395if __name__ == '__main__':
Austin Schuh17dd0892018-03-02 20:06:31 -0800396 argv = FLAGS(sys.argv)
397 glog.init()
398 sys.exit(main(argv))