blob: 4fb4f1ebe6c220c44a92909214c53f612047c8da [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
Austin Schuh17dd0892018-03-02 20:06:31 -080054 # Control loop time step
55 self.dt = 0.00505
Michael Schuh10dd1e02018-01-20 13:19:44 -080056
Austin Schuh17dd0892018-03-02 20:06:31 -080057 # State is [output_position, output_velocity,
58 # elastic_position, elastic_velocity]
59 # The output position is the absolute position of the intake arm.
60 # The elastic position is the absolute position of the motor side of the
61 # series elastic.
62 # Input is [voltage]
Michael Schuh10dd1e02018-01-20 13:19:44 -080063
Austin Schuh17dd0892018-03-02 20:06:31 -080064 self.A_continuous = numpy.matrix(
65 [[0.0, 1.0, 0.0, 0.0],
66 [(-self.Ks / self.Jo), 0.0, (self.Ks / self.Jo), 0.0],
67 [0.0, 0.0, 0.0, 1.0],
68 [(self.Ks / self.Je), 0.0, (-self.Ks / self.Je), \
69 -self.Kt / (self.Je * self.resistance * self.Kv * self.G * self.G)]])
Michael Schuh10dd1e02018-01-20 13:19:44 -080070
Austin Schuh17dd0892018-03-02 20:06:31 -080071 # Start with the unmodified input
72 self.B_continuous = numpy.matrix(
73 [[0.0], [0.0], [0.0],
74 [self.Kt / (self.G * self.Je * self.resistance)]])
Michael Schuh10dd1e02018-01-20 13:19:44 -080075
Austin Schuh17dd0892018-03-02 20:06:31 -080076 self.C = numpy.matrix([[1.0, 0.0, -1.0, 0.0], [0.0, 0.0, 1.0, 0.0]])
77 self.D = numpy.matrix([[0.0], [0.0]])
Michael Schuh10dd1e02018-01-20 13:19:44 -080078
Austin Schuh17dd0892018-03-02 20:06:31 -080079 self.A, self.B = self.ContinuousToDiscrete(self.A_continuous,
80 self.B_continuous, self.dt)
Michael Schuh10dd1e02018-01-20 13:19:44 -080081
Austin Schuh17dd0892018-03-02 20:06:31 -080082 #controllability = controls.ctrb(self.A, self.B)
83 #glog.debug('ctrb: ' + repr(numpy.linalg.matrix_rank(controllability)))
Michael Schuh10dd1e02018-01-20 13:19:44 -080084
Austin Schuh17dd0892018-03-02 20:06:31 -080085 #observability = controls.ctrb(self.A.T, self.C.T)
86 #glog.debug('obs: ' + repr(numpy.linalg.matrix_rank(observability)))
Michael Schuh10dd1e02018-01-20 13:19:44 -080087
Austin Schuh17dd0892018-03-02 20:06:31 -080088 glog.debug('A_continuous ' + repr(self.A_continuous))
89 glog.debug('B_continuous ' + repr(self.B_continuous))
Michael Schuh10dd1e02018-01-20 13:19:44 -080090
Austin Schuh17dd0892018-03-02 20:06:31 -080091 self.K = numpy.matrix(numpy.zeros((1, 4)))
Austin Schuhf173eb82018-01-20 23:32:30 -080092
Austin Schuh17dd0892018-03-02 20:06:31 -080093 q_pos = 0.05
94 q_vel = 2.65
95 self.Q = numpy.matrix(
96 numpy.diag([(q_pos**2.0), (q_vel**2.0), (q_pos**2.0), (q_vel
97 **2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -080098
Austin Schuh17dd0892018-03-02 20:06:31 -080099 r_nm = 0.025
100 self.R = numpy.matrix(numpy.diag([(r_nm**2.0), (r_nm**2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800101
Austin Schuh17dd0892018-03-02 20:06:31 -0800102 self.KalmanGain, self.Q_steady = controls.kalman(
103 A=self.A, B=self.B, C=self.C, Q=self.Q, R=self.R)
Austin Schuhf173eb82018-01-20 23:32:30 -0800104
Austin Schuh17dd0892018-03-02 20:06:31 -0800105 # The box formed by U_min and U_max must encompass all possible values,
106 # or else Austin's code gets angry.
107 self.U_max = numpy.matrix([[12.0]])
108 self.U_min = numpy.matrix([[-12.0]])
109
110 self.InitializeState()
Austin Schuhf173eb82018-01-20 23:32:30 -0800111
112
113class DelayedIntake(Intake):
Austin Schuh17dd0892018-03-02 20:06:31 -0800114 def __init__(self, name="DelayedIntake"):
115 super(DelayedIntake, self).__init__(name=name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800116
Austin Schuh17dd0892018-03-02 20:06:31 -0800117 self.A_undelayed = self.A
118 self.B_undelayed = self.B
Austin Schuhf173eb82018-01-20 23:32:30 -0800119
Austin Schuh17dd0892018-03-02 20:06:31 -0800120 self.C_unaugmented = self.C
121 self.C = numpy.matrix(numpy.zeros((2, 5)))
122 self.C[0:2, 0:4] = self.C_unaugmented
Austin Schuhf173eb82018-01-20 23:32:30 -0800123
Austin Schuh17dd0892018-03-02 20:06:31 -0800124 # Model this as X[4] is the last power. And then B applies to the last
125 # power. This lets us model the 1 cycle PWM delay accurately.
126 self.A = numpy.matrix(numpy.zeros((5, 5)))
127 self.A[0:4, 0:4] = self.A_undelayed
128 self.A[0:4, 4] = self.B_undelayed
129 self.B = numpy.matrix(numpy.zeros((5, 1)))
130 self.B[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800131
Austin Schuh17dd0892018-03-02 20:06:31 -0800132 # Coordinate transform fom absolute angles to relative angles.
133 # [output_position, output_velocity, spring_angle, spring_velocity, voltage]
134 abs_to_rel = numpy.matrix(
135 [[1.0, 0.0, 0.0, 0.0, 0.0],
136 [0.0, 1.0, 0.0, 0.0, 0.0],
137 [1.0, 0.0, -1.0, 0.0, 0.0],
138 [0.0, 1.0, 0.0, -1.0, 0.0],
139 [0.0, 0.0, 0.0, 0.0, 1.0]])
140 # and back again.
141 rel_to_abs = numpy.matrix(numpy.linalg.inv(abs_to_rel))
Austin Schuhf173eb82018-01-20 23:32:30 -0800142
Austin Schuh17dd0892018-03-02 20:06:31 -0800143 # Now, get A and B in the relative coordinate system.
144 self.A_transformed_full = numpy.matrix(numpy.zeros((5, 5)))
145 self.B_transformed_full = numpy.matrix(numpy.zeros((5, 1)))
146 (self.A_transformed_full[0:4, 0:4],
147 self.A_transformed_full[0:4, 4]) = self.ContinuousToDiscrete(
148 abs_to_rel[0:4, 0:4] * self.A_continuous * rel_to_abs[0:4, 0:4],
149 abs_to_rel[0:4, 0:4] * self.B_continuous, self.dt)
150 self.B_transformed_full[4, 0] = 1.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800151
Austin Schuh17dd0892018-03-02 20:06:31 -0800152 # Pull out the components of the dynamics which don't include the spring
153 # output position so we can do partial state feedback on what we care about.
154 self.A_transformed = self.A_transformed_full[1:5, 1:5]
155 self.B_transformed = self.B_transformed_full[1:5, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800156
Austin Schuh17dd0892018-03-02 20:06:31 -0800157 glog.debug('A_transformed_full ' + str(self.A_transformed_full))
158 glog.debug('B_transformed_full ' + str(self.B_transformed_full))
159 glog.debug('A_transformed ' + str(self.A_transformed))
160 glog.debug('B_transformed ' + str(self.B_transformed))
Austin Schuhf173eb82018-01-20 23:32:30 -0800161
Austin Schuh17dd0892018-03-02 20:06:31 -0800162 # Now, let's design a controller in
163 # [output_velocity, spring_position, spring_velocity, delayed_voltage]
164 # space.
Austin Schuhf173eb82018-01-20 23:32:30 -0800165
Austin Schuh17dd0892018-03-02 20:06:31 -0800166 q_output_vel = 1.0
Austin Schuhede47322018-07-08 16:04:36 -0700167 q_spring_pos = 0.10
Austin Schuh17dd0892018-03-02 20:06:31 -0800168 q_spring_vel = 2.0
169 q_voltage = 1000000000000.0
170 self.Q_lqr = numpy.matrix(
171 numpy.diag([
172 1.0 / (q_output_vel**2.0), 1.0 / (q_spring_pos**2.0),
173 1.0 / (q_spring_vel**2.0), 1.0 / (q_voltage**2.0)
174 ]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800175
Austin Schuh17dd0892018-03-02 20:06:31 -0800176 self.R = numpy.matrix([[(1.0 / (12.0**2.0))]])
Austin Schuhf173eb82018-01-20 23:32:30 -0800177
Austin Schuh17dd0892018-03-02 20:06:31 -0800178 self.K_transformed = controls.dlqr(
179 self.A_transformed, self.B_transformed, self.Q_lqr, self.R)
Austin Schuhf173eb82018-01-20 23:32:30 -0800180
Austin Schuh17dd0892018-03-02 20:06:31 -0800181 # Write the controller back out in the absolute coordinate system.
182 self.K = numpy.hstack((numpy.matrix([[0.0]]),
183 self.K_transformed)) * abs_to_rel
Austin Schuhf173eb82018-01-20 23:32:30 -0800184
Austin Schuh17dd0892018-03-02 20:06:31 -0800185 controllability = controls.ctrb(self.A_transformed, self.B_transformed)
186 glog.debug('ctrb: ' + repr(numpy.linalg.matrix_rank(controllability)))
Austin Schuhf173eb82018-01-20 23:32:30 -0800187
Austin Schuh17dd0892018-03-02 20:06:31 -0800188 w, v = numpy.linalg.eig(
189 self.A_transformed - self.B_transformed * self.K_transformed)
190 glog.debug('Poles are %s, for %s', repr(w), self._name)
Austin Schuhf173eb82018-01-20 23:32:30 -0800191
Austin Schuh17dd0892018-03-02 20:06:31 -0800192 for i in range(len(w)):
193 glog.debug(' Pole %s -> %s', repr(w[i]), v[:, i])
Austin Schuhf173eb82018-01-20 23:32:30 -0800194
Austin Schuh17dd0892018-03-02 20:06:31 -0800195 glog.debug('K is %s', repr(self.K_transformed))
Austin Schuhf173eb82018-01-20 23:32:30 -0800196
Austin Schuh17dd0892018-03-02 20:06:31 -0800197 # Design a kalman filter here as well.
198 q_pos = 0.05
199 q_vel = 2.65
200 q_volts = 0.005
201 self.Q = numpy.matrix(
202 numpy.diag([(q_pos**2.0), (q_vel**2.0), (q_pos**2.0), (q_vel**2.0),
203 (q_volts**2.0)]))
Austin Schuhf173eb82018-01-20 23:32:30 -0800204
Austin Schuh17dd0892018-03-02 20:06:31 -0800205 r_nm = 0.025
206 self.R = numpy.matrix(numpy.diag([(r_nm**2.0), (r_nm**2.0)]))
207
208 glog.debug('Overall poles are %s, for %s',
209 repr(numpy.linalg.eig(self.A - self.B * self.K)[0]),
210 self._name)
211
212 self.KalmanGain, self.Q_steady = controls.kalman(
213 A=self.A, B=self.B, C=self.C, Q=self.Q, R=self.R)
214
215 self.InitializeState()
Austin Schuhf173eb82018-01-20 23:32:30 -0800216
217
218class ScenarioPlotter(object):
Austin Schuh17dd0892018-03-02 20:06:31 -0800219 def __init__(self):
220 # Various lists for graphing things.
221 self.t = []
222 self.x_motor = []
223 self.x_output = []
224 self.v = []
225 self.goal_v = []
226 self.a = []
227 self.spring = []
228 self.x_hat = []
229 self.u = []
Austin Schuhf173eb82018-01-20 23:32:30 -0800230
Austin Schuh17dd0892018-03-02 20:06:31 -0800231 def run_test(self,
232 intake,
233 iterations=400,
234 controller_intake=None,
235 observer_intake=None):
236 """Runs the intake plant with an initial condition and goal.
Austin Schuhf173eb82018-01-20 23:32:30 -0800237
238 Test for whether the goal has been reached and whether the separation
239 goes outside of the initial and goal values by more than
240 max_separation_error.
241
242 Prints out something for a failure of either condition and returns
243 False if tests fail.
244 Args:
245 intake: intake object to use.
246 iterations: Number of timesteps to run the model for.
247 controller_intake: Intake object to get K from, or None if we should
248 use intake.
249 observer_intake: Intake object to use for the observer, or None if we
250 should use the actual state.
251 """
252
Austin Schuh17dd0892018-03-02 20:06:31 -0800253 if controller_intake is None:
254 controller_intake = intake
Austin Schuhf173eb82018-01-20 23:32:30 -0800255
Austin Schuh17dd0892018-03-02 20:06:31 -0800256 vbat = 12.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800257
Austin Schuh17dd0892018-03-02 20:06:31 -0800258 if self.t:
259 initial_t = self.t[-1] + intake.dt
260 else:
261 initial_t = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800262
Austin Schuh17dd0892018-03-02 20:06:31 -0800263 # Delay U by 1 cycle in our simulation to make it more realistic.
264 last_U = numpy.matrix([[0.0]])
265 intake.Y = intake.C * intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800266
Austin Schuh17dd0892018-03-02 20:06:31 -0800267 for i in xrange(iterations):
268 X_hat = intake.X
Austin Schuhf173eb82018-01-20 23:32:30 -0800269
Austin Schuh17dd0892018-03-02 20:06:31 -0800270 if observer_intake is not None:
271 X_hat = observer_intake.X_hat
272 self.x_hat.append(observer_intake.X_hat[0, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800273
Austin Schuh17dd0892018-03-02 20:06:31 -0800274 goal_angle = 3.0
275 goal_velocity = numpy.clip((goal_angle - X_hat[0, 0]) * 6.0, -1.0,
276 1.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800277
Austin Schuh17dd0892018-03-02 20:06:31 -0800278 self.goal_v.append(goal_velocity)
Austin Schuhf173eb82018-01-20 23:32:30 -0800279
Austin Schuh17dd0892018-03-02 20:06:31 -0800280 # Nominal: 1.8 N at 0.25 m -> 0.45 N m
281 # 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 -0800282
Austin Schuh17dd0892018-03-02 20:06:31 -0800283 R = numpy.matrix([[0.0], [goal_velocity], [0.0], [goal_velocity],
284 [goal_velocity / (intake.G * intake.Kv)]])
285 U = controller_intake.K * (R - X_hat) + R[4, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800286
Austin Schuh17dd0892018-03-02 20:06:31 -0800287 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat) # * 0.0
Austin Schuhf173eb82018-01-20 23:32:30 -0800288
Austin Schuh17dd0892018-03-02 20:06:31 -0800289 self.x_output.append(intake.X[0, 0])
290 self.x_motor.append(intake.X[2, 0])
291 self.spring.append(intake.X[0, 0] - intake.X[2, 0])
Austin Schuhf173eb82018-01-20 23:32:30 -0800292
Austin Schuh17dd0892018-03-02 20:06:31 -0800293 if self.v:
294 last_v = self.v[-1]
295 else:
296 last_v = 0
Austin Schuhf173eb82018-01-20 23:32:30 -0800297
Austin Schuh17dd0892018-03-02 20:06:31 -0800298 self.v.append(intake.X[1, 0])
299 self.a.append((self.v[-1] - last_v) / intake.dt)
Austin Schuhf173eb82018-01-20 23:32:30 -0800300
Austin Schuh17dd0892018-03-02 20:06:31 -0800301 if observer_intake is not None:
302 observer_intake.Y = intake.Y
303 observer_intake.CorrectObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800304
Austin Schuh17dd0892018-03-02 20:06:31 -0800305 intake.Update(last_U + 0.0)
Austin Schuhf173eb82018-01-20 23:32:30 -0800306
Austin Schuh17dd0892018-03-02 20:06:31 -0800307 if observer_intake is not None:
308 observer_intake.PredictObserver(U)
Austin Schuhf173eb82018-01-20 23:32:30 -0800309
Austin Schuh17dd0892018-03-02 20:06:31 -0800310 self.t.append(initial_t + i * intake.dt)
311 self.u.append(U[0, 0])
312 last_U = U
Austin Schuhf173eb82018-01-20 23:32:30 -0800313
Austin Schuh17dd0892018-03-02 20:06:31 -0800314 def Plot(self):
315 pylab.subplot(3, 1, 1)
316 pylab.plot(self.t, self.x_output, label='x output')
317 pylab.plot(self.t, self.x_motor, label='x motor')
318 pylab.plot(self.t, self.x_hat, label='x_hat')
319 pylab.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800320
Austin Schuh17dd0892018-03-02 20:06:31 -0800321 spring_ax1 = pylab.subplot(3, 1, 2)
322 spring_ax1.plot(self.t, self.u, 'k', label='u')
323 spring_ax2 = spring_ax1.twinx()
324 spring_ax2.plot(self.t, self.spring, label='spring_angle')
325 spring_ax1.legend(loc=2)
326 spring_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800327
Austin Schuh17dd0892018-03-02 20:06:31 -0800328 accel_ax1 = pylab.subplot(3, 1, 3)
329 accel_ax1.plot(self.t, self.a, 'r', label='a')
Austin Schuhf173eb82018-01-20 23:32:30 -0800330
Austin Schuh17dd0892018-03-02 20:06:31 -0800331 accel_ax2 = accel_ax1.twinx()
332 accel_ax2.plot(self.t, self.v, label='v')
333 accel_ax2.plot(self.t, self.goal_v, label='goal_v')
334 accel_ax1.legend(loc=2)
335 accel_ax2.legend()
Austin Schuhf173eb82018-01-20 23:32:30 -0800336
Austin Schuh17dd0892018-03-02 20:06:31 -0800337 pylab.show()
Austin Schuhf173eb82018-01-20 23:32:30 -0800338
339
340def main(argv):
Austin Schuh17dd0892018-03-02 20:06:31 -0800341 scenario_plotter = ScenarioPlotter()
Austin Schuhf173eb82018-01-20 23:32:30 -0800342
Austin Schuh17dd0892018-03-02 20:06:31 -0800343 intake = Intake()
344 intake.X[0, 0] = 0.0
345 intake_controller = DelayedIntake()
346 observer_intake = DelayedIntake()
347 observer_intake.X_hat[0, 0] = intake.X[0, 0]
Austin Schuhf173eb82018-01-20 23:32:30 -0800348
Austin Schuh17dd0892018-03-02 20:06:31 -0800349 # Test moving the intake with constant separation.
350 scenario_plotter.run_test(
351 intake,
352 controller_intake=intake_controller,
353 observer_intake=observer_intake,
354 iterations=200)
Austin Schuhf173eb82018-01-20 23:32:30 -0800355
Austin Schuh17dd0892018-03-02 20:06:31 -0800356 if FLAGS.plot:
357 scenario_plotter.Plot()
Austin Schuhf173eb82018-01-20 23:32:30 -0800358
Austin Schuh17dd0892018-03-02 20:06:31 -0800359 # Write the generated constants out to a file.
360 if len(argv) != 5:
361 glog.fatal(
362 'Expected .h file name and .cc file name for intake and delayed_intake.'
363 )
364 else:
365 namespaces = ['y2018', 'control_loops', 'superstructure', 'intake']
366 intake = Intake('Intake')
367 loop_writer = control_loop.ControlLoopWriter(
368 'Intake', [intake], namespaces=namespaces)
369 loop_writer.AddConstant(
370 control_loop.Constant('kGearRatio', '%f', intake.G))
371 loop_writer.AddConstant(
372 control_loop.Constant('kMotorVelocityConstant', '%f', intake.Kv))
373 loop_writer.AddConstant(
374 control_loop.Constant('kFreeSpeed', '%f', intake.free_speed))
375 loop_writer.Write(argv[1], argv[2])
Austin Schuhf173eb82018-01-20 23:32:30 -0800376
Austin Schuh17dd0892018-03-02 20:06:31 -0800377 delayed_intake = DelayedIntake('DelayedIntake')
378 loop_writer = control_loop.ControlLoopWriter(
379 'DelayedIntake', [delayed_intake], namespaces=namespaces)
380 loop_writer.Write(argv[3], argv[4])
381
Sabina Davis3922dfa2018-02-10 23:10:05 -0800382
Michael Schuh10dd1e02018-01-20 13:19:44 -0800383if __name__ == '__main__':
Austin Schuh17dd0892018-03-02 20:06:31 -0800384 argv = FLAGS(sys.argv)
385 glog.init()
386 sys.exit(main(argv))