blob: eceb2d29833a6139779de0871644f5f2257c7967 [file] [log] [blame]
Austin Schuhac61c882022-02-23 17:22:22 -08001from frc971.control_loops.python import angular_system
Austin Schuh82162452022-02-07 22:01:45 -08002from frc971.control_loops.python import control_loop
3from frc971.control_loops.python import controls
Austin Schuhac61c882022-02-23 17:22:22 -08004from aos.util.trapezoid_profile import TrapezoidProfile
Austin Schuh82162452022-02-07 22:01:45 -08005import numpy
6from matplotlib import pylab
7
8import gflags
9import glog
10
Austin Schuhac61c882022-02-23 17:22:22 -080011CatapultParams = angular_system.AngularSystemParams
Austin Schuh82162452022-02-07 22:01:45 -080012
13
Austin Schuhac61c882022-02-23 17:22:22 -080014# TODO(austin): This is mostly the same as angular_system. Can we either wrap an angular_system or assign it?
15class Catapult(angular_system.AngularSystem):
Ravago Jones5127ccc2022-07-31 16:32:45 -070016
Austin Schuh82162452022-02-07 22:01:45 -080017 def __init__(self, params, name="Catapult"):
Austin Schuhac61c882022-02-23 17:22:22 -080018 super(Catapult, self).__init__(params, name)
Austin Schuhb39f4522022-03-27 13:29:42 -070019 # Signal that we have a 2 cycle output delay to compensate for in
Austin Schuhac61c882022-02-23 17:22:22 -080020 # our observer.
Austin Schuhb39f4522022-03-27 13:29:42 -070021 self.delayed_u = 2
Austin Schuh82162452022-02-07 22:01:45 -080022
23 self.InitializeState()
24
25
Austin Schuhac61c882022-02-23 17:22:22 -080026class IntegralCatapult(angular_system.IntegralAngularSystem):
Ravago Jones5127ccc2022-07-31 16:32:45 -070027
Austin Schuh82162452022-02-07 22:01:45 -080028 def __init__(self, params, name="IntegralCatapult"):
29 super(IntegralCatapult, self).__init__(params, name=name)
Austin Schuhb39f4522022-03-27 13:29:42 -070030 # Signal that we have a 2 cycle output delay to compensate for in
Austin Schuhac61c882022-02-23 17:22:22 -080031 # our observer.
Austin Schuhb39f4522022-03-27 13:29:42 -070032 self.delayed_u = 2
Austin Schuh82162452022-02-07 22:01:45 -080033
34 self.InitializeState()
35
36
37def MaxSpeed(params, U, final_position):
38 """Runs the catapult plant with an initial condition and goal.
39
40 Args:
41 catapult: Catapult object to use.
42 goal: goal state.
43 iterations: Number of timesteps to run the model for.
44 controller_catapult: Catapult object to get K from, or None if we should
45 use catapult.
46 observer_catapult: Catapult object to use for the observer, or None if we
47 should use the actual state.
48 """
49
50 # Various lists for graphing things.
51 catapult = Catapult(params, params.name)
52 controller_catapult = IntegralCatapult(params, params.name)
53 observer_catapult = IntegralCatapult(params, params.name)
54 vbat = 12.0
55
56 while True:
57 X_hat = catapult.X
58 if catapult.X[0, 0] > final_position:
Austin Schuhac61c882022-02-23 17:22:22 -080059 return catapult.X[1, 0] * params.radius
Austin Schuh82162452022-02-07 22:01:45 -080060
61 if observer_catapult is not None:
62 X_hat = observer_catapult.X_hat
63
64 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat)
65
66 if observer_catapult is not None:
67 observer_catapult.Y = catapult.Y
Austin Schuhac61c882022-02-23 17:22:22 -080068 observer_catapult.CorrectObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -080069
70 applied_U = U.copy()
71 catapult.Update(applied_U)
72
73 if observer_catapult is not None:
Austin Schuhac61c882022-02-23 17:22:22 -080074 observer_catapult.PredictObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -080075
76
77def PlotShot(params, U, final_position):
78 """Runs the catapult plant with an initial condition and goal.
79
80 Args:
81 catapult: Catapult object to use.
82 goal: goal state.
83 iterations: Number of timesteps to run the model for.
84 controller_catapult: Catapult object to get K from, or None if we should
85 use catapult.
86 observer_catapult: Catapult object to use for the observer, or None if we
87 should use the actual state.
88 """
89
90 # Various lists for graphing things.
91 t = []
92 x = []
93 x_hat = []
94 v = []
95 w_hat = []
96 v_hat = []
97 a = []
98 u = []
99 offset = []
100
101 catapult = Catapult(params, params.name)
102 controller_catapult = IntegralCatapult(params, params.name)
103 observer_catapult = IntegralCatapult(params, params.name)
104 vbat = 12.0
105
106 if t:
107 initial_t = t[-1] + catapult.dt
108 else:
109 initial_t = 0
110
111 for i in range(10000):
112 X_hat = catapult.X
113 if catapult.X[0, 0] > final_position:
114 break
115
116 if observer_catapult is not None:
117 X_hat = observer_catapult.X_hat
118 x_hat.append(observer_catapult.X_hat[0, 0])
119 w_hat.append(observer_catapult.X_hat[1, 0])
Austin Schuhac61c882022-02-23 17:22:22 -0800120 v_hat.append(observer_catapult.X_hat[1, 0] * params.radius)
Austin Schuh82162452022-02-07 22:01:45 -0800121
122 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat)
123 x.append(catapult.X[0, 0])
124
125 if v:
126 last_v = v[-1]
127 else:
128 last_v = 0
129
130 v.append(catapult.X[1, 0])
131 a.append((v[-1] - last_v) / catapult.dt)
132
133 if observer_catapult is not None:
134 observer_catapult.Y = catapult.Y
Austin Schuhac61c882022-02-23 17:22:22 -0800135 observer_catapult.CorrectObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -0800136 offset.append(observer_catapult.X_hat[2, 0])
137
138 catapult.Update(U)
139
140 if observer_catapult is not None:
Austin Schuhac61c882022-02-23 17:22:22 -0800141 observer_catapult.PredictObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -0800142
143 t.append(initial_t + i * catapult.dt)
144 u.append(U[0, 0])
145
146 pylab.subplot(3, 1, 1)
147 pylab.plot(t, v, label='v')
148 pylab.plot(t, x_hat, label='x_hat')
149 pylab.plot(t, v, label='v')
150 pylab.plot(t, v_hat, label='v_hat')
151 pylab.plot(t, w_hat, label='w_hat')
152 pylab.legend()
153
154 pylab.subplot(3, 1, 2)
155 pylab.plot(t, u, label='u')
156 pylab.plot(t, offset, label='voltage_offset')
157 pylab.legend()
158
159 pylab.subplot(3, 1, 3)
160 pylab.plot(t, a, label='a')
161 pylab.legend()
162
163 pylab.show()
Austin Schuh2e28d872022-02-19 18:25:57 -0800164
Austin Schuhac61c882022-02-23 17:22:22 -0800165
166RunTest = angular_system.RunTest
167
168
169def PlotStep(params, R, plant_params=None):
170 """Plots a step move to the goal.
171
172 Args:
173 params: CatapultParams for the controller and observer
174 plant_params: CatapultParams for the plant. Defaults to params if
175 plant_params is None.
176 R: numpy.matrix(2, 1), the goal"""
177 plant = Catapult(plant_params or params, params.name)
178 controller = IntegralCatapult(params, params.name)
179 observer = IntegralCatapult(params, params.name)
180
181 # Test moving the system.
182 initial_X = numpy.matrix([[0.0], [0.0]])
183 augmented_R = numpy.matrix(numpy.zeros((3, 1)))
184 augmented_R[0:2, :] = R
185 RunTest(plant,
186 end_goal=augmented_R,
187 controller=controller,
188 observer=observer,
189 duration=2.0,
190 use_profile=False,
191 kick_time=1.0,
192 kick_magnitude=0.0)
193
194
195def PlotKick(params, R, plant_params=None):
196 """Plots a step motion with a kick at 1.0 seconds.
197
198 Args:
199 params: CatapultParams for the controller and observer
200 plant_params: CatapultParams for the plant. Defaults to params if
201 plant_params is None.
202 R: numpy.matrix(2, 1), the goal"""
203 plant = Catapult(plant_params or params, params.name)
204 controller = IntegralCatapult(params, params.name)
205 observer = IntegralCatapult(params, params.name)
206
207 # Test moving the system.
208 initial_X = numpy.matrix([[0.0], [0.0]])
209 augmented_R = numpy.matrix(numpy.zeros((3, 1)))
210 augmented_R[0:2, :] = R
211 RunTest(plant,
212 end_goal=augmented_R,
213 controller=controller,
214 observer=observer,
215 duration=2.0,
216 use_profile=False,
217 kick_time=1.0,
218 kick_magnitude=2.0)
219
220
221def PlotMotion(params,
222 R,
223 max_velocity=10.0,
224 max_acceleration=70.0,
225 plant_params=None):
226 """Plots a trapezoidal motion.
227
228 Args:
229 params: CatapultParams for the controller and observer
230 plant_params: CatapultParams for the plant. Defaults to params if
231 plant_params is None.
232 R: numpy.matrix(2, 1), the goal,
233 max_velocity: float, The max velocity of the profile.
234 max_acceleration: float, The max acceleration of the profile.
235 """
236 plant = Catapult(plant_params or params, params.name)
237 controller = IntegralCatapult(params, params.name)
238 observer = IntegralCatapult(params, params.name)
239
240 # Test moving the system.
241 initial_X = numpy.matrix([[0.0], [0.0]])
242 augmented_R = numpy.matrix(numpy.zeros((3, 1)))
243 augmented_R[0:2, :] = R
244 RunTest(plant,
245 end_goal=augmented_R,
246 controller=controller,
247 observer=observer,
248 duration=2.0,
249 use_profile=True,
250 max_velocity=max_velocity,
251 max_acceleration=max_acceleration)
252
253
Austin Schuh2e28d872022-02-19 18:25:57 -0800254def WriteCatapult(params, plant_files, controller_files, year_namespaces):
255 """Writes out the constants for a catapult to a file.
256
257 Args:
258 params: list of CatapultParams or CatapultParams, the
259 parameters defining the system.
260 plant_files: list of strings, the cc and h files for the plant.
261 controller_files: list of strings, the cc and h files for the integral
262 controller.
263 year_namespaces: list of strings, the namespace list to use.
264 """
265 # Write the generated constants out to a file.
266 catapults = []
267 integral_catapults = []
268
269 if type(params) is list:
270 name = params[0].name
271 for index, param in enumerate(params):
Austin Schuhac61c882022-02-23 17:22:22 -0800272 catapults.append(Catapult(param, param.name + str(index)))
Austin Schuh2e28d872022-02-19 18:25:57 -0800273 integral_catapults.append(
Austin Schuhac61c882022-02-23 17:22:22 -0800274 IntegralCatapult(param, 'Integral' + param.name + str(index)))
Austin Schuh2e28d872022-02-19 18:25:57 -0800275 else:
276 name = params.name
277 catapults.append(Catapult(params, params.name))
278 integral_catapults.append(
279 IntegralCatapult(params, 'Integral' + params.name))
280
Austin Schuhac61c882022-02-23 17:22:22 -0800281 loop_writer = control_loop.ControlLoopWriter(name,
282 catapults,
283 namespaces=year_namespaces)
Austin Schuh2e28d872022-02-19 18:25:57 -0800284 loop_writer.AddConstant(
285 control_loop.Constant('kOutputRatio', '%f', catapults[0].G))
286 loop_writer.AddConstant(
287 control_loop.Constant('kFreeSpeed', '%f',
288 catapults[0].motor.free_speed))
289 loop_writer.Write(plant_files[0], plant_files[1])
290
291 integral_loop_writer = control_loop.ControlLoopWriter(
292 'Integral' + name, integral_catapults, namespaces=year_namespaces)
293 integral_loop_writer.Write(controller_files[0], controller_files[1])