blob: 402585a6eb865353174e67c67f2164af1c0cbd12 [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
Brian Silverman5808bcb2014-09-14 21:40:43 -040016// For everything in this file, "inputs" and "outputs" are defined from the
17// perspective of the plant. This means U is an input and Y is an output
18// (because you give the plant U (powers) and it gives you back a Y (sensor
19// values). This is the opposite of what they mean from the perspective of the
20// controller (U is an output because that's what goes to the motors and Y is an
21// input because that's what comes back from the sensors).
22
Austin Schuhdc1c84a2013-02-23 16:33:10 -080023template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh64f17a52017-02-25 14:41:58 -080024struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080025 public:
26 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
27
Austin Schuhe3490622013-03-13 01:24:30 -070028 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080029 : A(other.A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080030 A_inv(other.A_inv),
Austin Schuh64f17a52017-02-25 14:41:58 -080031 A_continuous(other.A_continuous),
32 B(other.B),
33 B_continuous(other.B_continuous),
34 C(other.C),
35 D(other.D),
36 U_min(other.U_min),
37 U_max(other.U_max) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080038
Austin Schuhe3490622013-03-13 01:24:30 -070039 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080040 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
Austin Schuhc5fceb82017-02-25 16:24:12 -080041 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv,
Austin Schuh6c20f202017-02-18 22:31:44 -080042 const Eigen::Matrix<double, number_of_states, number_of_states>
43 &A_continuous,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080044 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
Austin Schuh6c20f202017-02-18 22:31:44 -080045 const Eigen::Matrix<double, number_of_states, number_of_inputs>
46 &B_continuous,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080047 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 Schuh64f17a52017-02-25 14:41:58 -080051 : A(A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080052 A_inv(A_inv),
Austin Schuh64f17a52017-02-25 14:41:58 -080053 A_continuous(A_continuous),
54 B(B),
55 B_continuous(B_continuous),
56 C(C),
57 D(D),
58 U_min(U_min),
59 U_max(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070060
Austin Schuh64f17a52017-02-25 14:41:58 -080061 const Eigen::Matrix<double, number_of_states, number_of_states> A;
Austin Schuhc5fceb82017-02-25 16:24:12 -080062 const Eigen::Matrix<double, number_of_states, number_of_states> A_inv;
Austin Schuh64f17a52017-02-25 14:41:58 -080063 const Eigen::Matrix<double, number_of_states, number_of_states> A_continuous;
64 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
65 const Eigen::Matrix<double, number_of_states, number_of_inputs> B_continuous;
66 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
67 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
68 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
69 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070070};
71
72template <int number_of_states, int number_of_inputs, int number_of_outputs>
73class StateFeedbackPlant {
74 public:
75 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070076
77 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080078 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh66c19882017-02-25 13:36:28 -080079 number_of_states, number_of_inputs, number_of_outputs>>>
80 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080081 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070082 Reset();
83 }
84
85 StateFeedbackPlant(StateFeedbackPlant &&other)
Austin Schuhc5fceb82017-02-25 16:24:12 -080086 : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070087 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070088 X_.swap(other.X_);
89 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070090 }
91
Austin Schuh1a387962015-01-31 16:36:20 -080092 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070093
Austin Schuhe3490622013-03-13 01:24:30 -070094 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080095 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070096 }
97 double A(int i, int j) const { return A()(i, j); }
Austin Schuhc5fceb82017-02-25 16:24:12 -080098 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv() const {
99 return coefficients().A_inv;
100 }
101 double A_inv(int i, int j) const { return A_inv()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700102 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800103 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700104 }
105 double B(int i, int j) const { return B()(i, j); }
106 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800107 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700108 }
109 double C(int i, int j) const { return C()(i, j); }
110 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800111 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700112 }
113 double D(int i, int j) const { return D()(i, j); }
114 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800115 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700116 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700117 double U_min(int i, int j) const { return U_min()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700118 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800119 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700120 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700121 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700122
123 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700124 double X(int i, int j) const { return X()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700125 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700126 double Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700127
Brian Silverman0ca790b2014-06-12 21:33:08 -0700128 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700129 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700130 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700131 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700132
Austin Schuhb6a6d822016-02-08 00:20:40 -0800133 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800134 number_of_outputs>
135 &coefficients(int index) const {
136 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700137 }
138
Austin Schuhc5fceb82017-02-25 16:24:12 -0800139 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
140 number_of_outputs>
141 &coefficients() const {
142 return *coefficients_[index_];
143 }
144
145 int index() const { return index_; }
146 void set_index(int index) {
147 assert(index >= 0);
148 assert(index < static_cast<int>(coefficients_.size()));
149 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700150 }
151
152 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700153 X_.setZero();
154 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800155 }
156
Austin Schuh849f0032013-03-03 23:59:53 -0800157 // Assert that U is within the hardware range.
Austin Schuh66c19882017-02-25 13:36:28 -0800158 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400159 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh66c19882017-02-25 13:36:28 -0800160 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
161 LOG(FATAL, "U out of range\n");
162 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800163 }
164 }
Austin Schuh849f0032013-03-03 23:59:53 -0800165
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800166 // Computes the new X and Y given the control input.
Austin Schuh66c19882017-02-25 13:36:28 -0800167 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800168 // Powers outside of the range are more likely controller bugs than things
169 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800170 CheckU(U);
171 X_ = A() * X() + B() * U;
172 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800173 }
174
175 protected:
176 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800177 static const int kNumStates = number_of_states;
178 static const int kNumOutputs = number_of_outputs;
179 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700180
181 private:
Brian Silverman273d8a32014-05-10 22:19:09 -0700182 Eigen::Matrix<double, number_of_states, 1> X_;
183 Eigen::Matrix<double, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700184
Austin Schuhb6a6d822016-02-08 00:20:40 -0800185 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh64f17a52017-02-25 14:41:58 -0800186 number_of_states, number_of_inputs, number_of_outputs>>>
187 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700188
Austin Schuhc5fceb82017-02-25 16:24:12 -0800189 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700190
191 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800192};
193
Austin Schuh32501832017-02-25 18:32:56 -0800194// A container for all the controller coefficients.
Austin Schuh9644e1c2013-03-12 00:40:36 -0700195template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800196struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700197 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700198
Brian Silverman5808bcb2014-09-14 21:40:43 -0400199 const Eigen::Matrix<double, number_of_inputs, number_of_states> K;
Austin Schuh86093ad2016-02-06 14:29:34 -0800200 const Eigen::Matrix<double, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700201
Austin Schuh32501832017-02-25 18:32:56 -0800202 StateFeedbackControllerCoefficients(
Brian Silverman5808bcb2014-09-14 21:40:43 -0400203 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800204 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800205 : K(K), Kff(Kff) {}
206};
207
208template <int number_of_states, int number_of_inputs, int number_of_outputs>
209class StateFeedbackController {
210 public:
211 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
212
213 explicit StateFeedbackController(
214 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
215 number_of_states, number_of_inputs, number_of_outputs>>> *controllers)
216 : coefficients_(::std::move(*controllers)) {}
217
218 StateFeedbackController(StateFeedbackController &&other)
219 : index_(other.index_) {
220 ::std::swap(coefficients_, other.coefficients_);
221 }
222
223 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K() const {
224 return coefficients().K;
225 }
226 double K(int i, int j) const { return K()(i, j); }
227 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff() const {
228 return coefficients().Kff;
229 }
230 double Kff(int i, int j) const { return Kff()(i, j); }
231 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
232 return coefficients().L;
233 }
234 double L(int i, int j) const { return L()(i, j); }
235
236 // Sets the current controller to be index, clamped to be within range.
237 void set_index(int index) {
238 if (index < 0) {
239 index_ = 0;
240 } else if (index >= static_cast<int>(coefficients_.size())) {
241 index_ = static_cast<int>(coefficients_.size()) - 1;
242 } else {
243 index_ = index;
244 }
245 }
246
247 int index() const { return index_; }
248
249 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
250 number_of_outputs>
251 &coefficients(int index) const {
252 return *coefficients_[index];
253 }
254
255 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
256 number_of_outputs>
257 &coefficients() const {
258 return *coefficients_[index_];
259 }
260
261 private:
262 int index_ = 0;
263 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
264 number_of_states, number_of_inputs, number_of_outputs>>>
265 coefficients_;
266};
267
268
269// A container for all the observer coefficients.
270template <int number_of_states, int number_of_inputs, int number_of_outputs>
271struct StateFeedbackObserverCoefficients final {
272 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
273
274 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
275
276 StateFeedbackObserverCoefficients(
277 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L)
278 : L(L) {}
279};
280
281template <int number_of_states, int number_of_inputs, int number_of_outputs>
282class StateFeedbackObserver {
283 public:
284 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
285
286 explicit StateFeedbackObserver(
287 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
288 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
289 : coefficients_(::std::move(*observers)) {}
290
291 StateFeedbackObserver(StateFeedbackObserver &&other)
292 : index_(other.index_) {
293 ::std::swap(coefficients_, other.coefficients_);
294 }
295
296 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
297 return coefficients().L;
298 }
299 double L(int i, int j) const { return L()(i, j); }
300
301 // Sets the current controller to be index, clamped to be within range.
302 void set_index(int index) {
303 if (index < 0) {
304 index_ = 0;
305 } else if (index >= static_cast<int>(coefficients_.size())) {
306 index_ = static_cast<int>(coefficients_.size()) - 1;
307 } else {
308 index_ = index;
309 }
310 }
311
312 int index() const { return index_; }
313
314 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
315 number_of_outputs>
316 &coefficients(int index) const {
317 return *coefficients_[index];
318 }
319
320 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
321 number_of_outputs>
322 &coefficients() const {
323 return *coefficients_[index_];
324 }
325
326 private:
327 int index_ = 0;
328 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
329 number_of_states, number_of_inputs, number_of_outputs>>>
330 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700331};
332
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800333template <int number_of_states, int number_of_inputs, int number_of_outputs>
334class StateFeedbackLoop {
335 public:
336 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
337
Austin Schuh32501832017-02-25 18:32:56 -0800338 explicit StateFeedbackLoop(
Austin Schuhc5fceb82017-02-25 16:24:12 -0800339 StateFeedbackPlant<number_of_states, number_of_inputs, number_of_outputs>
340 &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800341 StateFeedbackController<number_of_states, number_of_inputs,
342 number_of_outputs> &&controller,
343 StateFeedbackObserver<number_of_states, number_of_inputs,
344 number_of_outputs> &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800345 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800346 controller_(::std::move(controller)),
347 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700348 Reset();
349 }
350
Austin Schuhc5fceb82017-02-25 16:24:12 -0800351 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800352 : plant_(::std::move(other.plant_)),
353 controller_(::std::move(other.controller_)),
354 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700355 X_hat_.swap(other.X_hat_);
356 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800357 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700358 U_.swap(other.U_);
359 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800360 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700361 }
362
Austin Schuh1a387962015-01-31 16:36:20 -0800363 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700364
Austin Schuh9644e1c2013-03-12 00:40:36 -0700365 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
Austin Schuh32501832017-02-25 18:32:56 -0800366 return observer().L();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700367 }
368 double L(int i, int j) const { return L()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700369
370 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
371 return X_hat_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700372 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700373 double X_hat(int i, int j) const { return X_hat()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700374 const Eigen::Matrix<double, number_of_states, 1> &R() const { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700375 double R(int i, int j) const { return R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800376 const Eigen::Matrix<double, number_of_states, 1> &next_R() const {
377 return next_R_;
378 }
379 double next_R(int i, int j) const { return next_R()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700380 const Eigen::Matrix<double, number_of_inputs, 1> &U() const { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700381 double U(int i, int j) const { return U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700382 const Eigen::Matrix<double, number_of_inputs, 1> &U_uncapped() const {
383 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700384 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700385 double U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800386 const Eigen::Matrix<double, number_of_inputs, 1> &ff_U() const {
387 return ff_U_;
388 }
389 double ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700390
Brian Silverman0ca790b2014-06-12 21:33:08 -0700391 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700392 double &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700393 Eigen::Matrix<double, number_of_states, 1> &mutable_R() { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700394 double &mutable_R(int i, int j) { return mutable_R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800395 Eigen::Matrix<double, number_of_states, 1> &mutable_next_R() {
396 return next_R_;
397 }
398 double &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700399 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U() { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700400 double &mutable_U(int i, int j) { return mutable_U()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700401 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700402 return U_uncapped_;
403 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700404 double &mutable_U_uncapped(int i, int j) {
405 return mutable_U_uncapped()(i, j);
406 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800407
Austin Schuhc5fceb82017-02-25 16:24:12 -0800408 const StateFeedbackPlant<number_of_states, number_of_inputs,
409 number_of_outputs>
410 &plant() const {
411 return plant_;
412 }
413
Austin Schuh32501832017-02-25 18:32:56 -0800414 const StateFeedbackController<number_of_states, number_of_inputs,
415 number_of_outputs>
Austin Schuh66c19882017-02-25 13:36:28 -0800416 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800417 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700418 }
419
Austin Schuh32501832017-02-25 18:32:56 -0800420 const StateFeedbackObserver<number_of_states, number_of_inputs,
421 number_of_outputs>
422 &observer() const {
423 return observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700424 }
425
Austin Schuh9644e1c2013-03-12 00:40:36 -0700426 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700427 X_hat_.setZero();
428 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800429 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700430 U_.setZero();
431 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800432 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800433 }
434
435 // If U is outside the hardware range, limit it before the plant tries to use
436 // it.
437 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400438 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800439 if (U(i, 0) > plant().U_max(i, 0)) {
440 U_(i, 0) = plant().U_max(i, 0);
441 } else if (U(i, 0) < plant().U_min(i, 0)) {
442 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800443 }
444 }
445 }
446
Austin Schuhf9286cd2014-02-11 00:51:09 -0800447 // Corrects X_hat given the observation in Y.
448 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800449 X_hat_ +=
450 plant().A_inv() * L() * (Y - plant().C() * X_hat_ - plant().D() * U());
Austin Schuhf9286cd2014-02-11 00:51:09 -0800451 }
452
Austin Schuh3f862bb2016-02-27 14:48:05 -0800453 const Eigen::Matrix<double, number_of_states, 1> error() const {
454 return R() - X_hat();
455 }
456
Austin Schuhb6a6d822016-02-08 00:20:40 -0800457 // Returns the calculated controller power.
458 virtual const Eigen::Matrix<double, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800459 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800460 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800461 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800462 }
463
464 // Calculates the feed forwards power.
465 virtual const Eigen::Matrix<double, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800466 // TODO(austin): Should this live in StateSpaceController?
467 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800468 }
469
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800470 // stop_motors is whether or not to output all 0s.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800471 void Update(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800472 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700473 U_.setZero();
474 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800475 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800476 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800477 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800478 CapU();
479 }
480
Austin Schuhc2b77742015-11-26 16:18:27 -0800481 UpdateObserver(U_);
Austin Schuh093535c2016-03-05 23:21:00 -0800482
483 UpdateFFReference();
484 }
485
486 // Updates R() after any CapU operations happen on U().
487 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800488 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800489 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800490 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800491 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000492 }
493
Austin Schuhc2b77742015-11-26 16:18:27 -0800494 void UpdateObserver(const Eigen::Matrix<double, number_of_inputs, 1> &new_u) {
Austin Schuh32501832017-02-25 18:32:56 -0800495 // TODO(austin): Should this live in StateSpacePlant?
Austin Schuhc5fceb82017-02-25 16:24:12 -0800496 X_hat_ = plant().A() * X_hat() + plant().B() * new_u;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800497 }
498
Austin Schuh32501832017-02-25 18:32:56 -0800499 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800500 void set_index(int index) {
Austin Schuh32501832017-02-25 18:32:56 -0800501 controller_.set_index(index);
Austin Schuhc5fceb82017-02-25 16:24:12 -0800502 plant_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700503 }
504
Austin Schuh32501832017-02-25 18:32:56 -0800505 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700506
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800507 protected:
Austin Schuhc5fceb82017-02-25 16:24:12 -0800508 StateFeedbackPlant<number_of_states, number_of_inputs, number_of_outputs>
509 plant_;
510
Austin Schuh32501832017-02-25 18:32:56 -0800511 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs>
512 controller_;
513
514 StateFeedbackObserver<number_of_states, number_of_inputs, number_of_outputs>
515 observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700516
Brian Silverman273d8a32014-05-10 22:19:09 -0700517 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800518 static constexpr int kNumStates = number_of_states;
519 static constexpr int kNumOutputs = number_of_outputs;
520 static constexpr int kNumInputs = number_of_inputs;
521
522 // Portion of U which is based on the feed-forwards.
523 Eigen::Matrix<double, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700524
Brian Silverman273d8a32014-05-10 22:19:09 -0700525 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800526 // Internal state estimate.
Brian Silverman273d8a32014-05-10 22:19:09 -0700527 Eigen::Matrix<double, number_of_states, 1> X_hat_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800528 // Current goal (Used by the feed-back controller).
Brian Silverman273d8a32014-05-10 22:19:09 -0700529 Eigen::Matrix<double, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800530 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
531 Eigen::Matrix<double, number_of_states, 1> next_R_;
532 // Computed output after being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700533 Eigen::Matrix<double, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800534 // Computed output before being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700535 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped_;
536
Austin Schuhc5fceb82017-02-25 16:24:12 -0800537 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700538
Brian Silverman0a151c92014-05-02 15:28:44 -0700539 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800540};
541
Brian Silverman273d8a32014-05-10 22:19:09 -0700542#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_