blob: 4ca50e9e0d893545b45c4c7a3521ced4880e3328 [file] [log] [blame]
Austin Schuhc8ca2442013-02-23 12:29:33 -08001#!/usr/bin/python
2
Austin Schuh3c542312013-02-24 01:53:50 -08003import control_loop
Austin Schuh0d9467a2014-02-15 22:36:45 -08004import controls
Austin Schuhfe6d37e2014-03-24 09:45:01 -07005import polytope
6import polydrivetrain
Austin Schuhc8ca2442013-02-23 12:29:33 -08007import numpy
Austin Schuhc8ca2442013-02-23 12:29:33 -08008import sys
Austin Schuh1a387962015-01-31 16:36:20 -08009import matplotlib
Austin Schuhc8ca2442013-02-23 12:29:33 -080010from matplotlib import pylab
Austin Schuhc8ca2442013-02-23 12:29:33 -080011
Austin Schuh3bb9a442014-02-02 16:01:45 -080012class Claw(control_loop.ControlLoop):
Austin Schuh1a387962015-01-31 16:36:20 -080013 def __init__(self, name="Claw", mass=None):
Austin Schuh3bb9a442014-02-02 16:01:45 -080014 super(Claw, self).__init__(name)
Austin Schuhc8ca2442013-02-23 12:29:33 -080015 # Stall Torque in N m
Austin Schuh1a387962015-01-31 16:36:20 -080016 self.stall_torque = 0.476
Austin Schuhc8ca2442013-02-23 12:29:33 -080017 # Stall Current in Amps
Austin Schuh1a387962015-01-31 16:36:20 -080018 self.stall_current = 80.730
James Kuszmaul92797402014-02-17 14:08:49 -080019 # Free Speed in RPM
Austin Schuh1a387962015-01-31 16:36:20 -080020 self.free_speed = 13906.0
Austin Schuh3c542312013-02-24 01:53:50 -080021 # Free Current in Amps
Austin Schuh1a387962015-01-31 16:36:20 -080022 self.free_current = 5.820
23 # Mass of the claw
24 if mass is None:
25 self.mass = 5.0
26 else:
27 self.mass = mass
James Kuszmaul3ac190a2014-03-26 20:11:04 -070028
Austin Schuhc8ca2442013-02-23 12:29:33 -080029 # Resistance of the motor
James Kuszmaul92797402014-02-17 14:08:49 -080030 self.R = 12.0 / self.stall_current
Austin Schuhc8ca2442013-02-23 12:29:33 -080031 # Motor velocity constant
Austin Schuh3c542312013-02-24 01:53:50 -080032 self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
Austin Schuh1a387962015-01-31 16:36:20 -080033 (12.0 - self.R * self.free_current))
Austin Schuhc8ca2442013-02-23 12:29:33 -080034 # Torque constant
35 self.Kt = self.stall_torque / self.stall_current
36 # Gear ratio
Austin Schuh1a387962015-01-31 16:36:20 -080037 self.G = (56.0 / 12.0) * (54.0 / 14.0) * (64.0 / 14.0) * (72.0 / 18.0)
38 # Claw length
39 self.r = 18 * 0.0254
Austin Schuhc8ca2442013-02-23 12:29:33 -080040
Austin Schuh1a387962015-01-31 16:36:20 -080041 self.J = self.r * self.mass
42
43 # Control loop time step
44 self.dt = 0.005
45
46 # State is [position, velocity]
47 # Input is [Voltage]
48
49 C1 = self.G * self.G * self.Kt / (self.R * self.J * self.Kv)
50 C2 = self.Kt * self.G / (self.J * self.R)
James Kuszmaule2afbe42014-02-17 22:29:59 -080051
Austin Schuhc8ca2442013-02-23 12:29:33 -080052 self.A_continuous = numpy.matrix(
James Kuszmaule2afbe42014-02-17 22:29:59 -080053 [[0, 1],
Austin Schuh1a387962015-01-31 16:36:20 -080054 [0, -C1]])
James Kuszmaule2afbe42014-02-17 22:29:59 -080055
Austin Schuh1a387962015-01-31 16:36:20 -080056 # Start with the unmodified input
Austin Schuhc8ca2442013-02-23 12:29:33 -080057 self.B_continuous = numpy.matrix(
James Kuszmaule2afbe42014-02-17 22:29:59 -080058 [[0],
Austin Schuh1a387962015-01-31 16:36:20 -080059 [C2]])
James Kuszmaule2afbe42014-02-17 22:29:59 -080060
Austin Schuh1a387962015-01-31 16:36:20 -080061 self.C = numpy.matrix([[1, 0]])
62 self.D = numpy.matrix([[0]])
Austin Schuhc8ca2442013-02-23 12:29:33 -080063
Austin Schuhc1f68892013-03-16 17:06:27 -070064 self.A, self.B = self.ContinuousToDiscrete(
65 self.A_continuous, self.B_continuous, self.dt)
Austin Schuhc8ca2442013-02-23 12:29:33 -080066
Austin Schuh0d9467a2014-02-15 22:36:45 -080067 controlability = controls.ctrb(self.A, self.B);
Austin Schuhc1f68892013-03-16 17:06:27 -070068
Austin Schuhbd947022015-03-01 00:10:01 -080069 print "Free speed is", self.free_speed * numpy.pi * 2.0 / 60.0 / self.G
70
71 q_pos = 0.15
72 q_vel = 2.5
Austin Schuh1a387962015-01-31 16:36:20 -080073 self.Q = numpy.matrix([[(1.0 / (q_pos ** 2.0)), 0.0],
74 [0.0, (1.0 / (q_vel ** 2.0))]])
75
76 self.R = numpy.matrix([[(1.0 / (12.0 ** 2.0))]])
77 self.K = controls.dlqr(self.A, self.B, self.Q, self.R)
Austin Schuh1a387962015-01-31 16:36:20 -080078
Austin Schuh8a436e82015-02-16 23:31:28 -080079 print 'K', self.K
80 print 'Poles are', numpy.linalg.eig(self.A - self.B * self.K)[0]
Austin Schuhc1f68892013-03-16 17:06:27 -070081
Austin Schuh8a436e82015-02-16 23:31:28 -080082 self.rpl = 0.30
83 self.ipl = 0.10
Austin Schuh1a387962015-01-31 16:36:20 -080084 self.PlaceObserverPoles([self.rpl + 1j * self.ipl,
85 self.rpl - 1j * self.ipl])
Austin Schuhc1f68892013-03-16 17:06:27 -070086
Austin Schuhbd947022015-03-01 00:10:01 -080087 print 'L is', self.L
88
Brian Silverman73c298d2015-03-30 10:30:12 -040089 q_pos = 0.05
90 q_vel = 2.65
Austin Schuhbd947022015-03-01 00:10:01 -080091 self.Q = numpy.matrix([[(q_pos ** 2.0), 0.0],
92 [0.0, (q_vel ** 2.0)]])
93
Brian Silverman73c298d2015-03-30 10:30:12 -040094 r_volts = 0.025
Austin Schuhbd947022015-03-01 00:10:01 -080095 self.R = numpy.matrix([[(r_volts ** 2.0)]])
96
97 self.KalmanGain, self.Q_steady = controls.kalman(
98 A=self.A, B=self.B, C=self.C, Q=self.Q, R=self.R)
99
100 print 'Kal', self.KalmanGain
101 self.L = self.A * self.KalmanGain
102 print 'KalL is', self.L
103
Austin Schuh1a387962015-01-31 16:36:20 -0800104 # The box formed by U_min and U_max must encompass all possible values,
105 # or else Austin's code gets angry.
106 self.U_max = numpy.matrix([[12.0]])
107 self.U_min = numpy.matrix([[-12.0]])
Austin Schuhc1f68892013-03-16 17:06:27 -0700108
109 self.InitializeState()
110
Austin Schuhfe6d37e2014-03-24 09:45:01 -0700111
Austin Schuh1a387962015-01-31 16:36:20 -0800112def run_test(claw, initial_X, goal, max_separation_error=0.01,
113 show_graph=True, iterations=200, controller_claw=None,
114 observer_claw=None):
115 """Runs the claw plant with an initial condition and goal.
Brian Silverman6dd2c532014-03-29 23:34:39 -0700116
Austin Schuh1a387962015-01-31 16:36:20 -0800117 The tests themselves are not terribly sophisticated; I just test for
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700118 whether the goal has been reached and whether the separation goes
Brian Silverman6dd2c532014-03-29 23:34:39 -0700119 outside of the initial and goal values by more than max_separation_error.
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700120 Prints out something for a failure of either condition and returns
121 False if tests fail.
122 Args:
123 claw: claw object to use.
124 initial_X: starting state.
125 goal: goal state.
126 show_graph: Whether or not to display a graph showing the changing
127 states and voltages.
Austin Schuh1a387962015-01-31 16:36:20 -0800128 iterations: Number of timesteps to run the model for.
129 controller_claw: claw object to get K from, or None if we should
130 use claw.
131 observer_claw: claw object to use for the observer, or None if we should
132 use the actual state.
133 """
Austin Schuhc8ca2442013-02-23 12:29:33 -0800134
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700135 claw.X = initial_X
136
Austin Schuh1a387962015-01-31 16:36:20 -0800137 if controller_claw is None:
138 controller_claw = claw
139
140 if observer_claw is not None:
141 observer_claw.X_hat = initial_X + 0.01
142 observer_claw.X_hat = initial_X
143
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700144 # Various lists for graphing things.
Austin Schuhcda86af2014-02-16 16:16:39 -0800145 t = []
Austin Schuh1a387962015-01-31 16:36:20 -0800146 x = []
147 v = []
148 x_hat = []
149 u = []
Austin Schuhc8ca2442013-02-23 12:29:33 -0800150
Austin Schuh1a387962015-01-31 16:36:20 -0800151 sep_plot_gain = 100.0
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700152
153 for i in xrange(iterations):
Austin Schuh1a387962015-01-31 16:36:20 -0800154 X_hat = claw.X
155 if observer_claw is not None:
156 X_hat = observer_claw.X_hat
157 x_hat.append(observer_claw.X_hat[0, 0])
158 U = controller_claw.K * (goal - X_hat)
159 U[0, 0] = numpy.clip(U[0, 0], -12, 12)
160 x.append(claw.X[0, 0])
161 v.append(claw.X[1, 0])
162 if observer_claw is not None:
163 observer_claw.PredictObserver(U)
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700164 claw.Update(U)
Austin Schuh1a387962015-01-31 16:36:20 -0800165 if observer_claw is not None:
166 observer_claw.Y = claw.Y
167 observer_claw.CorrectObserver(U)
Brian Silvermanb087c0a2014-03-30 12:59:52 -0700168
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700169 t.append(i * claw.dt)
Austin Schuh1a387962015-01-31 16:36:20 -0800170 u.append(U[0, 0])
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700171
172 if show_graph:
Austin Schuh1a387962015-01-31 16:36:20 -0800173 pylab.subplot(2, 1, 1)
174 pylab.plot(t, x, label='x')
175 if observer_claw is not None:
176 pylab.plot(t, x_hat, label='x_hat')
177 pylab.legend()
178
179 pylab.subplot(2, 1, 2)
180 pylab.plot(t, u, label='u')
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700181 pylab.legend()
182 pylab.show()
183
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700184
185def main(argv):
Austin Schuhbd947022015-03-01 00:10:01 -0800186 loaded_mass = 0
Austin Schuh1a387962015-01-31 16:36:20 -0800187 #loaded_mass = 0
Austin Schuhbd947022015-03-01 00:10:01 -0800188 claw = Claw(mass=4 + loaded_mass)
189 claw_controller = Claw(mass=5 + 0)
190 observer_claw = Claw(mass=5 + 0)
Austin Schuh1a387962015-01-31 16:36:20 -0800191 #observer_claw = None
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700192
193 # Test moving the claw with constant separation.
Austin Schuh1a387962015-01-31 16:36:20 -0800194 initial_X = numpy.matrix([[0.0], [0.0]])
195 R = numpy.matrix([[1.0], [0.0]])
196 run_test(claw, initial_X, R, controller_claw=claw_controller,
197 observer_claw=observer_claw)
Brian Silvermanf05948b2014-03-30 00:24:36 -0700198
Austin Schuh3c542312013-02-24 01:53:50 -0800199 # Write the generated constants out to a file.
Austin Schuhcda86af2014-02-16 16:16:39 -0800200 if len(argv) != 3:
201 print "Expected .h file name and .cc file name for the claw."
Austin Schuhc8ca2442013-02-23 12:29:33 -0800202 else:
Austin Schuhcda86af2014-02-16 16:16:39 -0800203 claw = Claw("Claw")
204 loop_writer = control_loop.ControlLoopWriter("Claw", [claw])
Austin Schuh683a0d02013-03-02 01:51:31 -0800205 if argv[1][-3:] == '.cc':
Austin Schuhcda86af2014-02-16 16:16:39 -0800206 loop_writer.Write(argv[2], argv[1])
Austin Schuh683a0d02013-03-02 01:51:31 -0800207 else:
Austin Schuhcda86af2014-02-16 16:16:39 -0800208 loop_writer.Write(argv[1], argv[2])
Austin Schuhc8ca2442013-02-23 12:29:33 -0800209
210if __name__ == '__main__':
211 sys.exit(main(sys.argv))