blob: 2a34de363df2a660c11d52abcc9ac35a058b6ac7 [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>
Brian Silvermanc571e052013-03-13 17:58:56 -070010
Austin Schuhdc1c84a2013-02-23 16:33:10 -080011#include "Eigen/Dense"
12
Austin Schuhcda86af2014-02-16 16:16:39 -080013#include "aos/common/logging/logging.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070014#include "aos/common/macros.h"
15
Austin Schuhe91f14c2017-02-25 19:43:57 -080016template <int number_of_states, int number_of_inputs, int number_of_outputs,
17 typename PlantType, typename ObserverType>
18class StateFeedbackLoop;
19
Brian Silverman5808bcb2014-09-14 21:40:43 -040020// For everything in this file, "inputs" and "outputs" are defined from the
21// perspective of the plant. This means U is an input and Y is an output
22// (because you give the plant U (powers) and it gives you back a Y (sensor
23// values). This is the opposite of what they mean from the perspective of the
24// controller (U is an output because that's what goes to the motors and Y is an
25// input because that's what comes back from the sensors).
26
Austin Schuhdc1c84a2013-02-23 16:33:10 -080027template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh64f17a52017-02-25 14:41:58 -080028struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080029 public:
30 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
31
Austin Schuhe3490622013-03-13 01:24:30 -070032 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080033 : A(other.A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080034 A_inv(other.A_inv),
Austin Schuh64f17a52017-02-25 14:41:58 -080035 A_continuous(other.A_continuous),
36 B(other.B),
37 B_continuous(other.B_continuous),
38 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 Schuh6c20f202017-02-18 22:31:44 -080046 const Eigen::Matrix<double, number_of_states, number_of_states>
47 &A_continuous,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080048 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
Austin Schuh6c20f202017-02-18 22:31:44 -080049 const Eigen::Matrix<double, number_of_states, number_of_inputs>
50 &B_continuous,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080051 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
52 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
Brian Silverman5808bcb2014-09-14 21:40:43 -040053 const Eigen::Matrix<double, number_of_inputs, 1> &U_max,
54 const Eigen::Matrix<double, number_of_inputs, 1> &U_min)
Austin Schuh64f17a52017-02-25 14:41:58 -080055 : A(A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080056 A_inv(A_inv),
Austin Schuh64f17a52017-02-25 14:41:58 -080057 A_continuous(A_continuous),
58 B(B),
59 B_continuous(B_continuous),
60 C(C),
61 D(D),
62 U_min(U_min),
63 U_max(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070064
Austin Schuh64f17a52017-02-25 14:41:58 -080065 const Eigen::Matrix<double, number_of_states, number_of_states> A;
Austin Schuhc5fceb82017-02-25 16:24:12 -080066 const Eigen::Matrix<double, number_of_states, number_of_states> A_inv;
Austin Schuh64f17a52017-02-25 14:41:58 -080067 const Eigen::Matrix<double, number_of_states, number_of_states> A_continuous;
68 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
69 const Eigen::Matrix<double, number_of_states, number_of_inputs> B_continuous;
70 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
71 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
72 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
73 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070074};
75
76template <int number_of_states, int number_of_inputs, int number_of_outputs>
77class StateFeedbackPlant {
78 public:
79 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070080
81 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080082 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh66c19882017-02-25 13:36:28 -080083 number_of_states, number_of_inputs, number_of_outputs>>>
84 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080085 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070086 Reset();
87 }
88
89 StateFeedbackPlant(StateFeedbackPlant &&other)
Austin Schuhc5fceb82017-02-25 16:24:12 -080090 : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070091 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070092 X_.swap(other.X_);
93 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070094 }
95
Austin Schuh1a387962015-01-31 16:36:20 -080096 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070097
Austin Schuhe3490622013-03-13 01:24:30 -070098 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080099 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -0700100 }
101 double A(int i, int j) const { return A()(i, j); }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800102 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv() const {
103 return coefficients().A_inv;
104 }
105 double A_inv(int i, int j) const { return A_inv()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700106 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800107 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700108 }
109 double B(int i, int j) const { return B()(i, j); }
110 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800111 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700112 }
113 double C(int i, int j) const { return C()(i, j); }
114 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800115 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700116 }
117 double D(int i, int j) const { return D()(i, j); }
118 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800119 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700120 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700121 double U_min(int i, int j) const { return U_min()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700122 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800123 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700124 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700125 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700126
127 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700128 double X(int i, int j) const { return X()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700129 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700130 double Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700131
Brian Silverman0ca790b2014-06-12 21:33:08 -0700132 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700133 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700134 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700135 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700136
Austin Schuhb6a6d822016-02-08 00:20:40 -0800137 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800138 number_of_outputs>
139 &coefficients(int index) const {
140 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700141 }
142
Austin Schuhc5fceb82017-02-25 16:24:12 -0800143 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
144 number_of_outputs>
145 &coefficients() const {
146 return *coefficients_[index_];
147 }
148
149 int index() const { return index_; }
150 void set_index(int index) {
151 assert(index >= 0);
152 assert(index < static_cast<int>(coefficients_.size()));
153 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700154 }
155
156 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700157 X_.setZero();
158 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800159 }
160
Austin Schuh849f0032013-03-03 23:59:53 -0800161 // Assert that U is within the hardware range.
Austin Schuh66c19882017-02-25 13:36:28 -0800162 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400163 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh66c19882017-02-25 13:36:28 -0800164 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
165 LOG(FATAL, "U out of range\n");
166 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800167 }
168 }
Austin Schuh849f0032013-03-03 23:59:53 -0800169
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800170 // Computes the new X and Y given the control input.
Austin Schuh66c19882017-02-25 13:36:28 -0800171 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800172 // Powers outside of the range are more likely controller bugs than things
173 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800174 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800175 X_ = Update(X(), U);
Austin Schuh66c19882017-02-25 13:36:28 -0800176 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800177 }
178
Austin Schuhe91f14c2017-02-25 19:43:57 -0800179 Eigen::Matrix<double, number_of_states, 1> Update(
180 const Eigen::Matrix<double, number_of_states, 1> X,
181 const Eigen::Matrix<double, number_of_inputs, 1> &U) {
182 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:
Brian Silverman273d8a32014-05-10 22:19:09 -0700192 Eigen::Matrix<double, number_of_states, 1> X_;
193 Eigen::Matrix<double, 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 Schuh64f17a52017-02-25 14:41:58 -0800196 number_of_states, number_of_inputs, number_of_outputs>>>
197 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 Schuh9644e1c2013-03-12 00:40:36 -0700205template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800206struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700207 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700208
Brian Silverman5808bcb2014-09-14 21:40:43 -0400209 const Eigen::Matrix<double, number_of_inputs, number_of_states> K;
Austin Schuh86093ad2016-02-06 14:29:34 -0800210 const Eigen::Matrix<double, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700211
Austin Schuh32501832017-02-25 18:32:56 -0800212 StateFeedbackControllerCoefficients(
Brian Silverman5808bcb2014-09-14 21:40:43 -0400213 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800214 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800215 : K(K), Kff(Kff) {}
216};
217
218template <int number_of_states, int number_of_inputs, int number_of_outputs>
219class StateFeedbackController {
220 public:
221 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
222
223 explicit StateFeedbackController(
224 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
225 number_of_states, number_of_inputs, number_of_outputs>>> *controllers)
226 : coefficients_(::std::move(*controllers)) {}
227
228 StateFeedbackController(StateFeedbackController &&other)
229 : index_(other.index_) {
230 ::std::swap(coefficients_, other.coefficients_);
231 }
232
233 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K() const {
234 return coefficients().K;
235 }
236 double K(int i, int j) const { return K()(i, j); }
237 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff() const {
238 return coefficients().Kff;
239 }
240 double Kff(int i, int j) const { return Kff()(i, j); }
241 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
242 return coefficients().L;
243 }
244 double L(int i, int j) const { return L()(i, j); }
245
Austin Schuhe91f14c2017-02-25 19:43:57 -0800246 void Reset() {}
247
Austin Schuh32501832017-02-25 18:32:56 -0800248 // Sets the current controller to be index, clamped to be within range.
249 void set_index(int index) {
250 if (index < 0) {
251 index_ = 0;
252 } else if (index >= static_cast<int>(coefficients_.size())) {
253 index_ = static_cast<int>(coefficients_.size()) - 1;
254 } else {
255 index_ = index;
256 }
257 }
258
259 int index() const { return index_; }
260
261 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
262 number_of_outputs>
263 &coefficients(int index) const {
264 return *coefficients_[index];
265 }
266
267 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
268 number_of_outputs>
269 &coefficients() const {
270 return *coefficients_[index_];
271 }
272
273 private:
274 int index_ = 0;
275 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
276 number_of_states, number_of_inputs, number_of_outputs>>>
277 coefficients_;
278};
279
280
281// A container for all the observer coefficients.
282template <int number_of_states, int number_of_inputs, int number_of_outputs>
283struct StateFeedbackObserverCoefficients final {
284 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
285
286 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
287
288 StateFeedbackObserverCoefficients(
289 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L)
290 : L(L) {}
291};
292
293template <int number_of_states, int number_of_inputs, int number_of_outputs>
294class StateFeedbackObserver {
295 public:
296 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
297
298 explicit StateFeedbackObserver(
299 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
300 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
301 : 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
308 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
309 return coefficients().L;
310 }
311 double L(int i, int j) const { return L()(i, j); }
312
Austin Schuhe91f14c2017-02-25 19:43:57 -0800313 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
314 return X_hat_;
315 }
316 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
317
318 void Reset() { X_hat_.setZero(); }
319
320 void Predict(const StateFeedbackLoop<
321 number_of_states, number_of_inputs, number_of_outputs,
322 StateFeedbackPlant<number_of_states, number_of_inputs,
323 number_of_outputs>,
324 StateFeedbackObserver> &loop,
325 const Eigen::Matrix<double, number_of_inputs, 1> &new_u) {
326 mutable_X_hat() = loop.plant().A() * X_hat() + loop.plant().B() * new_u;
327 }
328
329 void Correct(const StateFeedbackLoop<
330 number_of_states, number_of_inputs, number_of_outputs,
331 StateFeedbackPlant<number_of_states, number_of_inputs,
332 number_of_outputs>,
333 StateFeedbackObserver> &loop,
334 const Eigen::Matrix<double, number_of_inputs, 1> &U,
335 const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
336 mutable_X_hat() += loop.plant().A_inv() * L() *
337 (Y - loop.plant().C() * X_hat() - loop.plant().D() * U);
338 }
339
Austin Schuh32501832017-02-25 18:32:56 -0800340 // Sets the current controller to be index, clamped to be within range.
341 void set_index(int index) {
342 if (index < 0) {
343 index_ = 0;
344 } else if (index >= static_cast<int>(coefficients_.size())) {
345 index_ = static_cast<int>(coefficients_.size()) - 1;
346 } else {
347 index_ = index;
348 }
349 }
350
351 int index() const { return index_; }
352
353 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
354 number_of_outputs>
355 &coefficients(int index) const {
356 return *coefficients_[index];
357 }
358
359 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
360 number_of_outputs>
361 &coefficients() const {
362 return *coefficients_[index_];
363 }
364
365 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800366 // Internal state estimate.
367 Eigen::Matrix<double, number_of_states, 1> X_hat_;
368
Austin Schuh32501832017-02-25 18:32:56 -0800369 int index_ = 0;
370 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
371 number_of_states, number_of_inputs, number_of_outputs>>>
372 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700373};
374
Austin Schuhe91f14c2017-02-25 19:43:57 -0800375template <int number_of_states, int number_of_inputs, int number_of_outputs,
376 typename PlantType = StateFeedbackPlant<
377 number_of_states, number_of_inputs, number_of_outputs>,
378 typename ObserverType = StateFeedbackObserver<
379 number_of_states, number_of_inputs, number_of_outputs>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800380class StateFeedbackLoop {
381 public:
382 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
383
Austin Schuh32501832017-02-25 18:32:56 -0800384 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800385 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800386 StateFeedbackController<number_of_states, number_of_inputs,
387 number_of_outputs> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800388 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800389 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800390 controller_(::std::move(controller)),
391 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700392 Reset();
393 }
394
Austin Schuhc5fceb82017-02-25 16:24:12 -0800395 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800396 : plant_(::std::move(other.plant_)),
397 controller_(::std::move(other.controller_)),
398 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700399 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800400 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700401 U_.swap(other.U_);
402 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800403 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700404 }
405
Austin Schuh1a387962015-01-31 16:36:20 -0800406 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700407
Austin Schuh9644e1c2013-03-12 00:40:36 -0700408 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
Austin Schuh32501832017-02-25 18:32:56 -0800409 return observer().L();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700410 }
411 double L(int i, int j) const { return L()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700412
413 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800414 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700415 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700416 double X_hat(int i, int j) const { return X_hat()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700417 const Eigen::Matrix<double, number_of_states, 1> &R() const { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700418 double R(int i, int j) const { return R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800419 const Eigen::Matrix<double, number_of_states, 1> &next_R() const {
420 return next_R_;
421 }
422 double next_R(int i, int j) const { return next_R()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700423 const Eigen::Matrix<double, number_of_inputs, 1> &U() const { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700424 double U(int i, int j) const { return U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700425 const Eigen::Matrix<double, number_of_inputs, 1> &U_uncapped() const {
426 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700427 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700428 double U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800429 const Eigen::Matrix<double, number_of_inputs, 1> &ff_U() const {
430 return ff_U_;
431 }
432 double ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700433
Austin Schuhe91f14c2017-02-25 19:43:57 -0800434 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() {
435 return observer_.mutable_X_hat();
436 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700437 double &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700438 Eigen::Matrix<double, number_of_states, 1> &mutable_R() { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700439 double &mutable_R(int i, int j) { return mutable_R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800440 Eigen::Matrix<double, number_of_states, 1> &mutable_next_R() {
441 return next_R_;
442 }
443 double &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700444 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U() { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700445 double &mutable_U(int i, int j) { return mutable_U()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700446 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700447 return U_uncapped_;
448 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700449 double &mutable_U_uncapped(int i, int j) {
450 return mutable_U_uncapped()(i, j);
451 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800452
Austin Schuhe91f14c2017-02-25 19:43:57 -0800453 const PlantType &plant() const { return plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800454
Austin Schuh32501832017-02-25 18:32:56 -0800455 const StateFeedbackController<number_of_states, number_of_inputs,
456 number_of_outputs>
Austin Schuh66c19882017-02-25 13:36:28 -0800457 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800458 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700459 }
460
Austin Schuhe91f14c2017-02-25 19:43:57 -0800461 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700462
Austin Schuh9644e1c2013-03-12 00:40:36 -0700463 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700464 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800465 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700466 U_.setZero();
467 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800468 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800469
470 plant_.Reset();
471 controller_.Reset();
472 observer_.Reset();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800473 }
474
475 // If U is outside the hardware range, limit it before the plant tries to use
476 // it.
477 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400478 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800479 if (U(i, 0) > plant().U_max(i, 0)) {
480 U_(i, 0) = plant().U_max(i, 0);
481 } else if (U(i, 0) < plant().U_min(i, 0)) {
482 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800483 }
484 }
485 }
486
Austin Schuhf9286cd2014-02-11 00:51:09 -0800487 // Corrects X_hat given the observation in Y.
488 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800489 observer_.Correct(*this, U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800490 }
491
Austin Schuh3f862bb2016-02-27 14:48:05 -0800492 const Eigen::Matrix<double, number_of_states, 1> error() const {
493 return R() - X_hat();
494 }
495
Austin Schuhb6a6d822016-02-08 00:20:40 -0800496 // Returns the calculated controller power.
497 virtual const Eigen::Matrix<double, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800498 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800499 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800500 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800501 }
502
503 // Calculates the feed forwards power.
504 virtual const Eigen::Matrix<double, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800505 // TODO(austin): Should this live in StateSpaceController?
506 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800507 }
508
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800509 // stop_motors is whether or not to output all 0s.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800510 void Update(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800511 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700512 U_.setZero();
513 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800514 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800515 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800516 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800517 CapU();
518 }
519
Austin Schuhc2b77742015-11-26 16:18:27 -0800520 UpdateObserver(U_);
Austin Schuh093535c2016-03-05 23:21:00 -0800521
522 UpdateFFReference();
523 }
524
525 // Updates R() after any CapU operations happen on U().
526 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800527 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800528 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800529 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800530 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000531 }
532
Austin Schuhc2b77742015-11-26 16:18:27 -0800533 void UpdateObserver(const Eigen::Matrix<double, number_of_inputs, 1> &new_u) {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800534 observer_.Predict(*this, new_u);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800535 }
536
Austin Schuh32501832017-02-25 18:32:56 -0800537 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800538 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800539 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800540 controller_.set_index(index);
541 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700542 }
543
Austin Schuh32501832017-02-25 18:32:56 -0800544 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700545
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800546 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800547 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800548
Austin Schuh32501832017-02-25 18:32:56 -0800549 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs>
550 controller_;
551
Austin Schuhe91f14c2017-02-25 19:43:57 -0800552 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700553
Brian Silverman273d8a32014-05-10 22:19:09 -0700554 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800555 static constexpr int kNumStates = number_of_states;
556 static constexpr int kNumOutputs = number_of_outputs;
557 static constexpr int kNumInputs = number_of_inputs;
558
559 // Portion of U which is based on the feed-forwards.
560 Eigen::Matrix<double, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700561
Brian Silverman273d8a32014-05-10 22:19:09 -0700562 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800563 // Current goal (Used by the feed-back controller).
Brian Silverman273d8a32014-05-10 22:19:09 -0700564 Eigen::Matrix<double, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800565 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
566 Eigen::Matrix<double, number_of_states, 1> next_R_;
567 // Computed output after being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700568 Eigen::Matrix<double, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800569 // Computed output before being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700570 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped_;
571
Austin Schuhc5fceb82017-02-25 16:24:12 -0800572 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700573
Brian Silverman0a151c92014-05-02 15:28:44 -0700574 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800575};
576
Brian Silverman273d8a32014-05-10 22:19:09 -0700577#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_