blob: a4c82de88b6571dc21fbc3982069043d16b55a06 [file] [log] [blame]
Austin Schuh1d731362022-02-22 13:57:55 -08001#ifndef Y2022_CONTROL_LOOPS_SUPERSTRUCTURE_CATAPULT_CATAPULT_H_
2#define Y2022_CONTROL_LOOPS_SUPERSTRUCTURE_CATAPULT_CATAPULT_H_
3
4#include "Eigen/Dense"
Austin Schuh1d731362022-02-22 13:57:55 -08005#include "glog/logging.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07006
7#include "frc971/control_loops/state_feedback_loop.h"
Austin Schuh1d731362022-02-22 13:57:55 -08008#include "osqp++.h"
Austin Schuh39f26f62022-02-24 21:34:46 -08009#include "y2022/constants.h"
10#include "y2022/control_loops/superstructure/superstructure_goal_generated.h"
11#include "y2022/control_loops/superstructure/superstructure_position_generated.h"
12#include "y2022/control_loops/superstructure/superstructure_status_generated.h"
Austin Schuh1d731362022-02-22 13:57:55 -080013
14namespace y2022 {
15namespace control_loops {
16namespace superstructure {
17namespace catapult {
18
19// MPC problem for a specified horizon. This contains all the state for the
20// solver, setters to modify the current and target state, and a way to fetch
21// the solution.
22class MPCProblem {
23 public:
24 MPCProblem(size_t horizon,
25 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> P,
26 Eigen::Matrix<double, Eigen::Dynamic, 1> accel_q,
27 Eigen::Matrix<double, 2, 2> Af,
28 Eigen::Matrix<double, Eigen::Dynamic, 2> final_q);
29
30 MPCProblem(MPCProblem const &) = delete;
31 void operator=(MPCProblem const &x) = delete;
32
33 // Sets the current and final state. This keeps the problem in tact and
34 // doesn't recreate it, so it will be fast.
35 void SetState(Eigen::Matrix<double, 2, 1> X_initial,
36 Eigen::Matrix<double, 2, 1> X_final);
37
38 // Solves our problem.
39 bool Solve();
40
41 double solve_time() const { return solve_time_; }
42
43 // Returns the solution that the solver found when Solve was last called.
44 double U(size_t i) const { return solver_.primal_solution()(i); }
45
46 // Returns the number of U's to be solved.
47 size_t horizon() const { return horizon_; }
48
49 // Warm starts the optimizer with the provided solution to make it solve
50 // faster.
51 void WarmStart(const MPCProblem &p);
52
53 private:
54 // The number of u's to solve for.
55 const size_t horizon_;
56
57 // The problem statement variables needed by SetState to update q.
58 const Eigen::Matrix<double, Eigen::Dynamic, 1> accel_q_;
59 const Eigen::Matrix<double, 2, 2> Af_;
60 const Eigen::Matrix<double, Eigen::Dynamic, 2> final_q_;
61
62 Eigen::Matrix<double, 2, 1> X_initial_;
63 Eigen::Matrix<double, 2, 1> X_final_;
64
Austin Schuh39f26f62022-02-24 21:34:46 -080065 Eigen::Matrix<double, Eigen::Dynamic, 1> objective_vector_;
66
Austin Schuh1d731362022-02-22 13:57:55 -080067 // Solver state.
68 osqp::OsqpInstance instance_;
69 osqp::OsqpSolver solver_;
70 osqp::OsqpSettings settings_;
71
72 double solve_time_ = 0;
73};
74
75// Decently efficient problem generator for multiple horizons given a max
76// horizon to solve for.
77//
78// The math is documented in mpc.tex
79class CatapultProblemGenerator {
80 public:
81 // Builds a problem generator for the specified max horizon and caches a lot
82 // of the state.
83 CatapultProblemGenerator(size_t horizon);
84
85 // Returns the maximum horizon.
86 size_t horizon() const { return horizon_; }
87
88 // Makes a problem for the specificed horizon.
89 std::unique_ptr<MPCProblem> MakeProblem(size_t horizon);
90
91 // Returns the P and Q matrices for the problem statement.
92 // cost = 0.5 X.T P X + q.T X
93 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> P(size_t horizon);
94 const Eigen::Matrix<double, Eigen::Dynamic, 1> q(
95 size_t horizon, Eigen::Matrix<double, 2, 1> X_initial,
96 Eigen::Matrix<double, 2, 1> X_final);
97
98 private:
99 const Eigen::Matrix<double, Eigen::Dynamic, 1> accel_q(size_t horizon);
100
101 const Eigen::Matrix<double, 2, 2> Af(size_t horizon);
102 const Eigen::Matrix<double, 2, Eigen::Dynamic> Bf(size_t horizon);
103 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Pi(
104 size_t horizon);
105
106 // These functions are used in the constructor to build up the matrices below.
107 Eigen::Matrix<double, Eigen::Dynamic, 2> MakeAs();
108 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> MakeBs();
109 Eigen::Matrix<double, Eigen::Dynamic, 1> Makem();
110 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> MakeM();
111 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> MakeW();
112 Eigen::Matrix<double, Eigen::Dynamic, 1> Makew();
113 Eigen::DiagonalMatrix<double, Eigen::Dynamic> MakePi();
114 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> MakeP();
115
116 const StateFeedbackPlant<2, 1, 1> plant_;
117 const size_t horizon_;
118
119 const Eigen::DiagonalMatrix<double, 2> Q_final_;
120
121 const Eigen::Matrix<double, Eigen::Dynamic, 2> As_;
122 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Bs_;
123 const Eigen::Matrix<double, Eigen::Dynamic, 1> m_;
124 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> M_;
125
126 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> W_;
127 const Eigen::Matrix<double, Eigen::Dynamic, 1> w_;
128 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> Pi_;
129
130 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> WM_;
131 const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Wmpw_;
132};
133
Austin Schuh39f26f62022-02-24 21:34:46 -0800134// A class to hold all the state needed to manage the catapult MPC solvers for
135// repeated shots.
136//
137// The solver may take a couple of cycles to get everything converged and ready.
138// The flow is as follows:
139// 1) Reset() the state for the new problem.
140// 2) Update to the current state with SetState()
141// 3) Call Solve(). This will return true if it is ready to be executed, false
142// if it needs more iterations to fully converge.
143// 4) Next() returns the current optimal control output and advances the
144// pointers to the next problem.
145// 5) Go back to 2 for the next cycle.
146class CatapultController {
147 public:
148 CatapultController(size_t horizon);
149
150 // Starts back over at the first controller.
151 void Reset();
152
153 // Updates our current and final states for the current controller.
154 void SetState(Eigen::Matrix<double, 2, 1> X_initial,
155 Eigen::Matrix<double, 2, 1> X_final);
156
157 // Solves! Returns true if the solution converged and osqp was happy.
158 bool Solve();
159
160 // Returns the time in seconds it last took Solve to run.
161 double solve_time() const { return solve_time_; }
162
Austin Schuh41472552022-03-13 18:09:41 -0700163 // Returns the horizon of the current controller.
164 size_t current_horizon() const {
165 if (current_controller_ >= problems_.size()) {
166 return 0u;
167 } else {
168 return problems_[current_controller_]->horizon();
169 }
170 }
171
Austin Schuh39f26f62022-02-24 21:34:46 -0800172 // Returns the controller value if there is a controller to run, or nullopt if
173 // we finished the last controller. Advances the controller pointer to the
174 // next controller and warms up the next controller.
175 std::optional<double> Next();
176
177 // Returns true if Next has been called and a controller has been used. Reset
178 // starts over.
179 bool started() const { return current_controller_ != 0u; }
180
181 private:
182 CatapultProblemGenerator generator_;
183
184 std::vector<std::unique_ptr<MPCProblem>> problems_;
185
186 size_t current_controller_ = 0;
187 double solve_time_ = 0.0;
188};
189
190// Class to handle transitioning between both the profiled subsystem and the MPC
191// for shooting.
192class Catapult {
193 public:
194 Catapult(const constants::Values &values)
Austin Schuh41472552022-03-13 18:09:41 -0700195 : catapult_(values.catapult.subsystem_params), catapult_mpc_(30) {}
Austin Schuh39f26f62022-02-24 21:34:46 -0800196
197 using PotAndAbsoluteEncoderSubsystem =
198 ::frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystem<
199 ::frc971::zeroing::PotAndAbsoluteEncoderZeroingEstimator,
200 ::frc971::control_loops::PotAndAbsoluteEncoderProfiledJointStatus>;
201
202 // Resets all state for when WPILib restarts.
203 void Reset() { catapult_.Reset(); }
204
Ravago Jones5da06352022-03-04 20:26:24 -0800205 void Estop() { catapult_.Estop(); }
206
Austin Schuh39f26f62022-02-24 21:34:46 -0800207 bool zeroed() const { return catapult_.zeroed(); }
208 bool estopped() const { return catapult_.estopped(); }
209 double solve_time() const { return catapult_mpc_.solve_time(); }
210
Austin Schuh41472552022-03-13 18:09:41 -0700211 uint8_t mpc_horizon() const { return current_horizon_; }
212
Austin Schuh39f26f62022-02-24 21:34:46 -0800213 bool mpc_active() const { return !use_profile_; }
214
Austin Schuh80fc2752022-02-25 13:33:56 -0800215 // Returns the number of shots taken.
216 int shot_count() const { return shot_count_; }
217
Ravago Jones5da06352022-03-04 20:26:24 -0800218 // Returns the estimated position
219 double estimated_position() const { return catapult_.estimated_position(); }
220
Austin Schuh39f26f62022-02-24 21:34:46 -0800221 // Runs either the MPC or the profiled subsystem depending on if we are
222 // shooting or not. Returns the status.
223 const flatbuffers::Offset<
224 frc971::control_loops::PotAndAbsoluteEncoderProfiledJointStatus>
Ravago Jones3283ce02022-03-09 19:31:29 -0800225 Iterate(const CatapultGoal *unsafe_goal, const Position *position,
Austin Schuh97410d72022-03-12 15:37:23 -0800226 double battery_voltage, double *catapult_voltage, bool fire,
Ravago Jones5da06352022-03-04 20:26:24 -0800227 flatbuffers::FlatBufferBuilder *fbb);
Austin Schuh39f26f62022-02-24 21:34:46 -0800228
229 private:
Austin Schuh39f26f62022-02-24 21:34:46 -0800230 PotAndAbsoluteEncoderSubsystem catapult_;
231
232 catapult::CatapultController catapult_mpc_;
233
234 enum CatapultState { PROFILE, FIRING, RESETTING };
235
236 CatapultState catapult_state_ = CatapultState::PROFILE;
237
Ravago Jones3283ce02022-03-09 19:31:29 -0800238 double latched_shot_position = 0.0;
239 double latched_shot_velocity = 0.0;
240
Austin Schuh39f26f62022-02-24 21:34:46 -0800241 bool last_firing_ = false;
242 bool use_profile_ = true;
Austin Schuh80fc2752022-02-25 13:33:56 -0800243
244 int shot_count_ = 0;
Austin Schuh41472552022-03-13 18:09:41 -0700245 uint8_t current_horizon_ = 0u;
Austin Schuh39f26f62022-02-24 21:34:46 -0800246};
247
Austin Schuh1d731362022-02-22 13:57:55 -0800248} // namespace catapult
249} // namespace superstructure
250} // namespace control_loops
251} // namespace y2022
252
253#endif // Y2022_CONTROL_LOOPS_SUPERSTRUCTURE_CATAPULT_CATAPULT_H_