blob: 6efecadaa1d3a5ff40933db3f446bab53523c934 [file] [log] [blame]
James Kuszmaulf7f5ec12013-11-01 17:58:58 -07001#!/usr/bin/python
2
3import numpy
4import sys
5from matplotlib import pylab
6import control_loop
James Kuszmaulb74c8112013-11-03 16:13:45 -08007import slycot
James Kuszmaulf7f5ec12013-11-01 17:58:58 -07008
9class Shooter(control_loop.ControlLoop):
10 def __init__(self):
11 super(Shooter, self).__init__("Shooter")
12 # Stall Torque in N m
13 self.stall_torque = 2.42211227883219
14 # Stall Current in Amps
15 self.stall_current = 133
16 # Free Speed in RPM
17 self.free_speed = 4650.0
18 # Free Current in Amps
19 self.free_current = 2.7
20 # Moment of inertia of the shooter wheel in kg m^2
21 self.J = 0.0032
22 # Resistance of the motor, divided by 2 to account for the 2 motors
23 self.R = 12.0 / self.stall_current
24 # Motor velocity constant
25 self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
26 (12.0 - self.R * self.free_current))
27 # Torque constant
28 self.Kt = self.stall_torque / self.stall_current
29 # Gear ratio
30 self.G = 40.0 / 34.0
31 # Control loop time step
32 self.dt = 0.01
33
34 # State feedback matrices
35 self.A_continuous = numpy.matrix(
36 [[0, 1],
37 [0, -self.Kt / self.Kv / (self.J * self.G * self.G * self.R)]])
38 self.B_continuous = numpy.matrix(
39 [[0],
40 [self.Kt / (self.J * self.G * self.R)]])
41 self.C = numpy.matrix([[1, 0]])
42 self.D = numpy.matrix([[0]])
43
James Kuszmaule78add72013-11-01 19:37:49 -070044 self.A, self.B = self.ContinuousToDiscrete(self.A_continuous, self.B_continuous,
45 self.dt)
46
James Kuszmaulb74c8112013-11-03 16:13:45 -080047 R_LQR = numpy.matrix([[1e-5]])
48 P = slycot.sb02od(2,1, self.A, self.B, self.C.T * self.C, R_LQR, 'D')[0]
49
50 self.K = numpy.linalg.inv(R_LQR + self.B.T * P * self.B) * self.B.T * P * self.A
51
52 print self.K
53
James Kuszmaule78add72013-11-01 19:37:49 -070054 self.InitializeState()
James Kuszmaulf7f5ec12013-11-01 17:58:58 -070055
James Kuszmaulb74c8112013-11-03 16:13:45 -080056# self.PlaceControllerPoles([.6, .981])
57# print self.K
James Kuszmaulf7f5ec12013-11-01 17:58:58 -070058
59 self.rpl = .45
60 self.ipl = 0.07
61 self.PlaceObserverPoles([self.rpl + 1j * self.ipl,
62 self.rpl - 1j * self.ipl])
63
64 self.U_max = numpy.matrix([[12.0]])
65 self.U_min = numpy.matrix([[-12.0]])
66
67
68def main(argv):
69 # Simulate the response of the system to a step input.
70 shooter_data = numpy.genfromtxt('shooter/shooter_data.csv', delimiter=',')
71 shooter = Shooter()
72 simulated_x = []
73 real_x = []
74 x_vel = []
75 initial_x = shooter_data[0, 2]
76 last_x = initial_x
77 for i in xrange(shooter_data.shape[0]):
78 shooter.Update(numpy.matrix([[shooter_data[i, 1]]]))
79 simulated_x.append(shooter.X[0, 0])
80 x_offset = shooter_data[i, 2] - initial_x
81 real_x.append(x_offset)
82 x_vel.append((shooter_data[i, 2] - last_x) * 100.0)
83 last_x = shooter_data[i, 2]
84
85 sim_delay = 1
James Kuszmaulb74c8112013-11-03 16:13:45 -080086# pylab.plot(range(sim_delay, shooter_data.shape[0] + sim_delay),
87# simulated_x, label='Simulation')
88# pylab.plot(range(shooter_data.shape[0]), real_x, label='Reality')
89# pylab.plot(range(shooter_data.shape[0]), x_vel, label='Velocity')
90# pylab.legend()
James Kuszmaule78add72013-11-01 19:37:49 -070091# pylab.show()
James Kuszmaulf7f5ec12013-11-01 17:58:58 -070092
93 # Simulate the closed loop response of the system to a step input.
94 shooter = Shooter()
95 close_loop_x = []
96 close_loop_U = []
97 velocity_goal = 300
98 R = numpy.matrix([[0.0], [velocity_goal]])
99 for _ in pylab.linspace(0,1.99,200):
100 # Iterate the position up.
101 R = numpy.matrix([[R[0, 0] + 10.5], [velocity_goal]])
102 # Prevents the position goal from going beyond what is necessary.
103 velocity_weight_scalar = 0.35
104 max_reference = (
105 (shooter.U_max[0, 0] - velocity_weight_scalar *
106 (velocity_goal - shooter.X_hat[1, 0]) * shooter.K[0, 1]) /
107 shooter.K[0, 0] +
108 shooter.X_hat[0, 0])
109 min_reference = (
110 (shooter.U_min[0, 0] - velocity_weight_scalar *
111 (velocity_goal - shooter.X_hat[1, 0]) * shooter.K[0, 1]) /
112 shooter.K[0, 0] +
113 shooter.X_hat[0, 0])
114 R[0, 0] = numpy.clip(R[0, 0], min_reference, max_reference)
115 U = numpy.clip(shooter.K * (R - shooter.X_hat),
116 shooter.U_min, shooter.U_max)
117 shooter.UpdateObserver(U)
118 shooter.Update(U)
119 close_loop_x.append(shooter.X[1, 0])
James Kuszmaulb74c8112013-11-03 16:13:45 -0800120 close_loop_U.append(U[0, 0] * 10)
James Kuszmaulf7f5ec12013-11-01 17:58:58 -0700121
122 #pylab.plotfile("shooter.csv", (0,1))
James Kuszmaulb74c8112013-11-03 16:13:45 -0800123 pylab.plot(pylab.linspace(0,1.99,200), close_loop_U)
James Kuszmaulf7f5ec12013-11-01 17:58:58 -0700124 #pylab.plotfile("shooter.csv", (0,2))
James Kuszmaulb74c8112013-11-03 16:13:45 -0800125 pylab.plot(pylab.linspace(0,1.99,200), close_loop_x)
126 pylab.show()
James Kuszmaulf7f5ec12013-11-01 17:58:58 -0700127
128 # Simulate spin down.
129 spin_down_x = [];
130 R = numpy.matrix([[50.0], [0.0]])
131 for _ in xrange(150):
132 U = 0
133 shooter.UpdateObserver(U)
134 shooter.Update(U)
135 spin_down_x.append(shooter.X[1, 0])
136
137 #pylab.plot(range(150), spin_down_x)
138 #pylab.show()
139
140 if len(argv) != 3:
141 print "Expected .h file name and .cc file name"
142 else:
143 loop_writer = control_loop.ControlLoopWriter("Shooter", [shooter])
144 if argv[1][-3:] == '.cc':
145 loop_writer.Write(argv[2], argv[1])
146 else:
147 loop_writer.Write(argv[1], argv[2])
148
149
150if __name__ == '__main__':
151 sys.exit(main(sys.argv))