blob: 4250df2d13b1b7b9e8753f6da0bf0baa476584cd [file] [log] [blame]
Brian Silverman273d8a32014-05-10 22:19:09 -07001#ifndef FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_
2#define FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_
Austin Schuhdc1c84a2013-02-23 16:33:10 -08003
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cassert>
Tyler Chatow6738c362019-02-16 14:12:30 -08005#include <chrono>
Austin Schuhc5fceb82017-02-25 16:24:12 -08006#include <memory>
7#include <utility>
8#include <vector>
Brian Silvermanc571e052013-03-13 17:58:56 -07009
Austin Schuhdc1c84a2013-02-23 16:33:10 -080010#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080011#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080012
Brian Silverman6260c092018-01-14 15:21:36 -080013#if defined(__linux__)
John Park33858a32018-09-28 23:05:48 -070014#include "aos/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080015#endif
John Park33858a32018-09-28 23:05:48 -070016#include "aos/macros.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070017
Austin Schuhe91f14c2017-02-25 19:43:57 -080018template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080019 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080020class StateFeedbackLoop;
21
Brian Silverman5808bcb2014-09-14 21:40:43 -040022// For everything in this file, "inputs" and "outputs" are defined from the
23// perspective of the plant. This means U is an input and Y is an output
24// (because you give the plant U (powers) and it gives you back a Y (sensor
25// values). This is the opposite of what they mean from the perspective of the
26// controller (U is an output because that's what goes to the motors and Y is an
27// input because that's what comes back from the sensors).
28
Austin Schuh20388b62017-11-23 22:40:46 -080029template <int number_of_states, int number_of_inputs, int number_of_outputs,
30 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080031struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080032 public:
33 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
34
Austin Schuhe3490622013-03-13 01:24:30 -070035 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080036 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080037 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080038 C(other.C),
39 D(other.D),
40 U_min(other.U_min),
James Kuszmaul03be1242020-02-21 14:52:04 -080041 U_max(other.U_max),
42 dt(other.dt) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080043
Austin Schuhe3490622013-03-13 01:24:30 -070044 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080045 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080046 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
47 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
48 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
49 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080050 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
51 const std::chrono::nanoseconds dt)
52 : A(A), B(B), C(C), D(D), U_min(U_min), U_max(U_max), dt(dt) {}
Austin Schuhe3490622013-03-13 01:24:30 -070053
Austin Schuh20388b62017-11-23 22:40:46 -080054 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080055 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
56 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
57 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
58 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
59 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
James Kuszmaul03be1242020-02-21 14:52:04 -080060 const std::chrono::nanoseconds dt;
Austin Schuhe3490622013-03-13 01:24:30 -070061};
62
Austin Schuh20388b62017-11-23 22:40:46 -080063template <int number_of_states, int number_of_inputs, int number_of_outputs,
64 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070065class StateFeedbackPlant {
66 public:
67 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070068
69 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080070 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080071 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh66c19882017-02-25 13:36:28 -080072 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080073 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070074 Reset();
75 }
76
Tyler Chatow6738c362019-02-16 14:12:30 -080077 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070078 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070079 X_.swap(other.X_);
80 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070081 }
82
Austin Schuh1a387962015-01-31 16:36:20 -080083 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070084
Austin Schuh20388b62017-11-23 22:40:46 -080085 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080086 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070087 }
Austin Schuh20388b62017-11-23 22:40:46 -080088 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -080089 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080090 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070091 }
Austin Schuh20388b62017-11-23 22:40:46 -080092 Scalar B(int i, int j) const { return B()(i, j); }
93 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080094 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -070095 }
Austin Schuh20388b62017-11-23 22:40:46 -080096 Scalar C(int i, int j) const { return C()(i, j); }
97 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080098 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -070099 }
Austin Schuh20388b62017-11-23 22:40:46 -0800100 Scalar D(int i, int j) const { return D()(i, j); }
101 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800102 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700103 }
Austin Schuh20388b62017-11-23 22:40:46 -0800104 Scalar U_min(int i, int j) const { return U_min()(i, j); }
105 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800106 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700107 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800108 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700109
Austin Schuh43b9ae92020-02-29 23:08:38 -0800110 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
111
Austin Schuh20388b62017-11-23 22:40:46 -0800112 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800113 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800114 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800115 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700116
Austin Schuh20388b62017-11-23 22:40:46 -0800117 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800118 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800119 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800120 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700121
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800122 size_t coefficients_size() const { return coefficients_.size(); }
123
Austin Schuhb6a6d822016-02-08 00:20:40 -0800124 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800125 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800126 &coefficients(int index) const {
127 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700128 }
129
Austin Schuhc5fceb82017-02-25 16:24:12 -0800130 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800131 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800132 &coefficients() const {
133 return *coefficients_[index_];
134 }
135
136 int index() const { return index_; }
137 void set_index(int index) {
138 assert(index >= 0);
139 assert(index < static_cast<int>(coefficients_.size()));
140 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700141 }
142
143 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700144 X_.setZero();
145 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800146 }
147
Austin Schuh849f0032013-03-03 23:59:53 -0800148 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800149 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400150 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800151 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
152 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800153#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700154 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800155#else
156 abort();
157#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800158 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800159 }
160 }
Austin Schuh849f0032013-03-03 23:59:53 -0800161
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800162 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800163 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800164 // Powers outside of the range are more likely controller bugs than things
165 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800166 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800167 X_ = Update(X(), U);
Austin Schuh01c7b252017-03-05 00:59:31 -0800168 UpdateY(U);
169 }
170
171 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800172 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800173 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800174 }
175
Austin Schuh20388b62017-11-23 22:40:46 -0800176 Eigen::Matrix<Scalar, number_of_states, 1> Update(
177 const Eigen::Matrix<Scalar, number_of_states, 1> X,
178 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800179 return A() * X + B() * U;
180 }
181
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800182 protected:
183 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800184 static const int kNumStates = number_of_states;
185 static const int kNumOutputs = number_of_outputs;
186 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700187
188 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800189 Eigen::Matrix<Scalar, number_of_states, 1> X_;
190 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700191
Austin Schuhb6a6d822016-02-08 00:20:40 -0800192 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800193 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800194 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700195
Austin Schuhc5fceb82017-02-25 16:24:12 -0800196 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700197
198 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800199};
200
Austin Schuh32501832017-02-25 18:32:56 -0800201// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800202template <int number_of_states, int number_of_inputs, int number_of_outputs,
203 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800204struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700205 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700206
Austin Schuh20388b62017-11-23 22:40:46 -0800207 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
208 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700209
Austin Schuh32501832017-02-25 18:32:56 -0800210 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800211 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
212 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800213 : K(K), Kff(Kff) {}
214};
215
Austin Schuh20388b62017-11-23 22:40:46 -0800216template <int number_of_states, int number_of_inputs, int number_of_outputs,
217 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800218class StateFeedbackController {
219 public:
220 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
221
222 explicit StateFeedbackController(
223 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800224 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
225 *controllers)
Austin Schuh32501832017-02-25 18:32:56 -0800226 : coefficients_(::std::move(*controllers)) {}
227
228 StateFeedbackController(StateFeedbackController &&other)
229 : index_(other.index_) {
230 ::std::swap(coefficients_, other.coefficients_);
231 }
232
Austin Schuh20388b62017-11-23 22:40:46 -0800233 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800234 return coefficients().K;
235 }
Austin Schuh20388b62017-11-23 22:40:46 -0800236 Scalar K(int i, int j) const { return K()(i, j); }
237 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800238 return coefficients().Kff;
239 }
Austin Schuh20388b62017-11-23 22:40:46 -0800240 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800241
Austin Schuhe91f14c2017-02-25 19:43:57 -0800242 void Reset() {}
243
Austin Schuh32501832017-02-25 18:32:56 -0800244 // Sets the current controller to be index, clamped to be within range.
245 void set_index(int index) {
246 if (index < 0) {
247 index_ = 0;
248 } else if (index >= static_cast<int>(coefficients_.size())) {
249 index_ = static_cast<int>(coefficients_.size()) - 1;
250 } else {
251 index_ = index;
252 }
253 }
254
255 int index() const { return index_; }
256
257 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800258 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800259 &coefficients(int index) const {
260 return *coefficients_[index];
261 }
262
263 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800264 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800265 &coefficients() const {
266 return *coefficients_[index_];
267 }
268
269 private:
270 int index_ = 0;
271 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800272 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800273 coefficients_;
274};
275
Austin Schuh32501832017-02-25 18:32:56 -0800276// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800277template <int number_of_states, int number_of_inputs, int number_of_outputs,
278 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800279struct StateFeedbackObserverCoefficients final {
280 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
281
Sabina Davis3922dfa2018-02-10 23:10:05 -0800282 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800283 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
284 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800285
286 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800287 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
288 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800289 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
290 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R)
291 : KalmanGain(KalmanGain), Q(Q), R(R) {}
Austin Schuh32501832017-02-25 18:32:56 -0800292};
293
Austin Schuh20388b62017-11-23 22:40:46 -0800294template <int number_of_states, int number_of_inputs, int number_of_outputs,
295 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800296class StateFeedbackObserver {
297 public:
298 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
299
300 explicit StateFeedbackObserver(
301 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800302 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
303 *observers)
Austin Schuh32501832017-02-25 18:32:56 -0800304 : coefficients_(::std::move(*observers)) {}
305
306 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800307 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800308 ::std::swap(coefficients_, other.coefficients_);
309 }
310
Tyler Chatow6738c362019-02-16 14:12:30 -0800311 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
312 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800313 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800314 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800315 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800316
Austin Schuh20388b62017-11-23 22:40:46 -0800317 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800318 return X_hat_;
319 }
Austin Schuh20388b62017-11-23 22:40:46 -0800320 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800321
Austin Schuh6501d232017-11-23 20:35:27 -0800322 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800323 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800324 X_hat_.setZero();
325 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800326
Austin Schuh6501d232017-11-23 20:35:27 -0800327 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800328 number_of_outputs, Scalar> *plant,
329 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800330 ::std::chrono::nanoseconds /*dt*/) {
331 mutable_X_hat() = plant->Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800332 }
333
Austin Schuh6501d232017-11-23 20:35:27 -0800334 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800335 number_of_outputs, Scalar> &plant,
336 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
337 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Tyler Chatow6738c362019-02-16 14:12:30 -0800338 mutable_X_hat() += KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800339 }
340
Austin Schuh32501832017-02-25 18:32:56 -0800341 // Sets the current controller to be index, clamped to be within range.
342 void set_index(int index) {
343 if (index < 0) {
344 index_ = 0;
345 } else if (index >= static_cast<int>(coefficients_.size())) {
346 index_ = static_cast<int>(coefficients_.size()) - 1;
347 } else {
348 index_ = index;
349 }
350 }
351
352 int index() const { return index_; }
353
354 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800355 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800356 &coefficients(int index) const {
357 return *coefficients_[index];
358 }
359
360 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800361 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800362 &coefficients() const {
363 return *coefficients_[index_];
364 }
365
366 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800367 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800368 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800369
Austin Schuh32501832017-02-25 18:32:56 -0800370 int index_ = 0;
371 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800372 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800373 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700374};
375
Austin Schuhe91f14c2017-02-25 19:43:57 -0800376template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800377 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800378 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800379 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800380 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800381 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800382class StateFeedbackLoop {
383 public:
384 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
385
Austin Schuh32501832017-02-25 18:32:56 -0800386 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800387 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800388 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800389 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800390 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800391 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800392 controller_(::std::move(controller)),
393 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700394 Reset();
395 }
396
Austin Schuhc5fceb82017-02-25 16:24:12 -0800397 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800398 : plant_(::std::move(other.plant_)),
399 controller_(::std::move(other.controller_)),
400 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800401 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700402 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800403 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700404 U_.swap(other.U_);
405 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700406 }
407
Austin Schuh1a387962015-01-31 16:36:20 -0800408 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700409
Austin Schuh20388b62017-11-23 22:40:46 -0800410 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800411 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700412 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800413 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800414 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800415 Scalar R(int i, int j = 0) const { return R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800416 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800417 return next_R_;
418 }
Austin Schuh95771d92021-01-23 14:42:25 -0800419 Scalar next_R(int i, int j = 0) const { return next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800420 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800421 Scalar U(int i, int j = 0) const { return U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800422 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700423 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700424 }
Austin Schuh95771d92021-01-23 14:42:25 -0800425 Scalar U_uncapped(int i, int j = 0) const { return U_uncapped()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800426 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800427 return ff_U_;
428 }
Austin Schuh95771d92021-01-23 14:42:25 -0800429 Scalar ff_U(int i, int j = 0) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700430
Austin Schuh20388b62017-11-23 22:40:46 -0800431 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800432 return observer_.mutable_X_hat();
433 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800434 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800435 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800436 Scalar &mutable_R(int i, int j = 0) { return mutable_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800437 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800438 return next_R_;
439 }
Austin Schuh95771d92021-01-23 14:42:25 -0800440 Scalar &mutable_next_R(int i, int j = 0) { return mutable_next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800441 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800442 Scalar &mutable_U(int i, int j = 0) { return mutable_U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800443 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700444 return U_uncapped_;
445 }
Austin Schuh95771d92021-01-23 14:42:25 -0800446 Scalar &mutable_U_uncapped(int i, int j = 0) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700447 return mutable_U_uncapped()(i, j);
448 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800449
Austin Schuhe91f14c2017-02-25 19:43:57 -0800450 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800451 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800452
Austin Schuh32501832017-02-25 18:32:56 -0800453 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800454 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800455 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800456 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700457 }
458
Austin Schuhe91f14c2017-02-25 19:43:57 -0800459 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700460
Austin Schuh9644e1c2013-03-12 00:40:36 -0700461 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700462 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800463 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700464 U_.setZero();
465 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800466 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800467
468 plant_.Reset();
469 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800470 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800471 }
472
473 // If U is outside the hardware range, limit it before the plant tries to use
474 // it.
475 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400476 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800477 if (U(i, 0) > plant().U_max(i, 0)) {
478 U_(i, 0) = plant().U_max(i, 0);
479 } else if (U(i, 0) < plant().U_min(i, 0)) {
480 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800481 }
482 }
483 }
484
Austin Schuhf9286cd2014-02-11 00:51:09 -0800485 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800486 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800487 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800488 }
489
Austin Schuh20388b62017-11-23 22:40:46 -0800490 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800491 return R() - X_hat();
492 }
493
Austin Schuhb6a6d822016-02-08 00:20:40 -0800494 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800495 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800496 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800497 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800498 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800499 }
500
501 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800502 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800503 // TODO(austin): Should this live in StateSpaceController?
504 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800505 }
506
Austin Schuh43b9ae92020-02-29 23:08:38 -0800507 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800508 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700509 U_.setZero();
510 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800511 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800512 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800513 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800514 CapU();
515 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800516 UpdateFFReference();
517 }
518
519 // stop_motors is whether or not to output all 0s.
520 void Update(bool stop_motors,
521 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
522 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800523
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800524 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800525 }
526
527 // Updates R() after any CapU operations happen on U().
528 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800529 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800530 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800531 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800532 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000533 }
534
Austin Schuh20388b62017-11-23 22:40:46 -0800535 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800536 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800537 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800538 }
539
Austin Schuh32501832017-02-25 18:32:56 -0800540 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800541 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800542 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800543 controller_.set_index(index);
544 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700545 }
546
Austin Schuh32501832017-02-25 18:32:56 -0800547 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700548
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800549 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800550 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800551
Austin Schuh20388b62017-11-23 22:40:46 -0800552 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
553 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800554 controller_;
555
Austin Schuhe91f14c2017-02-25 19:43:57 -0800556 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700557
Brian Silverman273d8a32014-05-10 22:19:09 -0700558 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800559 static constexpr int kNumStates = number_of_states;
560 static constexpr int kNumOutputs = number_of_outputs;
561 static constexpr int kNumInputs = number_of_inputs;
562
563 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800564 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700565
Brian Silverman273d8a32014-05-10 22:19:09 -0700566 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800567 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800568 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800569 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800570 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800571 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800572 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800573 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800574 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700575
Brian Silverman0a151c92014-05-02 15:28:44 -0700576 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800577};
578
Brian Silverman273d8a32014-05-10 22:19:09 -0700579#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_