blob: 379bd0a008245d6a33d99d3c9b4a0fd739ffcd9b [file] [log] [blame]
Brian Silverman17f503e2015-08-02 18:17:18 -07001#!/usr/bin/python
2
Austin Schuh9d4aca82015-11-08 14:41:31 -08003from frc971.control_loops.python import control_loop
4import argparse
Brian Silverman17f503e2015-08-02 18:17:18 -07005import numpy
6import sys
7from matplotlib import pylab
8
9class SprungShooter(control_loop.ControlLoop):
Austin Schuh0e997732015-11-08 15:14:53 -080010 def __init__(self, name="RawSprungShooter", verbose=False):
Brian Silverman17f503e2015-08-02 18:17:18 -070011 super(SprungShooter, self).__init__(name)
12 # Stall Torque in N m
13 self.stall_torque = .4982
14 # Stall Current in Amps
15 self.stall_current = 85
16 # Free Speed in RPM
17 self.free_speed = 19300.0
18 # Free Current in Amps
19 self.free_current = 1.2
20 # Effective mass of the shooter in kg.
21 # This rough estimate should about include the effect of the masses
22 # of the gears. If this number is too low, the eigen values of self.A
23 # will start to become extremely small.
24 self.J = 200
25 # Resistance of the motor, divided by the number of motors.
26 self.R = 12.0 / self.stall_current / 2.0
27 # Motor velocity constant
28 self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
29 (12.0 - self.R * self.free_current))
30 # Torque constant
31 self.Kt = self.stall_torque / self.stall_current
32 # Spring constant for the springs, N/m
33 self.Ks = 2800.0
34 # Maximum extension distance (Distance from the 0 force point on the
35 # spring to the latch position.)
36 self.max_extension = 0.32385
37 # Gear ratio multiplied by radius of final sprocket.
38 self.G = 10.0 / 40.0 * 20.0 / 54.0 * 24.0 / 54.0 * 20.0 / 84.0 * 16.0 * (3.0 / 8.0) / (2.0 * numpy.pi) * 0.0254
39
40 # Control loop time step
Austin Schuhadf2cde2015-11-08 20:35:16 -080041 self.dt = 0.005
Brian Silverman17f503e2015-08-02 18:17:18 -070042
43 # State feedback matrices
44 self.A_continuous = numpy.matrix(
45 [[0, 1],
46 [-self.Ks / self.J,
47 -self.Kt / self.Kv / (self.J * self.G * self.G * self.R)]])
48 self.B_continuous = numpy.matrix(
49 [[0],
50 [self.Kt / (self.J * self.G * self.R)]])
51 self.C = numpy.matrix([[1, 0]])
52 self.D = numpy.matrix([[0]])
53
54 self.A, self.B = self.ContinuousToDiscrete(
55 self.A_continuous, self.B_continuous, self.dt)
56
57 self.PlaceControllerPoles([0.45, 0.45])
58
59 self.rpl = .05
60 self.ipl = 0.008
61 self.PlaceObserverPoles([self.rpl,
62 self.rpl])
63
64 self.U_max = numpy.matrix([[12.0]])
65 self.U_min = numpy.matrix([[-12.0]])
66
67 self.InitializeState()
68
69
70class Shooter(SprungShooter):
Austin Schuh0e997732015-11-08 15:14:53 -080071 def __init__(self, name="RawShooter", verbose=False):
Brian Silverman17f503e2015-08-02 18:17:18 -070072 super(Shooter, self).__init__(name)
73
74 # State feedback matrices
75 self.A_continuous = numpy.matrix(
76 [[0, 1],
77 [0, -self.Kt / self.Kv / (self.J * self.G * self.G * self.R)]])
78 self.B_continuous = numpy.matrix(
79 [[0],
80 [self.Kt / (self.J * self.G * self.R)]])
81
82 self.A, self.B = self.ContinuousToDiscrete(
83 self.A_continuous, self.B_continuous, self.dt)
84
85 self.PlaceControllerPoles([0.45, 0.45])
86
87 self.rpl = .05
88 self.ipl = 0.008
89 self.PlaceObserverPoles([self.rpl,
90 self.rpl])
91
92 self.U_max = numpy.matrix([[12.0]])
93 self.U_min = numpy.matrix([[-12.0]])
94
95 self.InitializeState()
96
97
98class SprungShooterDeltaU(SprungShooter):
Austin Schuh0e997732015-11-08 15:14:53 -080099 def __init__(self, name="SprungShooter", verbose=False):
Brian Silverman17f503e2015-08-02 18:17:18 -0700100 super(SprungShooterDeltaU, self).__init__(name)
101 A_unaugmented = self.A
102 B_unaugmented = self.B
103
104 self.A = numpy.matrix([[0.0, 0.0, 0.0],
105 [0.0, 0.0, 0.0],
106 [0.0, 0.0, 1.0]])
107 self.A[0:2, 0:2] = A_unaugmented
108 self.A[0:2, 2] = B_unaugmented
109
110 self.B = numpy.matrix([[0.0],
111 [0.0],
112 [1.0]])
113
114 self.C = numpy.matrix([[1.0, 0.0, 0.0]])
115 self.D = numpy.matrix([[0.0]])
116
117 self.PlaceControllerPoles([0.50, 0.35, 0.80])
118
Austin Schuh0e997732015-11-08 15:14:53 -0800119 if verbose:
120 print "K"
121 print self.K
122 print "Placed controller poles are"
123 print numpy.linalg.eig(self.A - self.B * self.K)[0]
Brian Silverman17f503e2015-08-02 18:17:18 -0700124
125 self.rpl = .05
126 self.ipl = 0.008
127 self.PlaceObserverPoles([self.rpl + 1j * self.ipl,
128 self.rpl - 1j * self.ipl, 0.90])
Austin Schuh0e997732015-11-08 15:14:53 -0800129 if verbose:
130 print "Placed observer poles are"
131 print numpy.linalg.eig(self.A - self.L * self.C)[0]
Brian Silverman17f503e2015-08-02 18:17:18 -0700132
133 self.U_max = numpy.matrix([[12.0]])
134 self.U_min = numpy.matrix([[-12.0]])
135
136 self.InitializeState()
137
138
139class ShooterDeltaU(Shooter):
Austin Schuh0e997732015-11-08 15:14:53 -0800140 def __init__(self, name="Shooter", verbose=False):
Brian Silverman17f503e2015-08-02 18:17:18 -0700141 super(ShooterDeltaU, self).__init__(name)
142 A_unaugmented = self.A
143 B_unaugmented = self.B
144
145 self.A = numpy.matrix([[0.0, 0.0, 0.0],
146 [0.0, 0.0, 0.0],
147 [0.0, 0.0, 1.0]])
148 self.A[0:2, 0:2] = A_unaugmented
149 self.A[0:2, 2] = B_unaugmented
150
151 self.B = numpy.matrix([[0.0],
152 [0.0],
153 [1.0]])
154
155 self.C = numpy.matrix([[1.0, 0.0, 0.0]])
156 self.D = numpy.matrix([[0.0]])
157
158 self.PlaceControllerPoles([0.55, 0.45, 0.80])
159
Austin Schuh0e997732015-11-08 15:14:53 -0800160 if verbose:
161 print "K"
162 print self.K
163 print "Placed controller poles are"
164 print numpy.linalg.eig(self.A - self.B * self.K)[0]
Brian Silverman17f503e2015-08-02 18:17:18 -0700165
166 self.rpl = .05
167 self.ipl = 0.008
168 self.PlaceObserverPoles([self.rpl + 1j * self.ipl,
169 self.rpl - 1j * self.ipl, 0.90])
Austin Schuh0e997732015-11-08 15:14:53 -0800170 if verbose:
171 print "Placed observer poles are"
172 print numpy.linalg.eig(self.A - self.L * self.C)[0]
Brian Silverman17f503e2015-08-02 18:17:18 -0700173
174 self.U_max = numpy.matrix([[12.0]])
175 self.U_min = numpy.matrix([[-12.0]])
176
177 self.InitializeState()
178
179
180def ClipDeltaU(shooter, old_voltage, delta_u):
181 old_u = old_voltage
182 new_u = numpy.clip(old_u + delta_u, shooter.U_min, shooter.U_max)
183 return new_u - old_u
184
185def main(argv):
Austin Schuh9d4aca82015-11-08 14:41:31 -0800186 parser = argparse.ArgumentParser(description='Calculate shooter.')
187 parser.add_argument('--plot', action='store_true', default=False, help='If true, plot')
188 parser.add_argument('shootercc')
189 parser.add_argument('shooterh')
190 parser.add_argument('unaugmented_shootercc')
191 parser.add_argument('unaugmented_shooterh')
192
193 args = parser.parse_args(argv[1:])
194
Brian Silverman17f503e2015-08-02 18:17:18 -0700195 # Simulate the response of the system to a goal.
Austin Schuh0e997732015-11-08 15:14:53 -0800196 sprung_shooter = SprungShooterDeltaU(verbose=args.plot)
197 raw_sprung_shooter = SprungShooter(verbose=args.plot)
Brian Silverman17f503e2015-08-02 18:17:18 -0700198 close_loop_x = []
199 close_loop_u = []
200 goal_position = -0.3
Austin Schuh9d4aca82015-11-08 14:41:31 -0800201 R = numpy.matrix([[goal_position],
202 [0.0],
203 [-sprung_shooter.A[1, 0] / sprung_shooter.A[1, 2] *
204 goal_position]])
Brian Silverman17f503e2015-08-02 18:17:18 -0700205 voltage = numpy.matrix([[0.0]])
206 for _ in xrange(500):
207 U = sprung_shooter.K * (R - sprung_shooter.X_hat)
208 U = ClipDeltaU(sprung_shooter, voltage, U)
209 sprung_shooter.Y = raw_sprung_shooter.Y + 0.01
210 sprung_shooter.UpdateObserver(U)
211 voltage += U;
212 raw_sprung_shooter.Update(voltage)
213 close_loop_x.append(raw_sprung_shooter.X[0, 0] * 10)
214 close_loop_u.append(voltage[0, 0])
215
Austin Schuh9d4aca82015-11-08 14:41:31 -0800216 if args.plot:
217 pylab.plot(range(500), close_loop_x)
218 pylab.plot(range(500), close_loop_u)
219 pylab.show()
Brian Silverman17f503e2015-08-02 18:17:18 -0700220
Austin Schuh0e997732015-11-08 15:14:53 -0800221 shooter = ShooterDeltaU(verbose=args.plot)
222 raw_shooter = Shooter(verbose=args.plot)
Brian Silverman17f503e2015-08-02 18:17:18 -0700223 close_loop_x = []
224 close_loop_u = []
225 goal_position = -0.3
226 R = numpy.matrix([[goal_position], [0.0], [-shooter.A[1, 0] / shooter.A[1, 2] * goal_position]])
227 voltage = numpy.matrix([[0.0]])
228 for _ in xrange(500):
229 U = shooter.K * (R - shooter.X_hat)
230 U = ClipDeltaU(shooter, voltage, U)
231 shooter.Y = raw_shooter.Y + 0.01
232 shooter.UpdateObserver(U)
233 voltage += U;
234 raw_shooter.Update(voltage)
235 close_loop_x.append(raw_shooter.X[0, 0] * 10)
236 close_loop_u.append(voltage[0, 0])
237
Austin Schuh9d4aca82015-11-08 14:41:31 -0800238 if args.plot:
239 pylab.plot(range(500), close_loop_x)
240 pylab.plot(range(500), close_loop_u)
241 pylab.show()
Brian Silverman17f503e2015-08-02 18:17:18 -0700242
243 # Write the generated constants out to a file.
Austin Schuh0e997732015-11-08 15:14:53 -0800244 unaug_sprung_shooter = SprungShooter("RawSprungShooter", verbose=args.plot)
245 unaug_shooter = Shooter("RawShooter", verbose=args.plot)
Austin Schuh9d4aca82015-11-08 14:41:31 -0800246 namespaces = ['y2014', 'control_loops', 'shooter']
247 unaug_loop_writer = control_loop.ControlLoopWriter("RawShooter",
248 [unaug_sprung_shooter,
249 unaug_shooter],
250 namespaces=namespaces)
251 unaug_loop_writer.Write(args.unaugmented_shooterh,
252 args.unaugmented_shootercc)
Brian Silverman17f503e2015-08-02 18:17:18 -0700253
Austin Schuh0e997732015-11-08 15:14:53 -0800254 sprung_shooter = SprungShooterDeltaU(verbose=args.plot)
255 shooter = ShooterDeltaU(verbose=args.plot)
Austin Schuh9d4aca82015-11-08 14:41:31 -0800256 loop_writer = control_loop.ControlLoopWriter("Shooter",
257 [sprung_shooter, shooter],
258 namespaces=namespaces)
Brian Silverman17f503e2015-08-02 18:17:18 -0700259
Austin Schuh9d4aca82015-11-08 14:41:31 -0800260 loop_writer.AddConstant(control_loop.Constant("kMaxExtension", "%f",
Brian Silverman17f503e2015-08-02 18:17:18 -0700261 sprung_shooter.max_extension))
Austin Schuh9d4aca82015-11-08 14:41:31 -0800262 loop_writer.AddConstant(control_loop.Constant("kSpringConstant", "%f",
Brian Silverman17f503e2015-08-02 18:17:18 -0700263 sprung_shooter.Ks))
Austin Schuh0e997732015-11-08 15:14:53 -0800264 loop_writer.AddConstant(control_loop.Constant("kDt", "%f",
265 sprung_shooter.dt))
Austin Schuh9d4aca82015-11-08 14:41:31 -0800266 loop_writer.Write(args.shooterh, args.shootercc)
Brian Silverman17f503e2015-08-02 18:17:18 -0700267
268if __name__ == '__main__':
269 sys.exit(main(sys.argv))