blob: 168df43ce72db5ed32be010f1824c0ac05c845bf [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
Austin Schuh849f0032013-03-03 23:59:53 -08004#include <assert.h>
Austin Schuhdc1c84a2013-02-23 16:33:10 -08005
Tyler Chatow6738c362019-02-16 14:12:30 -08006#include <chrono>
Austin Schuhc5fceb82017-02-25 16:24:12 -08007#include <memory>
8#include <utility>
9#include <vector>
Brian Silvermanc571e052013-03-13 17:58:56 -070010
Austin Schuhdc1c84a2013-02-23 16:33:10 -080011#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080012#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080013
Brian Silverman6260c092018-01-14 15:21:36 -080014#if defined(__linux__)
John Park33858a32018-09-28 23:05:48 -070015#include "aos/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080016#endif
John Park33858a32018-09-28 23:05:48 -070017#include "aos/macros.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070018
Austin Schuhe91f14c2017-02-25 19:43:57 -080019template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080020 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080021class StateFeedbackLoop;
22
Brian Silverman5808bcb2014-09-14 21:40:43 -040023// For everything in this file, "inputs" and "outputs" are defined from the
24// perspective of the plant. This means U is an input and Y is an output
25// (because you give the plant U (powers) and it gives you back a Y (sensor
26// values). This is the opposite of what they mean from the perspective of the
27// controller (U is an output because that's what goes to the motors and Y is an
28// input because that's what comes back from the sensors).
29
Austin Schuh20388b62017-11-23 22:40:46 -080030template <int number_of_states, int number_of_inputs, int number_of_outputs,
31 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080032struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080033 public:
34 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
35
Austin Schuhe3490622013-03-13 01:24:30 -070036 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080037 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080038 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080039 C(other.C),
40 D(other.D),
41 U_min(other.U_min),
James Kuszmaul03be1242020-02-21 14:52:04 -080042 U_max(other.U_max),
43 dt(other.dt) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080044
Austin Schuhe3490622013-03-13 01:24:30 -070045 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080046 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080047 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
48 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
49 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
50 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080051 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
52 const std::chrono::nanoseconds dt)
53 : 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 -070054
Austin Schuh20388b62017-11-23 22:40:46 -080055 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080056 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
57 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
58 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
59 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
60 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
James Kuszmaul03be1242020-02-21 14:52:04 -080061 const std::chrono::nanoseconds dt;
Austin Schuhe3490622013-03-13 01:24:30 -070062};
63
Austin Schuh20388b62017-11-23 22:40:46 -080064template <int number_of_states, int number_of_inputs, int number_of_outputs,
65 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070066class StateFeedbackPlant {
67 public:
68 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070069
70 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080071 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080072 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh66c19882017-02-25 13:36:28 -080073 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080074 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070075 Reset();
76 }
77
Tyler Chatow6738c362019-02-16 14:12:30 -080078 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070079 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070080 X_.swap(other.X_);
81 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070082 }
83
Austin Schuh1a387962015-01-31 16:36:20 -080084 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070085
Austin Schuh20388b62017-11-23 22:40:46 -080086 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080087 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070088 }
Austin Schuh20388b62017-11-23 22:40:46 -080089 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -080090 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080091 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070092 }
Austin Schuh20388b62017-11-23 22:40:46 -080093 Scalar B(int i, int j) const { return B()(i, j); }
94 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080095 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -070096 }
Austin Schuh20388b62017-11-23 22:40:46 -080097 Scalar C(int i, int j) const { return C()(i, j); }
98 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080099 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700100 }
Austin Schuh20388b62017-11-23 22:40:46 -0800101 Scalar D(int i, int j) const { return D()(i, j); }
102 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800103 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700104 }
Austin Schuh20388b62017-11-23 22:40:46 -0800105 Scalar U_min(int i, int j) const { return U_min()(i, j); }
106 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800107 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700108 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800109 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700110
Austin Schuh43b9ae92020-02-29 23:08:38 -0800111 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
112
Austin Schuh20388b62017-11-23 22:40:46 -0800113 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800114 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800115 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800116 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700117
Austin Schuh20388b62017-11-23 22:40:46 -0800118 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800119 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800120 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800121 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700122
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800123 size_t coefficients_size() const { return coefficients_.size(); }
124
Austin Schuhb6a6d822016-02-08 00:20:40 -0800125 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800126 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800127 &coefficients(int index) const {
128 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700129 }
130
Austin Schuhc5fceb82017-02-25 16:24:12 -0800131 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800132 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800133 &coefficients() const {
134 return *coefficients_[index_];
135 }
136
137 int index() const { return index_; }
138 void set_index(int index) {
139 assert(index >= 0);
140 assert(index < static_cast<int>(coefficients_.size()));
141 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700142 }
143
144 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700145 X_.setZero();
146 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800147 }
148
Austin Schuh849f0032013-03-03 23:59:53 -0800149 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800150 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400151 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800152 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
153 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800154#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700155 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800156#else
157 abort();
158#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800159 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800160 }
161 }
Austin Schuh849f0032013-03-03 23:59:53 -0800162
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800163 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800164 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800165 // Powers outside of the range are more likely controller bugs than things
166 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800167 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800168 X_ = Update(X(), U);
Austin Schuh01c7b252017-03-05 00:59:31 -0800169 UpdateY(U);
170 }
171
172 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800173 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800174 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800175 }
176
Austin Schuh20388b62017-11-23 22:40:46 -0800177 Eigen::Matrix<Scalar, number_of_states, 1> Update(
178 const Eigen::Matrix<Scalar, number_of_states, 1> X,
179 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800180 return A() * X + B() * U;
181 }
182
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800183 protected:
184 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800185 static const int kNumStates = number_of_states;
186 static const int kNumOutputs = number_of_outputs;
187 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700188
189 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800190 Eigen::Matrix<Scalar, number_of_states, 1> X_;
191 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700192
Austin Schuhb6a6d822016-02-08 00:20:40 -0800193 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800194 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800195 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700196
Austin Schuhc5fceb82017-02-25 16:24:12 -0800197 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700198
199 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800200};
201
Austin Schuh32501832017-02-25 18:32:56 -0800202// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800203template <int number_of_states, int number_of_inputs, int number_of_outputs,
204 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800205struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700206 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700207
Austin Schuh20388b62017-11-23 22:40:46 -0800208 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
209 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700210
Austin Schuh32501832017-02-25 18:32:56 -0800211 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800212 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
213 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800214 : K(K), Kff(Kff) {}
215};
216
Austin Schuh20388b62017-11-23 22:40:46 -0800217template <int number_of_states, int number_of_inputs, int number_of_outputs,
218 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800219class StateFeedbackController {
220 public:
221 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
222
223 explicit StateFeedbackController(
224 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800225 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
226 *controllers)
Austin Schuh32501832017-02-25 18:32:56 -0800227 : coefficients_(::std::move(*controllers)) {}
228
229 StateFeedbackController(StateFeedbackController &&other)
230 : index_(other.index_) {
231 ::std::swap(coefficients_, other.coefficients_);
232 }
233
Austin Schuh20388b62017-11-23 22:40:46 -0800234 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800235 return coefficients().K;
236 }
Austin Schuh20388b62017-11-23 22:40:46 -0800237 Scalar K(int i, int j) const { return K()(i, j); }
238 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800239 return coefficients().Kff;
240 }
Austin Schuh20388b62017-11-23 22:40:46 -0800241 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800242
Austin Schuhe91f14c2017-02-25 19:43:57 -0800243 void Reset() {}
244
Austin Schuh32501832017-02-25 18:32:56 -0800245 // Sets the current controller to be index, clamped to be within range.
246 void set_index(int index) {
247 if (index < 0) {
248 index_ = 0;
249 } else if (index >= static_cast<int>(coefficients_.size())) {
250 index_ = static_cast<int>(coefficients_.size()) - 1;
251 } else {
252 index_ = index;
253 }
254 }
255
256 int index() const { return index_; }
257
258 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800259 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800260 &coefficients(int index) const {
261 return *coefficients_[index];
262 }
263
264 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800265 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800266 &coefficients() const {
267 return *coefficients_[index_];
268 }
269
270 private:
271 int index_ = 0;
272 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800273 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800274 coefficients_;
275};
276
Austin Schuh32501832017-02-25 18:32:56 -0800277// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800278template <int number_of_states, int number_of_inputs, int number_of_outputs,
279 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800280struct StateFeedbackObserverCoefficients final {
281 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
282
Sabina Davis3922dfa2018-02-10 23:10:05 -0800283 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800284 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
285 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800286
287 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800288 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
289 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800290 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
291 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R)
292 : KalmanGain(KalmanGain), Q(Q), R(R) {}
Austin Schuh32501832017-02-25 18:32:56 -0800293};
294
Austin Schuh20388b62017-11-23 22:40:46 -0800295template <int number_of_states, int number_of_inputs, int number_of_outputs,
296 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800297class StateFeedbackObserver {
298 public:
299 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
300
301 explicit StateFeedbackObserver(
302 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800303 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
304 *observers)
Austin Schuh32501832017-02-25 18:32:56 -0800305 : coefficients_(::std::move(*observers)) {}
306
307 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800308 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800309 ::std::swap(coefficients_, other.coefficients_);
310 }
311
Tyler Chatow6738c362019-02-16 14:12:30 -0800312 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
313 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800314 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800315 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800316 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800317
Austin Schuh20388b62017-11-23 22:40:46 -0800318 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800319 return X_hat_;
320 }
Austin Schuh20388b62017-11-23 22:40:46 -0800321 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800322
Austin Schuh6501d232017-11-23 20:35:27 -0800323 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800324 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800325 X_hat_.setZero();
326 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800327
Austin Schuh6501d232017-11-23 20:35:27 -0800328 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800329 number_of_outputs, Scalar> *plant,
330 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800331 ::std::chrono::nanoseconds /*dt*/) {
332 mutable_X_hat() = plant->Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800333 }
334
Austin Schuh6501d232017-11-23 20:35:27 -0800335 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800336 number_of_outputs, Scalar> &plant,
337 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
338 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Tyler Chatow6738c362019-02-16 14:12:30 -0800339 mutable_X_hat() += KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800340 }
341
Austin Schuh32501832017-02-25 18:32:56 -0800342 // Sets the current controller to be index, clamped to be within range.
343 void set_index(int index) {
344 if (index < 0) {
345 index_ = 0;
346 } else if (index >= static_cast<int>(coefficients_.size())) {
347 index_ = static_cast<int>(coefficients_.size()) - 1;
348 } else {
349 index_ = index;
350 }
351 }
352
353 int index() const { return index_; }
354
355 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800356 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800357 &coefficients(int index) const {
358 return *coefficients_[index];
359 }
360
361 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800362 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800363 &coefficients() const {
364 return *coefficients_[index_];
365 }
366
367 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800368 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800369 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800370
Austin Schuh32501832017-02-25 18:32:56 -0800371 int index_ = 0;
372 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800373 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800374 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700375};
376
Austin Schuhe91f14c2017-02-25 19:43:57 -0800377template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800378 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800379 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800380 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800381 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800382 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800383class StateFeedbackLoop {
384 public:
385 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
386
Austin Schuh32501832017-02-25 18:32:56 -0800387 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800388 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800389 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800390 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800391 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800392 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800393 controller_(::std::move(controller)),
394 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700395 Reset();
396 }
397
Austin Schuhc5fceb82017-02-25 16:24:12 -0800398 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800399 : plant_(::std::move(other.plant_)),
400 controller_(::std::move(other.controller_)),
401 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800402 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700403 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800404 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700405 U_.swap(other.U_);
406 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700407 }
408
Austin Schuh1a387962015-01-31 16:36:20 -0800409 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700410
Austin Schuh20388b62017-11-23 22:40:46 -0800411 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800412 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700413 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800414 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800415 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
416 Scalar R(int i, int j) const { return R()(i, j); }
417 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800418 return next_R_;
419 }
Austin Schuh20388b62017-11-23 22:40:46 -0800420 Scalar next_R(int i, int j) const { return next_R()(i, j); }
421 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
422 Scalar U(int i, int j) const { return U()(i, j); }
423 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700424 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700425 }
Austin Schuh20388b62017-11-23 22:40:46 -0800426 Scalar U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
427 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800428 return ff_U_;
429 }
Austin Schuh20388b62017-11-23 22:40:46 -0800430 Scalar ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700431
Austin Schuh20388b62017-11-23 22:40:46 -0800432 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800433 return observer_.mutable_X_hat();
434 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800435 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800436 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
437 Scalar &mutable_R(int i, int j) { return mutable_R()(i, j); }
438 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800439 return next_R_;
440 }
Austin Schuh20388b62017-11-23 22:40:46 -0800441 Scalar &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
442 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
443 Scalar &mutable_U(int i, int j) { return mutable_U()(i, j); }
444 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700445 return U_uncapped_;
446 }
Austin Schuh20388b62017-11-23 22:40:46 -0800447 Scalar &mutable_U_uncapped(int i, int j) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700448 return mutable_U_uncapped()(i, j);
449 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800450
Austin Schuhe91f14c2017-02-25 19:43:57 -0800451 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800452 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800453
Austin Schuh32501832017-02-25 18:32:56 -0800454 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800455 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800456 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800457 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700458 }
459
Austin Schuhe91f14c2017-02-25 19:43:57 -0800460 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700461
Austin Schuh9644e1c2013-03-12 00:40:36 -0700462 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700463 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800464 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700465 U_.setZero();
466 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800467 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800468
469 plant_.Reset();
470 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800471 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800472 }
473
474 // If U is outside the hardware range, limit it before the plant tries to use
475 // it.
476 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400477 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800478 if (U(i, 0) > plant().U_max(i, 0)) {
479 U_(i, 0) = plant().U_max(i, 0);
480 } else if (U(i, 0) < plant().U_min(i, 0)) {
481 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800482 }
483 }
484 }
485
Austin Schuhf9286cd2014-02-11 00:51:09 -0800486 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800487 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800488 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800489 }
490
Austin Schuh20388b62017-11-23 22:40:46 -0800491 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800492 return R() - X_hat();
493 }
494
Austin Schuhb6a6d822016-02-08 00:20:40 -0800495 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800496 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800497 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800498 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800499 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800500 }
501
502 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800503 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800504 // TODO(austin): Should this live in StateSpaceController?
505 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800506 }
507
Austin Schuh43b9ae92020-02-29 23:08:38 -0800508 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800509 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700510 U_.setZero();
511 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800512 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800513 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800514 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800515 CapU();
516 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800517 UpdateFFReference();
518 }
519
520 // stop_motors is whether or not to output all 0s.
521 void Update(bool stop_motors,
522 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
523 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800524
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800525 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800526 }
527
528 // Updates R() after any CapU operations happen on U().
529 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800530 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800531 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800532 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800533 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000534 }
535
Austin Schuh20388b62017-11-23 22:40:46 -0800536 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800537 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800538 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800539 }
540
Austin Schuh32501832017-02-25 18:32:56 -0800541 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800542 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800543 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800544 controller_.set_index(index);
545 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700546 }
547
Austin Schuh32501832017-02-25 18:32:56 -0800548 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700549
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800550 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800551 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800552
Austin Schuh20388b62017-11-23 22:40:46 -0800553 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
554 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800555 controller_;
556
Austin Schuhe91f14c2017-02-25 19:43:57 -0800557 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700558
Brian Silverman273d8a32014-05-10 22:19:09 -0700559 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800560 static constexpr int kNumStates = number_of_states;
561 static constexpr int kNumOutputs = number_of_outputs;
562 static constexpr int kNumInputs = number_of_inputs;
563
564 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800565 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700566
Brian Silverman273d8a32014-05-10 22:19:09 -0700567 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800568 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800569 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800570 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800571 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800572 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800573 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800574 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800575 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700576
Brian Silverman0a151c92014-05-02 15:28:44 -0700577 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800578};
579
Brian Silverman273d8a32014-05-10 22:19:09 -0700580#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_