blob: c39886aa22b7e4863f567077e997b1425c629a4c [file] [log] [blame]
James Kuszmaulf254c1a2013-03-10 16:31:26 -07001#!/usr/bin/python
2
3import control_loop
4import numpy
5import sys
6from matplotlib import pylab
7
Austin Schuh8afe35a2013-10-27 10:59:15 -07008
9class CIM(control_loop.ControlLoop):
10 def __init__(self):
11 super(CIM, self).__init__("CIM")
12 # Stall Torque in N m
13 self.stall_torque = 2.42
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 CIM in kg m^2
21 self.J = 0.0001
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 # Control loop time step
30 self.dt = 0.01
31
32 # State feedback matrices
33 self.A_continuous = numpy.matrix(
34 [[-self.Kt / self.Kv / (self.J * self.R)]])
35 self.B_continuous = numpy.matrix(
36 [[self.Kt / (self.J * self.R)]])
37 self.C = numpy.matrix([[1]])
38 self.D = numpy.matrix([[0]])
39
40 self.A, self.B = self.ContinuousToDiscrete(self.A_continuous,
41 self.B_continuous, self.dt)
42
43 self.PlaceControllerPoles([0.01])
Austin Schuh427b3702013-11-02 13:44:09 -070044 self.PlaceObserverPoles([0.01])
Austin Schuh8afe35a2013-10-27 10:59:15 -070045
46 self.U_max = numpy.matrix([[12.0]])
47 self.U_min = numpy.matrix([[-12.0]])
48
49 self.InitializeState()
50
51
James Kuszmaulf254c1a2013-03-10 16:31:26 -070052class Drivetrain(control_loop.ControlLoop):
Brian Silverman2c590c32013-11-04 18:08:54 -080053 def __init__(self, left_low=True, right_low=True, is_clutch=False):
54 super(Drivetrain, self).__init__(("Clutch" if is_clutch else "Dog" )+"Drivetrain")
James Kuszmaulf254c1a2013-03-10 16:31:26 -070055 # Stall Torque in N m
56 self.stall_torque = 2.42
57 # Stall Current in Amps
58 self.stall_current = 133
59 # Free Speed in RPM. Used number from last year.
60 self.free_speed = 4650.0
61 # Free Current in Amps
62 self.free_current = 2.7
63 # Moment of inertia of the drivetrain in kg m^2
64 # Just borrowed from last year.
Brian Silverman2c590c32013-11-04 18:08:54 -080065 if is_clutch:
66 self.J = 4.5
67 else:
68 self.J = 4.9
James Kuszmaulf254c1a2013-03-10 16:31:26 -070069 # Mass of the robot, in kg.
70 self.m = 68
71 # Radius of the robot, in meters (from last year).
72 self.rb = 0.617998644 / 2.0
73 # Radius of the wheels, in meters.
74 self.r = .04445
75 # Resistance of the motor, divided by the number of motors.
Austin Schuh8afe35a2013-10-27 10:59:15 -070076 self.R = (12.0 / self.stall_current / 4 + 0.03) / (0.93 ** 2.0)
James Kuszmaulf254c1a2013-03-10 16:31:26 -070077 # Motor velocity constant
78 self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
79 (12.0 - self.R * self.free_current))
80 # Torque constant
81 self.Kt = self.stall_torque / self.stall_current
82 # Gear ratios
Brian Silverman2c590c32013-11-04 18:08:54 -080083 if is_clutch:
84 self.G_low = 14.0 / 60.0 * 15.0 / 50.0
85 self.G_high = 30.0 / 44.0 * 15.0 / 50.0
86 else:
87 self.G_low = 16.0 / 60.0 * 17.0 / 50.0
88 self.G_high = 28.0 / 48.0 * 17.0 / 50.0
Austin Schuhde4d7fe2013-10-08 22:22:45 -070089 if left_low:
90 self.Gl = self.G_low
91 else:
92 self.Gl = self.G_high
93 if right_low:
94 self.Gr = self.G_low
95 else:
96 self.Gr = self.G_high
James Kuszmaulf254c1a2013-03-10 16:31:26 -070097 # Control loop time step
98 self.dt = 0.01
99
100 # These describe the way that a given side of a robot will be influenced
101 # by the other side. Units of 1 / kg.
102 self.msp = 1.0 / self.m + self.rb * self.rb / self.J
103 self.msn = 1.0 / self.m - self.rb * self.rb / self.J
104 # The calculations which we will need for A and B.
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700105 self.tcl = -self.Kt / self.Kv / (self.Gl * self.Gl * self.R * self.r * self.r)
106 self.tcr = -self.Kt / self.Kv / (self.Gr * self.Gr * self.R * self.r * self.r)
107 self.mpl = self.Kt / (self.Gl * self.R * self.r)
108 self.mpr = self.Kt / (self.Gr * self.R * self.r)
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700109
110 # State feedback matrices
111 # X will be of the format
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700112 # [[positionl], [velocityl], [positionr], velocityr]]
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700113 self.A_continuous = numpy.matrix(
114 [[0, 1, 0, 0],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700115 [0, self.msp * self.tcl, 0, self.msn * self.tcr],
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700116 [0, 0, 0, 1],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700117 [0, self.msn * self.tcl, 0, self.msp * self.tcr]])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700118 self.B_continuous = numpy.matrix(
119 [[0, 0],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700120 [self.msp * self.mpl, self.msn * self.mpr],
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700121 [0, 0],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700122 [self.msn * self.mpl, self.msp * self.mpr]])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700123 self.C = numpy.matrix([[1, 0, 0, 0],
124 [0, 0, 1, 0]])
125 self.D = numpy.matrix([[0, 0],
126 [0, 0]])
127
Austin Schuh4352ac62013-03-19 06:23:16 +0000128 self.A, self.B = self.ContinuousToDiscrete(
129 self.A_continuous, self.B_continuous, self.dt)
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700130
131 # Poles from last year.
Austin Schuh4352ac62013-03-19 06:23:16 +0000132 self.hp = 0.65
133 self.lp = 0.83
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700134 self.PlaceControllerPoles([self.hp, self.hp, self.lp, self.lp])
135
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700136 self.hlp = 0.07
137 self.llp = 0.09
138 self.PlaceObserverPoles([self.hlp, self.hlp, self.llp, self.llp])
139
140 self.U_max = numpy.matrix([[12.0], [12.0]])
141 self.U_min = numpy.matrix([[-12.0], [-12.0]])
Austin Schuh4352ac62013-03-19 06:23:16 +0000142 self.InitializeState()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700143
144def main(argv):
145 # Simulate the response of the system to a step input.
146 drivetrain = Drivetrain()
147 simulated_left = []
148 simulated_right = []
149 for _ in xrange(100):
150 drivetrain.Update(numpy.matrix([[12.0], [12.0]]))
151 simulated_left.append(drivetrain.X[0, 0])
152 simulated_right.append(drivetrain.X[2, 0])
153
Austin Schuh4352ac62013-03-19 06:23:16 +0000154 #pylab.plot(range(100), simulated_left)
155 #pylab.plot(range(100), simulated_right)
156 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700157
158 # Simulate forwards motion.
159 drivetrain = Drivetrain()
160 close_loop_left = []
161 close_loop_right = []
162 R = numpy.matrix([[1.0], [0.0], [1.0], [0.0]])
163 for _ in xrange(100):
164 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
165 drivetrain.U_min, drivetrain.U_max)
166 drivetrain.UpdateObserver(U)
167 drivetrain.Update(U)
168 close_loop_left.append(drivetrain.X[0, 0])
169 close_loop_right.append(drivetrain.X[2, 0])
170
Austin Schuh4352ac62013-03-19 06:23:16 +0000171 #pylab.plot(range(100), close_loop_left)
172 #pylab.plot(range(100), close_loop_right)
173 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700174
175 # Try turning in place
176 drivetrain = Drivetrain()
177 close_loop_left = []
178 close_loop_right = []
179 R = numpy.matrix([[-1.0], [0.0], [1.0], [0.0]])
180 for _ in xrange(100):
181 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
182 drivetrain.U_min, drivetrain.U_max)
183 drivetrain.UpdateObserver(U)
184 drivetrain.Update(U)
185 close_loop_left.append(drivetrain.X[0, 0])
186 close_loop_right.append(drivetrain.X[2, 0])
187
Austin Schuh4352ac62013-03-19 06:23:16 +0000188 #pylab.plot(range(100), close_loop_left)
189 #pylab.plot(range(100), close_loop_right)
190 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700191
192 # Try turning just one side.
193 drivetrain = Drivetrain()
194 close_loop_left = []
195 close_loop_right = []
196 R = numpy.matrix([[0.0], [0.0], [1.0], [0.0]])
197 for _ in xrange(100):
198 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
199 drivetrain.U_min, drivetrain.U_max)
200 drivetrain.UpdateObserver(U)
201 drivetrain.Update(U)
202 close_loop_left.append(drivetrain.X[0, 0])
203 close_loop_right.append(drivetrain.X[2, 0])
204
Austin Schuh4352ac62013-03-19 06:23:16 +0000205 #pylab.plot(range(100), close_loop_left)
206 #pylab.plot(range(100), close_loop_right)
207 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700208
209 # Write the generated constants out to a file.
Brian Silverman2c590c32013-11-04 18:08:54 -0800210 dog_drivetrain = Drivetrain(is_clutch=False)
211 clutch_drivetrain = Drivetrain(is_clutch=True)
212
213 if len(argv) != 5:
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700214 print "Expected .h file name and .cc file name"
215 else:
Brian Silverman2c590c32013-11-04 18:08:54 -0800216 dog_loop_writer = control_loop.ControlLoopWriter("DogDrivetrain", [dog_drivetrain])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700217 if argv[1][-3:] == '.cc':
Brian Silverman2c590c32013-11-04 18:08:54 -0800218 dog_loop_writer.Write(argv[2], argv[1])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700219 else:
Brian Silverman2c590c32013-11-04 18:08:54 -0800220 dog_loop_writer.Write(argv[1], argv[2])
221
222 clutch_loop_writer = control_loop.ControlLoopWriter("ClutchDrivetrain", [clutch_drivetrain])
223 if argv[3][-3:] == '.cc':
224 clutch_loop_writer.Write(argv[4], argv[3])
225 else:
226 clutch_loop_writer.Write(argv[3], argv[4])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700227
228if __name__ == '__main__':
229 sys.exit(main(sys.argv))