blob: ac05a5756c3818f8445adb1368376b2473be0f8f [file] [log] [blame]
Brian Silverman17f503e2015-08-02 18:17:18 -07001#!/usr/bin/python
2
3import control_loop
4import controls
5import numpy
6import sys
7from matplotlib import pylab
8
9
10class CIM(control_loop.ControlLoop):
11 def __init__(self):
12 super(CIM, self).__init__("CIM")
13 # Stall Torque in N m
14 self.stall_torque = 2.42
15 # Stall Current in Amps
16 self.stall_current = 133
17 # Free Speed in RPM
18 self.free_speed = 4650.0
19 # Free Current in Amps
20 self.free_current = 2.7
21 # Moment of inertia of the CIM in kg m^2
22 self.J = 0.0001
23 # Resistance of the motor, divided by 2 to account for the 2 motors
24 self.R = 12.0 / self.stall_current
25 # Motor velocity constant
26 self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
27 (12.0 - self.R * self.free_current))
28 # Torque constant
29 self.Kt = self.stall_torque / self.stall_current
30 # Control loop time step
31 self.dt = 0.005
32
33 # State feedback matrices
34 self.A_continuous = numpy.matrix(
35 [[-self.Kt / self.Kv / (self.J * self.R)]])
36 self.B_continuous = numpy.matrix(
37 [[self.Kt / (self.J * self.R)]])
38 self.C = numpy.matrix([[1]])
39 self.D = numpy.matrix([[0]])
40
41 self.A, self.B = self.ContinuousToDiscrete(self.A_continuous,
42 self.B_continuous, self.dt)
43
44 self.PlaceControllerPoles([0.01])
45 self.PlaceObserverPoles([0.01])
46
47 self.U_max = numpy.matrix([[12.0]])
48 self.U_min = numpy.matrix([[-12.0]])
49
50 self.InitializeState()
51
52
53class Drivetrain(control_loop.ControlLoop):
54 def __init__(self, name="Drivetrain", left_low=True, right_low=True):
55 super(Drivetrain, self).__init__(name)
56 # Stall Torque in N m
57 self.stall_torque = 2.42
58 # Stall Current in Amps
59 self.stall_current = 133.0
60 # Free Speed in RPM. Used number from last year.
61 self.free_speed = 4650.0
62 # Free Current in Amps
63 self.free_current = 2.7
64 # Moment of inertia of the drivetrain in kg m^2
65 # Just borrowed from last year.
66 self.J = 4.5
67 # Mass of the robot, in kg.
68 self.m = 68
69 # Radius of the robot, in meters (from last year).
70 self.rb = 0.617998644 / 2.0
71 # Radius of the wheels, in meters.
72 self.r = .04445
73 # Resistance of the motor, divided by the number of motors.
74 self.R = 12.0 / self.stall_current / 4
75 # Motor velocity constant
76 self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
77 (12.0 - self.R * self.free_current))
78 # Torque constant
79 self.Kt = self.stall_torque / self.stall_current
80 # Gear ratios
81 self.G_low = 18.0 / 60.0 * 18.0 / 50.0
82 self.G_high = 28.0 / 50.0 * 18.0 / 50.0
83 if left_low:
84 self.Gl = self.G_low
85 else:
86 self.Gl = self.G_high
87 if right_low:
88 self.Gr = self.G_low
89 else:
90 self.Gr = self.G_high
91
92 # Control loop time step
93 self.dt = 0.005
94
95 # These describe the way that a given side of a robot will be influenced
96 # by the other side. Units of 1 / kg.
97 self.msp = 1.0 / self.m + self.rb * self.rb / self.J
98 self.msn = 1.0 / self.m - self.rb * self.rb / self.J
99 # The calculations which we will need for A and B.
100 self.tcl = -self.Kt / self.Kv / (self.Gl * self.Gl * self.R * self.r * self.r)
101 self.tcr = -self.Kt / self.Kv / (self.Gr * self.Gr * self.R * self.r * self.r)
102 self.mpl = self.Kt / (self.Gl * self.R * self.r)
103 self.mpr = self.Kt / (self.Gr * self.R * self.r)
104
105 # State feedback matrices
106 # X will be of the format
107 # [[positionl], [velocityl], [positionr], velocityr]]
108 self.A_continuous = numpy.matrix(
109 [[0, 1, 0, 0],
110 [0, self.msp * self.tcl, 0, self.msn * self.tcr],
111 [0, 0, 0, 1],
112 [0, self.msn * self.tcl, 0, self.msp * self.tcr]])
113 self.B_continuous = numpy.matrix(
114 [[0, 0],
115 [self.msp * self.mpl, self.msn * self.mpr],
116 [0, 0],
117 [self.msn * self.mpl, self.msp * self.mpr]])
118 self.C = numpy.matrix([[1, 0, 0, 0],
119 [0, 0, 1, 0]])
120 self.D = numpy.matrix([[0, 0],
121 [0, 0]])
122
123 #print "THE NUMBER I WANT" + str(numpy.linalg.inv(self.A_continuous) * -self.B_continuous * numpy.matrix([[12.0], [12.0]]))
124 self.A, self.B = self.ContinuousToDiscrete(
125 self.A_continuous, self.B_continuous, self.dt)
126
127 # Poles from last year.
128 self.hp = 0.65
129 self.lp = 0.83
130 self.PlaceControllerPoles([self.hp, self.lp, self.hp, self.lp])
131 print self.K
132 q_pos = 0.07
133 q_vel = 1.0
134 self.Q = numpy.matrix([[(1.0 / (q_pos ** 2.0)), 0.0, 0.0, 0.0],
135 [0.0, (1.0 / (q_vel ** 2.0)), 0.0, 0.0],
136 [0.0, 0.0, (1.0 / (q_pos ** 2.0)), 0.0],
137 [0.0, 0.0, 0.0, (1.0 / (q_vel ** 2.0))]])
138
139 self.R = numpy.matrix([[(1.0 / (12.0 ** 2.0)), 0.0],
140 [0.0, (1.0 / (12.0 ** 2.0))]])
141 self.K = controls.dlqr(self.A, self.B, self.Q, self.R)
142 print self.A
143 print self.B
144 print self.K
145 print numpy.linalg.eig(self.A - self.B * self.K)[0]
146
147 self.hlp = 0.3
148 self.llp = 0.4
149 self.PlaceObserverPoles([self.hlp, self.hlp, self.llp, self.llp])
150
151 self.U_max = numpy.matrix([[12.0], [12.0]])
152 self.U_min = numpy.matrix([[-12.0], [-12.0]])
153 self.InitializeState()
154
155def main(argv):
156 # Simulate the response of the system to a step input.
157 drivetrain = Drivetrain()
158 simulated_left = []
159 simulated_right = []
160 for _ in xrange(100):
161 drivetrain.Update(numpy.matrix([[12.0], [12.0]]))
162 simulated_left.append(drivetrain.X[0, 0])
163 simulated_right.append(drivetrain.X[2, 0])
164
165 #pylab.plot(range(100), simulated_left)
166 #pylab.plot(range(100), simulated_right)
167 #pylab.show()
168
169 # Simulate forwards motion.
170 drivetrain = Drivetrain()
171 close_loop_left = []
172 close_loop_right = []
173 R = numpy.matrix([[1.0], [0.0], [1.0], [0.0]])
174 for _ in xrange(100):
175 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
176 drivetrain.U_min, drivetrain.U_max)
177 drivetrain.UpdateObserver(U)
178 drivetrain.Update(U)
179 close_loop_left.append(drivetrain.X[0, 0])
180 close_loop_right.append(drivetrain.X[2, 0])
181
182 #pylab.plot(range(100), close_loop_left)
183 #pylab.plot(range(100), close_loop_right)
184 #pylab.show()
185
186 # Try turning in place
187 drivetrain = Drivetrain()
188 close_loop_left = []
189 close_loop_right = []
190 R = numpy.matrix([[-1.0], [0.0], [1.0], [0.0]])
191 for _ in xrange(100):
192 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
193 drivetrain.U_min, drivetrain.U_max)
194 drivetrain.UpdateObserver(U)
195 drivetrain.Update(U)
196 close_loop_left.append(drivetrain.X[0, 0])
197 close_loop_right.append(drivetrain.X[2, 0])
198
199 #pylab.plot(range(100), close_loop_left)
200 #pylab.plot(range(100), close_loop_right)
201 #pylab.show()
202
203 # Try turning just one side.
204 drivetrain = Drivetrain()
205 close_loop_left = []
206 close_loop_right = []
207 R = numpy.matrix([[0.0], [0.0], [1.0], [0.0]])
208 for _ in xrange(100):
209 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
210 drivetrain.U_min, drivetrain.U_max)
211 drivetrain.UpdateObserver(U)
212 drivetrain.Update(U)
213 close_loop_left.append(drivetrain.X[0, 0])
214 close_loop_right.append(drivetrain.X[2, 0])
215
216 #pylab.plot(range(100), close_loop_left)
217 #pylab.plot(range(100), close_loop_right)
218 #pylab.show()
219
220 # Write the generated constants out to a file.
221 print "Output one"
222 drivetrain_low_low = Drivetrain(name="DrivetrainLowLow", left_low=True, right_low=True)
223 drivetrain_low_high = Drivetrain(name="DrivetrainLowHigh", left_low=True, right_low=False)
224 drivetrain_high_low = Drivetrain(name="DrivetrainHighLow", left_low=False, right_low=True)
225 drivetrain_high_high = Drivetrain(name="DrivetrainHighHigh", left_low=False, right_low=False)
226
227 if len(argv) != 5:
228 print "Expected .h file name and .cc file name"
229 else:
230 dog_loop_writer = control_loop.ControlLoopWriter(
231 "Drivetrain", [drivetrain_low_low, drivetrain_low_high,
232 drivetrain_high_low, drivetrain_high_high])
233 if argv[1][-3:] == '.cc':
234 dog_loop_writer.Write(argv[2], argv[1])
235 else:
236 dog_loop_writer.Write(argv[1], argv[2])
237
238if __name__ == '__main__':
239 sys.exit(main(sys.argv))