blob: 8ed62d6de986d08175960dfd6883032b77c15f6f [file] [log] [blame]
James Kuszmaulf254c1a2013-03-10 16:31:26 -07001#!/usr/bin/python
2
3import control_loop
Austin Schuha25a0412014-03-09 00:50:04 -08004import controls
James Kuszmaulf254c1a2013-03-10 16:31:26 -07005import numpy
6import sys
7from matplotlib import pylab
8
Austin Schuh8afe35a2013-10-27 10:59:15 -07009
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
Comran Morshed1c91be42015-02-11 21:16:01 +000031 self.dt = 0.005
Austin Schuh8afe35a2013-10-27 10:59:15 -070032
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])
Austin Schuh427b3702013-11-02 13:44:09 -070045 self.PlaceObserverPoles([0.01])
Austin Schuh8afe35a2013-10-27 10:59:15 -070046
47 self.U_max = numpy.matrix([[12.0]])
48 self.U_min = numpy.matrix([[-12.0]])
49
50 self.InitializeState()
51
52
James Kuszmaulf254c1a2013-03-10 16:31:26 -070053class Drivetrain(control_loop.ControlLoop):
Brian Silverman176303a2014-04-10 10:54:55 -070054 def __init__(self, name="Drivetrain", left_low=True, right_low=True):
55 super(Drivetrain, self).__init__(name)
James Kuszmaulf254c1a2013-03-10 16:31:26 -070056 # Stall Torque in N m
57 self.stall_torque = 2.42
58 # Stall Current in Amps
Brian Silverman4b36e2e2015-03-16 15:46:53 -070059 self.stall_current = 133.0
James Kuszmaulf254c1a2013-03-10 16:31:26 -070060 # 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.
Brian Silverman4b36e2e2015-03-16 15:46:53 -070066 self.J = 10
James Kuszmaulf254c1a2013-03-10 16:31:26 -070067 # Mass of the robot, in kg.
68 self.m = 68
69 # Radius of the robot, in meters (from last year).
Austin Schuh0b69d0c2015-03-15 16:38:45 -070070 self.rb = 0.9603 / 2.0
James Kuszmaulf254c1a2013-03-10 16:31:26 -070071 # Radius of the wheels, in meters.
Comran Morshed1c91be42015-02-11 21:16:01 +000072 self.r = .0515938
James Kuszmaulf254c1a2013-03-10 16:31:26 -070073 # Resistance of the motor, divided by the number of motors.
Brian Silverman4b36e2e2015-03-16 15:46:53 -070074 self.R = 12.0 / self.stall_current / 2
James Kuszmaulf254c1a2013-03-10 16:31:26 -070075 # 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
Comran Morshed1c91be42015-02-11 21:16:01 +000081 self.G_const = 28.0 / 50.0 * 20.0 / 64.0
82
83 self.G_low = self.G_const
84 self.G_high = self.G_const
85
Austin Schuhde4d7fe2013-10-08 22:22:45 -070086 if left_low:
87 self.Gl = self.G_low
88 else:
89 self.Gl = self.G_high
90 if right_low:
91 self.Gr = self.G_low
92 else:
93 self.Gr = self.G_high
Comran Morshed1c91be42015-02-11 21:16:01 +000094
James Kuszmaulf254c1a2013-03-10 16:31:26 -070095 # Control loop time step
Comran Morshed1c91be42015-02-11 21:16:01 +000096 self.dt = 0.005
97
James Kuszmaulf254c1a2013-03-10 16:31:26 -070098 # These describe the way that a given side of a robot will be influenced
99 # by the other side. Units of 1 / kg.
100 self.msp = 1.0 / self.m + self.rb * self.rb / self.J
101 self.msn = 1.0 / self.m - self.rb * self.rb / self.J
102 # The calculations which we will need for A and B.
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700103 self.tcl = -self.Kt / self.Kv / (self.Gl * self.Gl * self.R * self.r * self.r)
104 self.tcr = -self.Kt / self.Kv / (self.Gr * self.Gr * self.R * self.r * self.r)
105 self.mpl = self.Kt / (self.Gl * self.R * self.r)
106 self.mpr = self.Kt / (self.Gr * self.R * self.r)
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700107
108 # State feedback matrices
109 # X will be of the format
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700110 # [[positionl], [velocityl], [positionr], velocityr]]
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700111 self.A_continuous = numpy.matrix(
112 [[0, 1, 0, 0],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700113 [0, self.msp * self.tcl, 0, self.msn * self.tcr],
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700114 [0, 0, 0, 1],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700115 [0, self.msn * self.tcl, 0, self.msp * self.tcr]])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700116 self.B_continuous = numpy.matrix(
117 [[0, 0],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700118 [self.msp * self.mpl, self.msn * self.mpr],
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700119 [0, 0],
Austin Schuhde4d7fe2013-10-08 22:22:45 -0700120 [self.msn * self.mpl, self.msp * self.mpr]])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700121 self.C = numpy.matrix([[1, 0, 0, 0],
122 [0, 0, 1, 0]])
123 self.D = numpy.matrix([[0, 0],
124 [0, 0]])
125
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000126 #print "THE NUMBER I WANT" + str(numpy.linalg.inv(self.A_continuous) * -self.B_continuous * numpy.matrix([[12.0], [12.0]]))
Austin Schuh4352ac62013-03-19 06:23:16 +0000127 self.A, self.B = self.ContinuousToDiscrete(
128 self.A_continuous, self.B_continuous, self.dt)
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700129
130 # Poles from last year.
Austin Schuh4352ac62013-03-19 06:23:16 +0000131 self.hp = 0.65
132 self.lp = 0.83
Austin Schuha25a0412014-03-09 00:50:04 -0800133 self.PlaceControllerPoles([self.hp, self.lp, self.hp, self.lp])
134 print self.K
135 q_pos = 0.07
136 q_vel = 1.0
137 self.Q = numpy.matrix([[(1.0 / (q_pos ** 2.0)), 0.0, 0.0, 0.0],
138 [0.0, (1.0 / (q_vel ** 2.0)), 0.0, 0.0],
139 [0.0, 0.0, (1.0 / (q_pos ** 2.0)), 0.0],
140 [0.0, 0.0, 0.0, (1.0 / (q_vel ** 2.0))]])
141
142 self.R = numpy.matrix([[(1.0 / (12.0 ** 2.0)), 0.0],
143 [0.0, (1.0 / (12.0 ** 2.0))]])
144 self.K = controls.dlqr(self.A, self.B, self.Q, self.R)
145 print self.A
146 print self.B
147 print self.K
148 print numpy.linalg.eig(self.A - self.B * self.K)[0]
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700149
Brian Silverman38ea9bf2014-04-19 22:57:54 -0700150 self.hlp = 0.3
151 self.llp = 0.4
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700152 self.PlaceObserverPoles([self.hlp, self.hlp, self.llp, self.llp])
153
154 self.U_max = numpy.matrix([[12.0], [12.0]])
155 self.U_min = numpy.matrix([[-12.0], [-12.0]])
Austin Schuh4352ac62013-03-19 06:23:16 +0000156 self.InitializeState()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700157
158def main(argv):
159 # Simulate the response of the system to a step input.
160 drivetrain = Drivetrain()
161 simulated_left = []
162 simulated_right = []
163 for _ in xrange(100):
164 drivetrain.Update(numpy.matrix([[12.0], [12.0]]))
165 simulated_left.append(drivetrain.X[0, 0])
166 simulated_right.append(drivetrain.X[2, 0])
167
Austin Schuh4352ac62013-03-19 06:23:16 +0000168 #pylab.plot(range(100), simulated_left)
169 #pylab.plot(range(100), simulated_right)
170 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700171
172 # Simulate forwards motion.
173 drivetrain = Drivetrain()
174 close_loop_left = []
175 close_loop_right = []
176 R = numpy.matrix([[1.0], [0.0], [1.0], [0.0]])
177 for _ in xrange(100):
178 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
179 drivetrain.U_min, drivetrain.U_max)
180 drivetrain.UpdateObserver(U)
181 drivetrain.Update(U)
182 close_loop_left.append(drivetrain.X[0, 0])
183 close_loop_right.append(drivetrain.X[2, 0])
184
Austin Schuh4352ac62013-03-19 06:23:16 +0000185 #pylab.plot(range(100), close_loop_left)
186 #pylab.plot(range(100), close_loop_right)
187 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700188
189 # Try turning in place
190 drivetrain = Drivetrain()
191 close_loop_left = []
192 close_loop_right = []
193 R = numpy.matrix([[-1.0], [0.0], [1.0], [0.0]])
194 for _ in xrange(100):
195 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
196 drivetrain.U_min, drivetrain.U_max)
197 drivetrain.UpdateObserver(U)
198 drivetrain.Update(U)
199 close_loop_left.append(drivetrain.X[0, 0])
200 close_loop_right.append(drivetrain.X[2, 0])
201
Austin Schuh4352ac62013-03-19 06:23:16 +0000202 #pylab.plot(range(100), close_loop_left)
203 #pylab.plot(range(100), close_loop_right)
204 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700205
206 # Try turning just one side.
207 drivetrain = Drivetrain()
208 close_loop_left = []
209 close_loop_right = []
210 R = numpy.matrix([[0.0], [0.0], [1.0], [0.0]])
211 for _ in xrange(100):
212 U = numpy.clip(drivetrain.K * (R - drivetrain.X_hat),
213 drivetrain.U_min, drivetrain.U_max)
214 drivetrain.UpdateObserver(U)
215 drivetrain.Update(U)
216 close_loop_left.append(drivetrain.X[0, 0])
217 close_loop_right.append(drivetrain.X[2, 0])
218
Austin Schuh4352ac62013-03-19 06:23:16 +0000219 #pylab.plot(range(100), close_loop_left)
220 #pylab.plot(range(100), close_loop_right)
221 #pylab.show()
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700222
223 # Write the generated constants out to a file.
Austin Schuha25a0412014-03-09 00:50:04 -0800224 print "Output one"
Brian Silverman176303a2014-04-10 10:54:55 -0700225 drivetrain_low_low = Drivetrain(name="DrivetrainLowLow", left_low=True, right_low=True)
226 drivetrain_low_high = Drivetrain(name="DrivetrainLowHigh", left_low=True, right_low=False)
227 drivetrain_high_low = Drivetrain(name="DrivetrainHighLow", left_low=False, right_low=True)
228 drivetrain_high_high = Drivetrain(name="DrivetrainHighHigh", left_low=False, right_low=False)
Brian Silverman2c590c32013-11-04 18:08:54 -0800229
230 if len(argv) != 5:
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700231 print "Expected .h file name and .cc file name"
232 else:
Brian Silverman176303a2014-04-10 10:54:55 -0700233 dog_loop_writer = control_loop.ControlLoopWriter(
234 "Drivetrain", [drivetrain_low_low, drivetrain_low_high,
235 drivetrain_high_low, drivetrain_high_high])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700236 if argv[1][-3:] == '.cc':
Brian Silverman2c590c32013-11-04 18:08:54 -0800237 dog_loop_writer.Write(argv[2], argv[1])
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700238 else:
Brian Silverman2c590c32013-11-04 18:08:54 -0800239 dog_loop_writer.Write(argv[1], argv[2])
240
James Kuszmaulf254c1a2013-03-10 16:31:26 -0700241if __name__ == '__main__':
242 sys.exit(main(sys.argv))