blob: a1e6cd4aabe878696d2f71e29f5c88870909cdc2 [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
Austin Schuhcda86af2014-02-16 16:16:39 -08006#include <iostream>
Austin Schuhc5fceb82017-02-25 16:24:12 -08007#include <memory>
8#include <utility>
9#include <vector>
Austin Schuh3ad5ed82017-02-25 21:36:19 -080010#include <chrono>
Brian Silvermanc571e052013-03-13 17:58:56 -070011
Austin Schuhdc1c84a2013-02-23 16:33:10 -080012#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080013#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080014
Brian Silverman6260c092018-01-14 15:21:36 -080015#if defined(__linux__)
Austin Schuhcda86af2014-02-16 16:16:39 -080016#include "aos/common/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080017#endif
Brian Silverman0a151c92014-05-02 15:28:44 -070018#include "aos/common/macros.h"
19
Austin Schuhe91f14c2017-02-25 19:43:57 -080020template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080021 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080022class StateFeedbackLoop;
23
Brian Silverman5808bcb2014-09-14 21:40:43 -040024// For everything in this file, "inputs" and "outputs" are defined from the
25// perspective of the plant. This means U is an input and Y is an output
26// (because you give the plant U (powers) and it gives you back a Y (sensor
27// values). This is the opposite of what they mean from the perspective of the
28// controller (U is an output because that's what goes to the motors and Y is an
29// input because that's what comes back from the sensors).
30
Austin Schuh20388b62017-11-23 22:40:46 -080031template <int number_of_states, int number_of_inputs, int number_of_outputs,
32 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080033struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080034 public:
35 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
36
Austin Schuhe3490622013-03-13 01:24:30 -070037 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080038 : A(other.A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080039 A_inv(other.A_inv),
Austin Schuh64f17a52017-02-25 14:41:58 -080040 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080041 C(other.C),
42 D(other.D),
43 U_min(other.U_min),
44 U_max(other.U_max) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080045
Austin Schuhe3490622013-03-13 01:24:30 -070046 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080047 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
48 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A_inv,
49 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
50 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
51 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
52 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
53 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min)
Austin Schuh3ad5ed82017-02-25 21:36:19 -080054 : A(A), A_inv(A_inv), B(B), C(C), D(D), U_min(U_min), U_max(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070055
Austin Schuh20388b62017-11-23 22:40:46 -080056 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
57 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A_inv;
58 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
59 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
60 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
61 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
62 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070063};
64
Austin Schuh20388b62017-11-23 22:40:46 -080065template <int number_of_states, int number_of_inputs, int number_of_outputs,
66 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070067class StateFeedbackPlant {
68 public:
69 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070070
71 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080072 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080073 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh66c19882017-02-25 13:36:28 -080074 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080075 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070076 Reset();
77 }
78
79 StateFeedbackPlant(StateFeedbackPlant &&other)
Austin Schuhc5fceb82017-02-25 16:24:12 -080080 : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070081 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070082 X_.swap(other.X_);
83 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070084 }
85
Austin Schuh1a387962015-01-31 16:36:20 -080086 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070087
Austin Schuh20388b62017-11-23 22:40:46 -080088 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080089 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070090 }
Austin Schuh20388b62017-11-23 22:40:46 -080091 Scalar A(int i, int j) const { return A()(i, j); }
92 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A_inv() const {
Austin Schuhc5fceb82017-02-25 16:24:12 -080093 return coefficients().A_inv;
94 }
Austin Schuh20388b62017-11-23 22:40:46 -080095 Scalar A_inv(int i, int j) const { return A_inv()(i, j); }
96 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080097 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070098 }
Austin Schuh20388b62017-11-23 22:40:46 -080099 Scalar B(int i, int j) const { return B()(i, j); }
100 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800101 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700102 }
Austin Schuh20388b62017-11-23 22:40:46 -0800103 Scalar C(int i, int j) const { return C()(i, j); }
104 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800105 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700106 }
Austin Schuh20388b62017-11-23 22:40:46 -0800107 Scalar D(int i, int j) const { return D()(i, j); }
108 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800109 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700110 }
Austin Schuh20388b62017-11-23 22:40:46 -0800111 Scalar U_min(int i, int j) const { return U_min()(i, j); }
112 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800113 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700114 }
Austin Schuh20388b62017-11-23 22:40:46 -0800115 Scalar U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700116
Austin Schuh20388b62017-11-23 22:40:46 -0800117 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
118 Scalar X(int i, int j) const { return X()(i, j); }
119 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
120 Scalar Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700121
Austin Schuh20388b62017-11-23 22:40:46 -0800122 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
123 Scalar &mutable_X(int i, int j) { return mutable_X()(i, j); }
124 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
125 Scalar &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700126
Austin Schuhb6a6d822016-02-08 00:20:40 -0800127 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800128 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800129 &coefficients(int index) const {
130 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700131 }
132
Austin Schuhc5fceb82017-02-25 16:24:12 -0800133 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800134 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800135 &coefficients() const {
136 return *coefficients_[index_];
137 }
138
139 int index() const { return index_; }
140 void set_index(int index) {
141 assert(index >= 0);
142 assert(index < static_cast<int>(coefficients_.size()));
143 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700144 }
145
146 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700147 X_.setZero();
148 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800149 }
150
Austin Schuh849f0032013-03-03 23:59:53 -0800151 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800152 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400153 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800154 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
155 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800156#if defined(__linux__)
Austin Schuh66c19882017-02-25 13:36:28 -0800157 LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800158#else
159 abort();
160#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800161 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800162 }
163 }
Austin Schuh849f0032013-03-03 23:59:53 -0800164
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800165 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800166 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800167 // Powers outside of the range are more likely controller bugs than things
168 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800169 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800170 X_ = Update(X(), U);
Austin Schuh01c7b252017-03-05 00:59:31 -0800171 UpdateY(U);
172 }
173
174 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800175 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800176 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800177 }
178
Austin Schuh20388b62017-11-23 22:40:46 -0800179 Eigen::Matrix<Scalar, number_of_states, 1> Update(
180 const Eigen::Matrix<Scalar, number_of_states, 1> X,
181 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800182 return A() * X + B() * U;
183 }
184
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800185 protected:
186 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800187 static const int kNumStates = number_of_states;
188 static const int kNumOutputs = number_of_outputs;
189 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700190
191 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800192 Eigen::Matrix<Scalar, number_of_states, 1> X_;
193 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700194
Austin Schuhb6a6d822016-02-08 00:20:40 -0800195 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800196 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800197 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700198
Austin Schuhc5fceb82017-02-25 16:24:12 -0800199 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700200
201 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800202};
203
Austin Schuh32501832017-02-25 18:32:56 -0800204// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800205template <int number_of_states, int number_of_inputs, int number_of_outputs,
206 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800207struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700208 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700209
Austin Schuh20388b62017-11-23 22:40:46 -0800210 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
211 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700212
Austin Schuh32501832017-02-25 18:32:56 -0800213 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800214 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
215 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800216 : K(K), Kff(Kff) {}
217};
218
Austin Schuh20388b62017-11-23 22:40:46 -0800219template <int number_of_states, int number_of_inputs, int number_of_outputs,
220 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800221class StateFeedbackController {
222 public:
223 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
224
225 explicit StateFeedbackController(
226 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800227 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
228 *controllers)
Austin Schuh32501832017-02-25 18:32:56 -0800229 : coefficients_(::std::move(*controllers)) {}
230
231 StateFeedbackController(StateFeedbackController &&other)
232 : index_(other.index_) {
233 ::std::swap(coefficients_, other.coefficients_);
234 }
235
Austin Schuh20388b62017-11-23 22:40:46 -0800236 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800237 return coefficients().K;
238 }
Austin Schuh20388b62017-11-23 22:40:46 -0800239 Scalar K(int i, int j) const { return K()(i, j); }
240 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800241 return coefficients().Kff;
242 }
Austin Schuh20388b62017-11-23 22:40:46 -0800243 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800244
Austin Schuhe91f14c2017-02-25 19:43:57 -0800245 void Reset() {}
246
Austin Schuh32501832017-02-25 18:32:56 -0800247 // Sets the current controller to be index, clamped to be within range.
248 void set_index(int index) {
249 if (index < 0) {
250 index_ = 0;
251 } else if (index >= static_cast<int>(coefficients_.size())) {
252 index_ = static_cast<int>(coefficients_.size()) - 1;
253 } else {
254 index_ = index;
255 }
256 }
257
258 int index() const { return index_; }
259
260 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800261 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800262 &coefficients(int index) const {
263 return *coefficients_[index];
264 }
265
266 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800267 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800268 &coefficients() const {
269 return *coefficients_[index_];
270 }
271
272 private:
273 int index_ = 0;
274 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800275 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800276 coefficients_;
277};
278
Austin Schuh32501832017-02-25 18:32:56 -0800279// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800280template <int number_of_states, int number_of_inputs, int number_of_outputs,
281 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800282struct StateFeedbackObserverCoefficients final {
283 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
284
Austin Schuh20388b62017-11-23 22:40:46 -0800285 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> L;
Austin Schuh32501832017-02-25 18:32:56 -0800286
287 StateFeedbackObserverCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800288 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &L)
Austin Schuh32501832017-02-25 18:32:56 -0800289 : L(L) {}
290};
291
Austin Schuh20388b62017-11-23 22:40:46 -0800292template <int number_of_states, int number_of_inputs, int number_of_outputs,
293 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800294class StateFeedbackObserver {
295 public:
296 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
297
298 explicit StateFeedbackObserver(
299 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800300 number_of_states, number_of_inputs, number_of_outputs, Scalar>>> *observers)
Austin Schuh32501832017-02-25 18:32:56 -0800301 : coefficients_(::std::move(*observers)) {}
302
303 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800304 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800305 ::std::swap(coefficients_, other.coefficients_);
306 }
307
Austin Schuh20388b62017-11-23 22:40:46 -0800308 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &L() const {
Austin Schuh32501832017-02-25 18:32:56 -0800309 return coefficients().L;
310 }
Austin Schuh20388b62017-11-23 22:40:46 -0800311 Scalar L(int i, int j) const { return L()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800312
Austin Schuh20388b62017-11-23 22:40:46 -0800313 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800314 return X_hat_;
315 }
Austin Schuh20388b62017-11-23 22:40:46 -0800316 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800317
Austin Schuh6501d232017-11-23 20:35:27 -0800318 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800319 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800320 X_hat_.setZero();
321 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800322
Austin Schuh6501d232017-11-23 20:35:27 -0800323 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800324 number_of_outputs, Scalar> *plant,
325 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800326 ::std::chrono::nanoseconds /*dt*/) {
327 mutable_X_hat() = plant->Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800328 }
329
Austin Schuh6501d232017-11-23 20:35:27 -0800330 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800331 number_of_outputs, Scalar> &plant,
332 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
333 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800334 mutable_X_hat() +=
335 plant.A_inv() * L() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800336 }
337
Austin Schuh32501832017-02-25 18:32:56 -0800338 // Sets the current controller to be index, clamped to be within range.
339 void set_index(int index) {
340 if (index < 0) {
341 index_ = 0;
342 } else if (index >= static_cast<int>(coefficients_.size())) {
343 index_ = static_cast<int>(coefficients_.size()) - 1;
344 } else {
345 index_ = index;
346 }
347 }
348
349 int index() const { return index_; }
350
351 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800352 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800353 &coefficients(int index) const {
354 return *coefficients_[index];
355 }
356
357 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800358 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800359 &coefficients() const {
360 return *coefficients_[index_];
361 }
362
363 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800364 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800365 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800366
Austin Schuh32501832017-02-25 18:32:56 -0800367 int index_ = 0;
368 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800369 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800370 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700371};
372
Austin Schuhe91f14c2017-02-25 19:43:57 -0800373template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800374 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800375 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800376 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800377 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800378 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800379class StateFeedbackLoop {
380 public:
381 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
382
Austin Schuh32501832017-02-25 18:32:56 -0800383 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800384 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800385 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800386 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800387 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800388 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800389 controller_(::std::move(controller)),
390 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700391 Reset();
392 }
393
Austin Schuhc5fceb82017-02-25 16:24:12 -0800394 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800395 : plant_(::std::move(other.plant_)),
396 controller_(::std::move(other.controller_)),
397 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700398 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800399 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700400 U_.swap(other.U_);
401 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800402 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700403 }
404
Austin Schuh1a387962015-01-31 16:36:20 -0800405 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700406
Austin Schuh20388b62017-11-23 22:40:46 -0800407 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800408 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700409 }
Austin Schuh20388b62017-11-23 22:40:46 -0800410 Scalar X_hat(int i, int j) const { return X_hat()(i, j); }
411 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
412 Scalar R(int i, int j) const { return R()(i, j); }
413 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800414 return next_R_;
415 }
Austin Schuh20388b62017-11-23 22:40:46 -0800416 Scalar next_R(int i, int j) const { return next_R()(i, j); }
417 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
418 Scalar U(int i, int j) const { return U()(i, j); }
419 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700420 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700421 }
Austin Schuh20388b62017-11-23 22:40:46 -0800422 Scalar U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
423 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800424 return ff_U_;
425 }
Austin Schuh20388b62017-11-23 22:40:46 -0800426 Scalar ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700427
Austin Schuh20388b62017-11-23 22:40:46 -0800428 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800429 return observer_.mutable_X_hat();
430 }
Austin Schuh20388b62017-11-23 22:40:46 -0800431 Scalar &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
432 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
433 Scalar &mutable_R(int i, int j) { return mutable_R()(i, j); }
434 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800435 return next_R_;
436 }
Austin Schuh20388b62017-11-23 22:40:46 -0800437 Scalar &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
438 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
439 Scalar &mutable_U(int i, int j) { return mutable_U()(i, j); }
440 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700441 return U_uncapped_;
442 }
Austin Schuh20388b62017-11-23 22:40:46 -0800443 Scalar &mutable_U_uncapped(int i, int j) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700444 return mutable_U_uncapped()(i, j);
445 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800446
Austin Schuhe91f14c2017-02-25 19:43:57 -0800447 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800448 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800449
Austin Schuh32501832017-02-25 18:32:56 -0800450 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800451 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800452 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800453 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700454 }
455
Austin Schuhe91f14c2017-02-25 19:43:57 -0800456 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700457
Austin Schuh9644e1c2013-03-12 00:40:36 -0700458 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700459 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800460 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700461 U_.setZero();
462 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800463 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800464
465 plant_.Reset();
466 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800467 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800468 }
469
470 // If U is outside the hardware range, limit it before the plant tries to use
471 // it.
472 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400473 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800474 if (U(i, 0) > plant().U_max(i, 0)) {
475 U_(i, 0) = plant().U_max(i, 0);
476 } else if (U(i, 0) < plant().U_min(i, 0)) {
477 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800478 }
479 }
480 }
481
Austin Schuhf9286cd2014-02-11 00:51:09 -0800482 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800483 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800484 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800485 }
486
Austin Schuh20388b62017-11-23 22:40:46 -0800487 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800488 return R() - X_hat();
489 }
490
Austin Schuhb6a6d822016-02-08 00:20:40 -0800491 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800492 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800493 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800494 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800495 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800496 }
497
498 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800499 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800500 // TODO(austin): Should this live in StateSpaceController?
501 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800502 }
503
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800504 // stop_motors is whether or not to output all 0s.
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800505 void Update(bool stop_motors,
506 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(5)) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800507 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700508 U_.setZero();
509 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800510 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800511 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800512 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800513 CapU();
514 }
515
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800516 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800517
518 UpdateFFReference();
519 }
520
521 // Updates R() after any CapU operations happen on U().
522 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800523 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800524 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800525 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800526 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000527 }
528
Austin Schuh20388b62017-11-23 22:40:46 -0800529 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800530 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800531 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800532 }
533
Austin Schuh32501832017-02-25 18:32:56 -0800534 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800535 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800536 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800537 controller_.set_index(index);
538 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700539 }
540
Austin Schuh32501832017-02-25 18:32:56 -0800541 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700542
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800543 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800544 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800545
Austin Schuh20388b62017-11-23 22:40:46 -0800546 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
547 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800548 controller_;
549
Austin Schuhe91f14c2017-02-25 19:43:57 -0800550 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700551
Brian Silverman273d8a32014-05-10 22:19:09 -0700552 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800553 static constexpr int kNumStates = number_of_states;
554 static constexpr int kNumOutputs = number_of_outputs;
555 static constexpr int kNumInputs = number_of_inputs;
556
557 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800558 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700559
Brian Silverman273d8a32014-05-10 22:19:09 -0700560 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800561 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800562 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800563 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800564 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800565 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800566 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800567 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800568 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700569
Brian Silverman0a151c92014-05-02 15:28:44 -0700570 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800571};
572
Brian Silverman273d8a32014-05-10 22:19:09 -0700573#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_