blob: d6040d11eca6072085e47c3a8b0f6de61e680254 [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):
Austin Schuh82162452022-02-07 22:01:45 -080016 def __init__(self, params, name="Catapult"):
Austin Schuhac61c882022-02-23 17:22:22 -080017 super(Catapult, self).__init__(params, name)
18 # Signal that we have a single cycle output delay to compensate for in
19 # our observer.
20 self.delayed_u = True
Austin Schuh82162452022-02-07 22:01:45 -080021
22 self.InitializeState()
23
24
Austin Schuhac61c882022-02-23 17:22:22 -080025class IntegralCatapult(angular_system.IntegralAngularSystem):
Austin Schuh82162452022-02-07 22:01:45 -080026 def __init__(self, params, name="IntegralCatapult"):
27 super(IntegralCatapult, self).__init__(params, name=name)
Austin Schuhac61c882022-02-23 17:22:22 -080028 # Signal that we have a single cycle output delay to compensate for in
29 # our observer.
30 self.delayed_u = True
Austin Schuh82162452022-02-07 22:01:45 -080031
32 self.InitializeState()
33
34
35def MaxSpeed(params, U, final_position):
36 """Runs the catapult plant with an initial condition and goal.
37
38 Args:
39 catapult: Catapult object to use.
40 goal: goal state.
41 iterations: Number of timesteps to run the model for.
42 controller_catapult: Catapult object to get K from, or None if we should
43 use catapult.
44 observer_catapult: Catapult object to use for the observer, or None if we
45 should use the actual state.
46 """
47
48 # Various lists for graphing things.
49 catapult = Catapult(params, params.name)
50 controller_catapult = IntegralCatapult(params, params.name)
51 observer_catapult = IntegralCatapult(params, params.name)
52 vbat = 12.0
53
54 while True:
55 X_hat = catapult.X
56 if catapult.X[0, 0] > final_position:
Austin Schuhac61c882022-02-23 17:22:22 -080057 return catapult.X[1, 0] * params.radius
Austin Schuh82162452022-02-07 22:01:45 -080058
59 if observer_catapult is not None:
60 X_hat = observer_catapult.X_hat
61
62 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat)
63
64 if observer_catapult is not None:
65 observer_catapult.Y = catapult.Y
Austin Schuhac61c882022-02-23 17:22:22 -080066 observer_catapult.CorrectObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -080067
68 applied_U = U.copy()
69 catapult.Update(applied_U)
70
71 if observer_catapult is not None:
Austin Schuhac61c882022-02-23 17:22:22 -080072 observer_catapult.PredictObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -080073
74
75def PlotShot(params, U, final_position):
76 """Runs the catapult plant with an initial condition and goal.
77
78 Args:
79 catapult: Catapult object to use.
80 goal: goal state.
81 iterations: Number of timesteps to run the model for.
82 controller_catapult: Catapult object to get K from, or None if we should
83 use catapult.
84 observer_catapult: Catapult object to use for the observer, or None if we
85 should use the actual state.
86 """
87
88 # Various lists for graphing things.
89 t = []
90 x = []
91 x_hat = []
92 v = []
93 w_hat = []
94 v_hat = []
95 a = []
96 u = []
97 offset = []
98
99 catapult = Catapult(params, params.name)
100 controller_catapult = IntegralCatapult(params, params.name)
101 observer_catapult = IntegralCatapult(params, params.name)
102 vbat = 12.0
103
104 if t:
105 initial_t = t[-1] + catapult.dt
106 else:
107 initial_t = 0
108
109 for i in range(10000):
110 X_hat = catapult.X
111 if catapult.X[0, 0] > final_position:
112 break
113
114 if observer_catapult is not None:
115 X_hat = observer_catapult.X_hat
116 x_hat.append(observer_catapult.X_hat[0, 0])
117 w_hat.append(observer_catapult.X_hat[1, 0])
Austin Schuhac61c882022-02-23 17:22:22 -0800118 v_hat.append(observer_catapult.X_hat[1, 0] * params.radius)
Austin Schuh82162452022-02-07 22:01:45 -0800119
120 U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat)
121 x.append(catapult.X[0, 0])
122
123 if v:
124 last_v = v[-1]
125 else:
126 last_v = 0
127
128 v.append(catapult.X[1, 0])
129 a.append((v[-1] - last_v) / catapult.dt)
130
131 if observer_catapult is not None:
132 observer_catapult.Y = catapult.Y
Austin Schuhac61c882022-02-23 17:22:22 -0800133 observer_catapult.CorrectObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -0800134 offset.append(observer_catapult.X_hat[2, 0])
135
136 catapult.Update(U)
137
138 if observer_catapult is not None:
Austin Schuhac61c882022-02-23 17:22:22 -0800139 observer_catapult.PredictObserver(U)
Austin Schuh82162452022-02-07 22:01:45 -0800140
141 t.append(initial_t + i * catapult.dt)
142 u.append(U[0, 0])
143
144 pylab.subplot(3, 1, 1)
145 pylab.plot(t, v, label='v')
146 pylab.plot(t, x_hat, label='x_hat')
147 pylab.plot(t, v, label='v')
148 pylab.plot(t, v_hat, label='v_hat')
149 pylab.plot(t, w_hat, label='w_hat')
150 pylab.legend()
151
152 pylab.subplot(3, 1, 2)
153 pylab.plot(t, u, label='u')
154 pylab.plot(t, offset, label='voltage_offset')
155 pylab.legend()
156
157 pylab.subplot(3, 1, 3)
158 pylab.plot(t, a, label='a')
159 pylab.legend()
160
161 pylab.show()
Austin Schuh2e28d872022-02-19 18:25:57 -0800162
Austin Schuhac61c882022-02-23 17:22:22 -0800163
164RunTest = angular_system.RunTest
165
166
167def PlotStep(params, R, plant_params=None):
168 """Plots a step move to the goal.
169
170 Args:
171 params: CatapultParams for the controller and observer
172 plant_params: CatapultParams for the plant. Defaults to params if
173 plant_params is None.
174 R: numpy.matrix(2, 1), the goal"""
175 plant = Catapult(plant_params or params, params.name)
176 controller = IntegralCatapult(params, params.name)
177 observer = IntegralCatapult(params, params.name)
178
179 # Test moving the system.
180 initial_X = numpy.matrix([[0.0], [0.0]])
181 augmented_R = numpy.matrix(numpy.zeros((3, 1)))
182 augmented_R[0:2, :] = R
183 RunTest(plant,
184 end_goal=augmented_R,
185 controller=controller,
186 observer=observer,
187 duration=2.0,
188 use_profile=False,
189 kick_time=1.0,
190 kick_magnitude=0.0)
191
192
193def PlotKick(params, R, plant_params=None):
194 """Plots a step motion with a kick at 1.0 seconds.
195
196 Args:
197 params: CatapultParams for the controller and observer
198 plant_params: CatapultParams for the plant. Defaults to params if
199 plant_params is None.
200 R: numpy.matrix(2, 1), the goal"""
201 plant = Catapult(plant_params or params, params.name)
202 controller = IntegralCatapult(params, params.name)
203 observer = IntegralCatapult(params, params.name)
204
205 # Test moving the system.
206 initial_X = numpy.matrix([[0.0], [0.0]])
207 augmented_R = numpy.matrix(numpy.zeros((3, 1)))
208 augmented_R[0:2, :] = R
209 RunTest(plant,
210 end_goal=augmented_R,
211 controller=controller,
212 observer=observer,
213 duration=2.0,
214 use_profile=False,
215 kick_time=1.0,
216 kick_magnitude=2.0)
217
218
219def PlotMotion(params,
220 R,
221 max_velocity=10.0,
222 max_acceleration=70.0,
223 plant_params=None):
224 """Plots a trapezoidal motion.
225
226 Args:
227 params: CatapultParams for the controller and observer
228 plant_params: CatapultParams for the plant. Defaults to params if
229 plant_params is None.
230 R: numpy.matrix(2, 1), the goal,
231 max_velocity: float, The max velocity of the profile.
232 max_acceleration: float, The max acceleration of the profile.
233 """
234 plant = Catapult(plant_params or params, params.name)
235 controller = IntegralCatapult(params, params.name)
236 observer = IntegralCatapult(params, params.name)
237
238 # Test moving the system.
239 initial_X = numpy.matrix([[0.0], [0.0]])
240 augmented_R = numpy.matrix(numpy.zeros((3, 1)))
241 augmented_R[0:2, :] = R
242 RunTest(plant,
243 end_goal=augmented_R,
244 controller=controller,
245 observer=observer,
246 duration=2.0,
247 use_profile=True,
248 max_velocity=max_velocity,
249 max_acceleration=max_acceleration)
250
251
Austin Schuh2e28d872022-02-19 18:25:57 -0800252def WriteCatapult(params, plant_files, controller_files, year_namespaces):
253 """Writes out the constants for a catapult to a file.
254
255 Args:
256 params: list of CatapultParams or CatapultParams, the
257 parameters defining the system.
258 plant_files: list of strings, the cc and h files for the plant.
259 controller_files: list of strings, the cc and h files for the integral
260 controller.
261 year_namespaces: list of strings, the namespace list to use.
262 """
263 # Write the generated constants out to a file.
264 catapults = []
265 integral_catapults = []
266
267 if type(params) is list:
268 name = params[0].name
269 for index, param in enumerate(params):
Austin Schuhac61c882022-02-23 17:22:22 -0800270 catapults.append(Catapult(param, param.name + str(index)))
Austin Schuh2e28d872022-02-19 18:25:57 -0800271 integral_catapults.append(
Austin Schuhac61c882022-02-23 17:22:22 -0800272 IntegralCatapult(param, 'Integral' + param.name + str(index)))
Austin Schuh2e28d872022-02-19 18:25:57 -0800273 else:
274 name = params.name
275 catapults.append(Catapult(params, params.name))
276 integral_catapults.append(
277 IntegralCatapult(params, 'Integral' + params.name))
278
Austin Schuhac61c882022-02-23 17:22:22 -0800279 loop_writer = control_loop.ControlLoopWriter(name,
280 catapults,
281 namespaces=year_namespaces)
Austin Schuh2e28d872022-02-19 18:25:57 -0800282 loop_writer.AddConstant(
283 control_loop.Constant('kOutputRatio', '%f', catapults[0].G))
284 loop_writer.AddConstant(
285 control_loop.Constant('kFreeSpeed', '%f',
286 catapults[0].motor.free_speed))
287 loop_writer.Write(plant_files[0], plant_files[1])
288
289 integral_loop_writer = control_loop.ControlLoopWriter(
290 'Integral' + name, integral_catapults, namespaces=year_namespaces)
291 integral_loop_writer.Write(controller_files[0], controller_files[1])