blob: 34a0fcfa068b189c8551b044f160f87cf15ebd42 [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
Austin Schuhcda86af2014-02-16 16:16:39 -080015#include "aos/common/logging/logging.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070016#include "aos/common/macros.h"
17
Austin Schuhe91f14c2017-02-25 19:43:57 -080018template <int number_of_states, int number_of_inputs, int number_of_outputs,
19 typename PlantType, typename ObserverType>
20class 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 Schuhdc1c84a2013-02-23 16:33:10 -080029template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh64f17a52017-02-25 14:41:58 -080030struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080031 public:
32 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
33
Austin Schuhe3490622013-03-13 01:24:30 -070034 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080035 : A(other.A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080036 A_inv(other.A_inv),
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),
41 U_max(other.U_max) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080042
Austin Schuhe3490622013-03-13 01:24:30 -070043 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080044 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
Austin Schuhc5fceb82017-02-25 16:24:12 -080045 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080046 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
47 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
48 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
Brian Silverman5808bcb2014-09-14 21:40:43 -040049 const Eigen::Matrix<double, number_of_inputs, 1> &U_max,
50 const Eigen::Matrix<double, number_of_inputs, 1> &U_min)
Austin Schuh3ad5ed82017-02-25 21:36:19 -080051 : 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 -070052
Austin Schuh64f17a52017-02-25 14:41:58 -080053 const Eigen::Matrix<double, number_of_states, number_of_states> A;
Austin Schuhc5fceb82017-02-25 16:24:12 -080054 const Eigen::Matrix<double, number_of_states, number_of_states> A_inv;
Austin Schuh64f17a52017-02-25 14:41:58 -080055 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
Austin Schuh64f17a52017-02-25 14:41:58 -080056 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
57 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
58 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
59 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070060};
61
62template <int number_of_states, int number_of_inputs, int number_of_outputs>
63class StateFeedbackPlant {
64 public:
65 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070066
67 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080068 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh66c19882017-02-25 13:36:28 -080069 number_of_states, number_of_inputs, number_of_outputs>>>
70 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080071 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070072 Reset();
73 }
74
75 StateFeedbackPlant(StateFeedbackPlant &&other)
Austin Schuhc5fceb82017-02-25 16:24:12 -080076 : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070077 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070078 X_.swap(other.X_);
79 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070080 }
81
Austin Schuh1a387962015-01-31 16:36:20 -080082 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070083
Austin Schuhe3490622013-03-13 01:24:30 -070084 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080085 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070086 }
87 double A(int i, int j) const { return A()(i, j); }
Austin Schuhc5fceb82017-02-25 16:24:12 -080088 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv() const {
89 return coefficients().A_inv;
90 }
91 double A_inv(int i, int j) const { return A_inv()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -070092 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080093 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070094 }
95 double B(int i, int j) const { return B()(i, j); }
96 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080097 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -070098 }
99 double C(int i, int j) const { return C()(i, j); }
100 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800101 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700102 }
103 double D(int i, int j) const { return D()(i, j); }
104 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800105 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700106 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700107 double U_min(int i, int j) const { return U_min()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700108 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800109 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700110 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700111 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700112
113 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700114 double X(int i, int j) const { return X()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700115 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700116 double Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700117
Brian Silverman0ca790b2014-06-12 21:33:08 -0700118 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700119 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700120 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700121 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700122
Austin Schuhb6a6d822016-02-08 00:20:40 -0800123 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800124 number_of_outputs>
125 &coefficients(int index) const {
126 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700127 }
128
Austin Schuhc5fceb82017-02-25 16:24:12 -0800129 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
130 number_of_outputs>
131 &coefficients() const {
132 return *coefficients_[index_];
133 }
134
135 int index() const { return index_; }
136 void set_index(int index) {
137 assert(index >= 0);
138 assert(index < static_cast<int>(coefficients_.size()));
139 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700140 }
141
142 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700143 X_.setZero();
144 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800145 }
146
Austin Schuh849f0032013-03-03 23:59:53 -0800147 // Assert that U is within the hardware range.
Austin Schuh66c19882017-02-25 13:36:28 -0800148 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400149 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh66c19882017-02-25 13:36:28 -0800150 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
151 LOG(FATAL, "U out of range\n");
152 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800153 }
154 }
Austin Schuh849f0032013-03-03 23:59:53 -0800155
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800156 // Computes the new X and Y given the control input.
Austin Schuh66c19882017-02-25 13:36:28 -0800157 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800158 // Powers outside of the range are more likely controller bugs than things
159 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800160 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800161 X_ = Update(X(), U);
Austin Schuh01c7b252017-03-05 00:59:31 -0800162 UpdateY(U);
163 }
164
165 // Computes the new Y given the control input.
166 void UpdateY(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800167 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800168 }
169
Austin Schuhe91f14c2017-02-25 19:43:57 -0800170 Eigen::Matrix<double, number_of_states, 1> Update(
171 const Eigen::Matrix<double, number_of_states, 1> X,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800172 const Eigen::Matrix<double, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800173 return A() * X + B() * U;
174 }
175
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800176 protected:
177 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800178 static const int kNumStates = number_of_states;
179 static const int kNumOutputs = number_of_outputs;
180 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700181
182 private:
Brian Silverman273d8a32014-05-10 22:19:09 -0700183 Eigen::Matrix<double, number_of_states, 1> X_;
184 Eigen::Matrix<double, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700185
Austin Schuhb6a6d822016-02-08 00:20:40 -0800186 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh64f17a52017-02-25 14:41:58 -0800187 number_of_states, number_of_inputs, number_of_outputs>>>
188 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700189
Austin Schuhc5fceb82017-02-25 16:24:12 -0800190 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700191
192 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800193};
194
Austin Schuh32501832017-02-25 18:32:56 -0800195// A container for all the controller coefficients.
Austin Schuh9644e1c2013-03-12 00:40:36 -0700196template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800197struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700198 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700199
Brian Silverman5808bcb2014-09-14 21:40:43 -0400200 const Eigen::Matrix<double, number_of_inputs, number_of_states> K;
Austin Schuh86093ad2016-02-06 14:29:34 -0800201 const Eigen::Matrix<double, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700202
Austin Schuh32501832017-02-25 18:32:56 -0800203 StateFeedbackControllerCoefficients(
Brian Silverman5808bcb2014-09-14 21:40:43 -0400204 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800205 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800206 : K(K), Kff(Kff) {}
207};
208
209template <int number_of_states, int number_of_inputs, int number_of_outputs>
210class StateFeedbackController {
211 public:
212 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
213
214 explicit StateFeedbackController(
215 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
216 number_of_states, number_of_inputs, number_of_outputs>>> *controllers)
217 : coefficients_(::std::move(*controllers)) {}
218
219 StateFeedbackController(StateFeedbackController &&other)
220 : index_(other.index_) {
221 ::std::swap(coefficients_, other.coefficients_);
222 }
223
224 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K() const {
225 return coefficients().K;
226 }
227 double K(int i, int j) const { return K()(i, j); }
228 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff() const {
229 return coefficients().Kff;
230 }
231 double Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800232
Austin Schuhe91f14c2017-02-25 19:43:57 -0800233 void Reset() {}
234
Austin Schuh32501832017-02-25 18:32:56 -0800235 // Sets the current controller to be index, clamped to be within range.
236 void set_index(int index) {
237 if (index < 0) {
238 index_ = 0;
239 } else if (index >= static_cast<int>(coefficients_.size())) {
240 index_ = static_cast<int>(coefficients_.size()) - 1;
241 } else {
242 index_ = index;
243 }
244 }
245
246 int index() const { return index_; }
247
248 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
249 number_of_outputs>
250 &coefficients(int index) const {
251 return *coefficients_[index];
252 }
253
254 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
255 number_of_outputs>
256 &coefficients() const {
257 return *coefficients_[index_];
258 }
259
260 private:
261 int index_ = 0;
262 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
263 number_of_states, number_of_inputs, number_of_outputs>>>
264 coefficients_;
265};
266
Austin Schuh32501832017-02-25 18:32:56 -0800267// A container for all the observer coefficients.
268template <int number_of_states, int number_of_inputs, int number_of_outputs>
269struct StateFeedbackObserverCoefficients final {
270 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
271
272 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
273
274 StateFeedbackObserverCoefficients(
275 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L)
276 : L(L) {}
277};
278
279template <int number_of_states, int number_of_inputs, int number_of_outputs>
280class StateFeedbackObserver {
281 public:
282 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
283
284 explicit StateFeedbackObserver(
285 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
286 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
287 : coefficients_(::std::move(*observers)) {}
288
289 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800290 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800291 ::std::swap(coefficients_, other.coefficients_);
292 }
293
294 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
295 return coefficients().L;
296 }
297 double L(int i, int j) const { return L()(i, j); }
298
Austin Schuhe91f14c2017-02-25 19:43:57 -0800299 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
300 return X_hat_;
301 }
302 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
303
Austin Schuh6501d232017-11-23 20:35:27 -0800304 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
305 number_of_outputs> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800306 X_hat_.setZero();
307 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800308
Austin Schuh6501d232017-11-23 20:35:27 -0800309 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
310 number_of_outputs> *plant,
311 const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
312 ::std::chrono::nanoseconds /*dt*/) {
313 mutable_X_hat() = plant->Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800314 }
315
Austin Schuh6501d232017-11-23 20:35:27 -0800316 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
317 number_of_outputs> &plant,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800318 const Eigen::Matrix<double, number_of_inputs, 1> &U,
319 const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800320 mutable_X_hat() +=
321 plant.A_inv() * L() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800322 }
323
Austin Schuh32501832017-02-25 18:32:56 -0800324 // Sets the current controller to be index, clamped to be within range.
325 void set_index(int index) {
326 if (index < 0) {
327 index_ = 0;
328 } else if (index >= static_cast<int>(coefficients_.size())) {
329 index_ = static_cast<int>(coefficients_.size()) - 1;
330 } else {
331 index_ = index;
332 }
333 }
334
335 int index() const { return index_; }
336
337 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
338 number_of_outputs>
339 &coefficients(int index) const {
340 return *coefficients_[index];
341 }
342
343 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
344 number_of_outputs>
345 &coefficients() const {
346 return *coefficients_[index_];
347 }
348
349 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800350 // Internal state estimate.
351 Eigen::Matrix<double, number_of_states, 1> X_hat_;
352
Austin Schuh32501832017-02-25 18:32:56 -0800353 int index_ = 0;
354 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
355 number_of_states, number_of_inputs, number_of_outputs>>>
356 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700357};
358
Austin Schuhe91f14c2017-02-25 19:43:57 -0800359template <int number_of_states, int number_of_inputs, int number_of_outputs,
360 typename PlantType = StateFeedbackPlant<
361 number_of_states, number_of_inputs, number_of_outputs>,
362 typename ObserverType = StateFeedbackObserver<
363 number_of_states, number_of_inputs, number_of_outputs>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800364class StateFeedbackLoop {
365 public:
366 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
367
Austin Schuh32501832017-02-25 18:32:56 -0800368 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800369 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800370 StateFeedbackController<number_of_states, number_of_inputs,
371 number_of_outputs> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800372 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800373 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800374 controller_(::std::move(controller)),
375 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700376 Reset();
377 }
378
Austin Schuhc5fceb82017-02-25 16:24:12 -0800379 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800380 : plant_(::std::move(other.plant_)),
381 controller_(::std::move(other.controller_)),
382 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700383 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800384 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700385 U_.swap(other.U_);
386 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800387 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700388 }
389
Austin Schuh1a387962015-01-31 16:36:20 -0800390 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700391
Brian Silverman273d8a32014-05-10 22:19:09 -0700392 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800393 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700394 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700395 double X_hat(int i, int j) const { return X_hat()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700396 const Eigen::Matrix<double, number_of_states, 1> &R() const { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700397 double R(int i, int j) const { return R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800398 const Eigen::Matrix<double, number_of_states, 1> &next_R() const {
399 return next_R_;
400 }
401 double next_R(int i, int j) const { return next_R()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700402 const Eigen::Matrix<double, number_of_inputs, 1> &U() const { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700403 double U(int i, int j) const { return U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700404 const Eigen::Matrix<double, number_of_inputs, 1> &U_uncapped() const {
405 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700406 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700407 double U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800408 const Eigen::Matrix<double, number_of_inputs, 1> &ff_U() const {
409 return ff_U_;
410 }
411 double ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700412
Austin Schuhe91f14c2017-02-25 19:43:57 -0800413 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() {
414 return observer_.mutable_X_hat();
415 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700416 double &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700417 Eigen::Matrix<double, number_of_states, 1> &mutable_R() { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700418 double &mutable_R(int i, int j) { return mutable_R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800419 Eigen::Matrix<double, number_of_states, 1> &mutable_next_R() {
420 return next_R_;
421 }
422 double &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700423 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U() { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700424 double &mutable_U(int i, int j) { return mutable_U()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700425 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700426 return U_uncapped_;
427 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700428 double &mutable_U_uncapped(int i, int j) {
429 return mutable_U_uncapped()(i, j);
430 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800431
Austin Schuhe91f14c2017-02-25 19:43:57 -0800432 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800433 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800434
Austin Schuh32501832017-02-25 18:32:56 -0800435 const StateFeedbackController<number_of_states, number_of_inputs,
436 number_of_outputs>
Austin Schuh66c19882017-02-25 13:36:28 -0800437 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800438 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700439 }
440
Austin Schuhe91f14c2017-02-25 19:43:57 -0800441 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700442
Austin Schuh9644e1c2013-03-12 00:40:36 -0700443 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700444 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800445 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700446 U_.setZero();
447 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800448 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800449
450 plant_.Reset();
451 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800452 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800453 }
454
455 // If U is outside the hardware range, limit it before the plant tries to use
456 // it.
457 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400458 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800459 if (U(i, 0) > plant().U_max(i, 0)) {
460 U_(i, 0) = plant().U_max(i, 0);
461 } else if (U(i, 0) < plant().U_min(i, 0)) {
462 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800463 }
464 }
465 }
466
Austin Schuhf9286cd2014-02-11 00:51:09 -0800467 // Corrects X_hat given the observation in Y.
468 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800469 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800470 }
471
Austin Schuh3f862bb2016-02-27 14:48:05 -0800472 const Eigen::Matrix<double, number_of_states, 1> error() const {
473 return R() - X_hat();
474 }
475
Austin Schuhb6a6d822016-02-08 00:20:40 -0800476 // Returns the calculated controller power.
477 virtual const Eigen::Matrix<double, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800478 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800479 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800480 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800481 }
482
483 // Calculates the feed forwards power.
484 virtual const Eigen::Matrix<double, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800485 // TODO(austin): Should this live in StateSpaceController?
486 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800487 }
488
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800489 // stop_motors is whether or not to output all 0s.
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800490 void Update(bool stop_motors,
491 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(5)) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800492 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700493 U_.setZero();
494 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800495 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800496 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800497 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800498 CapU();
499 }
500
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800501 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800502
503 UpdateFFReference();
504 }
505
506 // Updates R() after any CapU operations happen on U().
507 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800508 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800509 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800510 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800511 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000512 }
513
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800514 void UpdateObserver(const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
515 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800516 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800517 }
518
Austin Schuh32501832017-02-25 18:32:56 -0800519 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800520 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800521 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800522 controller_.set_index(index);
523 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700524 }
525
Austin Schuh32501832017-02-25 18:32:56 -0800526 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700527
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800528 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800529 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800530
Austin Schuh32501832017-02-25 18:32:56 -0800531 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs>
532 controller_;
533
Austin Schuhe91f14c2017-02-25 19:43:57 -0800534 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700535
Brian Silverman273d8a32014-05-10 22:19:09 -0700536 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800537 static constexpr int kNumStates = number_of_states;
538 static constexpr int kNumOutputs = number_of_outputs;
539 static constexpr int kNumInputs = number_of_inputs;
540
541 // Portion of U which is based on the feed-forwards.
542 Eigen::Matrix<double, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700543
Brian Silverman273d8a32014-05-10 22:19:09 -0700544 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800545 // Current goal (Used by the feed-back controller).
Brian Silverman273d8a32014-05-10 22:19:09 -0700546 Eigen::Matrix<double, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800547 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
548 Eigen::Matrix<double, number_of_states, 1> next_R_;
549 // Computed output after being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700550 Eigen::Matrix<double, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800551 // Computed output before being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700552 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped_;
553
Brian Silverman0a151c92014-05-02 15:28:44 -0700554 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800555};
556
Brian Silverman273d8a32014-05-10 22:19:09 -0700557#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_