blob: 471f2463c97bc9438f071d7349fc23be82ed0041 [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):
Austin Schuh17dd0892018-03-02 20:06:31 -080020 def __init__(self, name="Intake"):
21 super(Intake, self).__init__(name)
22 self.motor = control_loop.BAG()
23 # Stall Torque in N m
24 self.stall_torque = self.motor.stall_torque
25 # Stall Current in Amps
26 self.stall_current = self.motor.stall_current
27 # Free Speed in RPM
28 self.free_speed = self.motor.free_speed
29 # Free Current in Amps
30 self.free_current = self.motor.free_current
Michael Schuh10dd1e02018-01-20 13:19:44 -080031
Austin Schuh17dd0892018-03-02 20:06:31 -080032 # Resistance of the motor
33 self.resistance = self.motor.resistance
34 # Motor velocity constant
35 self.Kv = self.motor.Kv
36 # Torque constant
37 self.Kt = self.motor.Kt
38 # Gear ratio
39 self.G = 1.0 / 102.6
Michael Schuh10dd1e02018-01-20 13:19:44 -080040
Austin Schuh17dd0892018-03-02 20:06:31 -080041 self.motor_inertia = 0.00000589 * 1.2
Michael Schuh10dd1e02018-01-20 13:19:44 -080042
Austin Schuh17dd0892018-03-02 20:06:31 -080043 # Series elastic moment of inertia
44 self.Je = self.motor_inertia / (self.G * self.G)
45 # Grabber moment of inertia
46 self.Jo = 0.0363
Michael Schuh10dd1e02018-01-20 13:19:44 -080047
Austin Schuh17dd0892018-03-02 20:06:31 -080048 # Bot has a time constant of 0.22
49 # Current physics has a time constant of 0.18
Michael Schuh10dd1e02018-01-20 13:19:44 -080050
Austin Schuh17dd0892018-03-02 20:06:31 -080051 # Spring constant (N m / radian)
52 self.Ks = 32.74
Michael Schuh10dd1e02018-01-20 13:19:44 -080053
Michael Schuhd77b08c2018-02-27 22:15:07 -080054 # Damper constant (N m s/ radian)
55 # 0.01 is small and 1 is big
56 self.b = 0.1
57
Austin Schuh17dd0892018-03-02 20:06:31 -080058 # Control loop time step
59 self.dt = 0.00505
Michael Schuh10dd1e02018-01-20 13:19:44 -080060
Austin Schuh17dd0892018-03-02 20:06:31 -080061 # State is [output_position, output_velocity,
62 # elastic_position, elastic_velocity]
63 # The output position is the absolute position of the intake arm.
64 # The elastic position is the absolute position of the motor side of the
65 # series elastic.
66 # Input is [voltage]
Michael Schuh10dd1e02018-01-20 13:19:44 -080067
Austin Schuh17dd0892018-03-02 20:06:31 -080068 self.A_continuous = numpy.matrix(
69 [[0.0, 1.0, 0.0, 0.0],
Michael Schuhd77b08c2018-02-27 22:15:07 -080070 [(-self.Ks / self.Jo), (-self.b/self.Jo),
71 (self.Ks / self.Jo), ( self.b/self.Jo)],
Austin Schuh17dd0892018-03-02 20:06:31 -080072 [0.0, 0.0, 0.0, 1.0],
Michael Schuhd77b08c2018-02-27 22:15:07 -080073 [( self.Ks / self.Je), ( self.b/self.Je),
74 (-self.Ks / self.Je), (-self.b/self.Je)
75 -self.Kt / (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(
102 numpy.diag([(q_pos**2.0), (q_vel**2.0), (q_pos**2.0), (q_vel
103 **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):
Austin Schuh17dd0892018-03-02 20:06:31 -0800120 def __init__(self, name="DelayedIntake"):
121 super(DelayedIntake, self).__init__(name=name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800122
Austin Schuh17dd0892018-03-02 20:06:31 -0800123 self.A_undelayed = self.A
124 self.B_undelayed = self.B
Austin Schuhf173eb82018-01-20 23:32:30 -0800125
Austin Schuh17dd0892018-03-02 20:06:31 -0800126 self.C_unaugmented = self.C
127 self.C = numpy.matrix(numpy.zeros((2, 5)))
128 self.C[0:2, 0:4] = self.C_unaugmented
Austin Schuhf173eb82018-01-20 23:32:30 -0800129
Austin Schuh17dd0892018-03-02 20:06:31 -0800130 # Model this as X[4] is the last power. And then B applies to the last
131 # power. This lets us model the 1 cycle PWM delay accurately.
132 self.A = numpy.matrix(numpy.zeros((5, 5)))
133 self.A[0:4, 0:4] = self.A_undelayed
134 self.A[0:4, 4] = self.B_undelayed
135 self.B = numpy.matrix(numpy.zeros((5, 1)))
136 self.B[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800137
Austin Schuh17dd0892018-03-02 20:06:31 -0800138 # Coordinate transform fom absolute angles to relative angles.
139 # [output_position, output_velocity, spring_angle, spring_velocity, voltage]
140 abs_to_rel = numpy.matrix(
141 [[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]])
146 # 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.
188 self.K = numpy.hstack((numpy.matrix([[0.0]]),
189 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
Austin Schuh17dd0892018-03-02 20:06:31 -0800194 w, v = numpy.linalg.eig(
195 self.A_transformed - self.B_transformed * self.K_transformed)
196 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):
Austin Schuh17dd0892018-03-02 20:06:31 -0800225 def __init__(self):
226 # Various lists for graphing things.
227 self.t = []
228 self.x_motor = []
229 self.x_output = []
230 self.v = []
231 self.goal_v = []
232 self.a = []
233 self.spring = []
234 self.x_hat = []
235 self.u = []
Austin Schuhf173eb82018-01-20 23:32:30 -0800236
Austin Schuh17dd0892018-03-02 20:06:31 -0800237 def run_test(self,
238 intake,
239 iterations=400,
240 controller_intake=None,
241 observer_intake=None):
242 """Runs the intake plant with an initial condition and goal.
Austin Schuhf173eb82018-01-20 23:32:30 -0800243
244 Test for whether the goal has been reached and whether the separation
245 goes outside of the initial and goal values by more than
246 max_separation_error.
247
248 Prints out something for a failure of either condition and returns
249 False if tests fail.
250 Args:
251 intake: intake object to use.
252 iterations: Number of timesteps to run the model for.
253 controller_intake: Intake object to get K from, or None if we should
254 use intake.
255 observer_intake: Intake object to use for the observer, or None if we
256 should use the actual state.
257 """
258
Austin Schuh17dd0892018-03-02 20:06:31 -0800259 if controller_intake is None:
260 controller_intake = intake
Austin Schuhf173eb82018-01-20 23:32:30 -0800261
Austin Schuh17dd0892018-03-02 20:06:31 -0800262 vbat = 12.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800263
Austin Schuh17dd0892018-03-02 20:06:31 -0800264 if self.t:
265 initial_t = self.t[-1] + intake.dt
266 else:
267 initial_t = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800268
Austin Schuh17dd0892018-03-02 20:06:31 -0800269 # Delay U by 1 cycle in our simulation to make it more realistic.
270 last_U = numpy.matrix([[0.0]])
271 intake.Y = intake.C * intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800272
Michael Schuhd77b08c2018-02-27 22:15:07 -0800273 # Start with the intake deflected by 0.2 radians
274 # intake.X[0,0] = 0.2
275 # intake.Y[0,0] = intake.X[0,0]
276 # observer_intake.X_hat[0,0] = intake.X[0,0]
277
Austin Schuh17dd0892018-03-02 20:06:31 -0800278 for i in xrange(iterations):
279 X_hat = intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800280
Austin Schuh17dd0892018-03-02 20:06:31 -0800281 if observer_intake is not None:
282 X_hat = observer_intake.X_hat
283 self.x_hat.append(observer_intake.X_hat[0, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800284
Austin Schuh17dd0892018-03-02 20:06:31 -0800285 goal_angle = 3.0
286 goal_velocity = numpy.clip((goal_angle - X_hat[0, 0]) * 6.0, -1.0,
287 1.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800288
Austin Schuh17dd0892018-03-02 20:06:31 -0800289 self.goal_v.append(goal_velocity)
Austin Schuhf173eb82018-01-20 23:32:30 -0800290
Austin Schuh17dd0892018-03-02 20:06:31 -0800291 # Nominal: 1.8 N at 0.25 m -> 0.45 N m
292 # 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 -0800293
Austin Schuh17dd0892018-03-02 20:06:31 -0800294 R = numpy.matrix([[0.0], [goal_velocity], [0.0], [goal_velocity],
295 [goal_velocity / (intake.G * intake.Kv)]])
296 U = controller_intake.K * (R - X_hat) + R[4, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800297
Austin Schuh17dd0892018-03-02 20:06:31 -0800298 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat) # * 0.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800299
Austin Schuh17dd0892018-03-02 20:06:31 -0800300 self.x_output.append(intake.X[0, 0])
301 self.x_motor.append(intake.X[2, 0])
302 self.spring.append(intake.X[0, 0] - intake.X[2, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800303
Austin Schuh17dd0892018-03-02 20:06:31 -0800304 if self.v:
305 last_v = self.v[-1]
306 else:
307 last_v = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800308
Austin Schuh17dd0892018-03-02 20:06:31 -0800309 self.v.append(intake.X[1, 0])
310 self.a.append((self.v[-1] - last_v) / intake.dt)
Austin Schuhf173eb82018-01-20 23:32:30 -0800311
Austin Schuh17dd0892018-03-02 20:06:31 -0800312 if observer_intake is not None:
313 observer_intake.Y = intake.Y
314 observer_intake.CorrectObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800315
Austin Schuh17dd0892018-03-02 20:06:31 -0800316 intake.Update(last_U + 0.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800317
Austin Schuh17dd0892018-03-02 20:06:31 -0800318 if observer_intake is not None:
319 observer_intake.PredictObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800320
Austin Schuh17dd0892018-03-02 20:06:31 -0800321 self.t.append(initial_t + i * intake.dt)
322 self.u.append(U[0, 0])
323 last_U = U
Austin Schuhf173eb82018-01-20 23:32:30 -0800324
Austin Schuh17dd0892018-03-02 20:06:31 -0800325 def Plot(self):
326 pylab.subplot(3, 1, 1)
327 pylab.plot(self.t, self.x_output, label='x output')
328 pylab.plot(self.t, self.x_motor, label='x motor')
329 pylab.plot(self.t, self.x_hat, label='x_hat')
330 pylab.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800331
Austin Schuh17dd0892018-03-02 20:06:31 -0800332 spring_ax1 = pylab.subplot(3, 1, 2)
333 spring_ax1.plot(self.t, self.u, 'k', label='u')
334 spring_ax2 = spring_ax1.twinx()
335 spring_ax2.plot(self.t, self.spring, label='spring_angle')
336 spring_ax1.legend(loc=2)
337 spring_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800338
Austin Schuh17dd0892018-03-02 20:06:31 -0800339 accel_ax1 = pylab.subplot(3, 1, 3)
340 accel_ax1.plot(self.t, self.a, 'r', label='a')
Austin Schuhf173eb82018-01-20 23:32:30 -0800341
Austin Schuh17dd0892018-03-02 20:06:31 -0800342 accel_ax2 = accel_ax1.twinx()
343 accel_ax2.plot(self.t, self.v, label='v')
344 accel_ax2.plot(self.t, self.goal_v, label='goal_v')
345 accel_ax1.legend(loc=2)
346 accel_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800347
Austin Schuh17dd0892018-03-02 20:06:31 -0800348 pylab.show()
Austin Schuhf173eb82018-01-20 23:32:30 -0800349
350
351def main(argv):
Austin Schuh17dd0892018-03-02 20:06:31 -0800352 scenario_plotter = ScenarioPlotter()
Austin Schuhf173eb82018-01-20 23:32:30 -0800353
Austin Schuh17dd0892018-03-02 20:06:31 -0800354 intake = Intake()
355 intake.X[0, 0] = 0.0
356 intake_controller = DelayedIntake()
357 observer_intake = DelayedIntake()
358 observer_intake.X_hat[0, 0] = intake.X[0, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800359
Austin Schuh17dd0892018-03-02 20:06:31 -0800360 # Test moving the intake with constant separation.
361 scenario_plotter.run_test(
362 intake,
363 controller_intake=intake_controller,
364 observer_intake=observer_intake,
365 iterations=200)
Austin Schuhf173eb82018-01-20 23:32:30 -0800366
Austin Schuh17dd0892018-03-02 20:06:31 -0800367 if FLAGS.plot:
368 scenario_plotter.Plot()
Austin Schuhf173eb82018-01-20 23:32:30 -0800369
Austin Schuh17dd0892018-03-02 20:06:31 -0800370 # Write the generated constants out to a file.
371 if len(argv) != 5:
372 glog.fatal(
373 'Expected .h file name and .cc file name for intake and delayed_intake.'
374 )
375 else:
376 namespaces = ['y2018', 'control_loops', 'superstructure', 'intake']
377 intake = Intake('Intake')
378 loop_writer = control_loop.ControlLoopWriter(
379 'Intake', [intake], namespaces=namespaces)
380 loop_writer.AddConstant(
381 control_loop.Constant('kGearRatio', '%f', intake.G))
382 loop_writer.AddConstant(
383 control_loop.Constant('kMotorVelocityConstant', '%f', intake.Kv))
384 loop_writer.AddConstant(
385 control_loop.Constant('kFreeSpeed', '%f', intake.free_speed))
386 loop_writer.Write(argv[1], argv[2])
Austin Schuhf173eb82018-01-20 23:32:30 -0800387
Austin Schuh17dd0892018-03-02 20:06:31 -0800388 delayed_intake = DelayedIntake('DelayedIntake')
389 loop_writer = control_loop.ControlLoopWriter(
390 'DelayedIntake', [delayed_intake], namespaces=namespaces)
391 loop_writer.Write(argv[3], argv[4])
392
Sabina Davis3922dfa2018-02-10 23:10:05 -0800393
Michael Schuh10dd1e02018-01-20 13:19:44 -0800394if __name__ == '__main__':
Austin Schuh17dd0892018-03-02 20:06:31 -0800395 argv = FLAGS(sys.argv)
396 glog.init()
397 sys.exit(main(argv))