blob: 3f4a6ad82b428de8b5172791328152afc6b892da [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
Brian Silvermanc571e052013-03-13 17:58:56 -07006#include <vector>
Austin Schuh1a387962015-01-31 16:36:20 -08007#include <memory>
Austin Schuhcda86af2014-02-16 16:16:39 -08008#include <iostream>
Brian Silvermanc571e052013-03-13 17:58:56 -07009
Austin Schuhdc1c84a2013-02-23 16:33:10 -080010#include "Eigen/Dense"
11
Austin Schuhcda86af2014-02-16 16:16:39 -080012#include "aos/common/logging/logging.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070013#include "aos/common/macros.h"
14
Brian Silverman5808bcb2014-09-14 21:40:43 -040015// For everything in this file, "inputs" and "outputs" are defined from the
16// perspective of the plant. This means U is an input and Y is an output
17// (because you give the plant U (powers) and it gives you back a Y (sensor
18// values). This is the opposite of what they mean from the perspective of the
19// controller (U is an output because that's what goes to the motors and Y is an
20// input because that's what comes back from the sensors).
21
Austin Schuhdc1c84a2013-02-23 16:33:10 -080022template <int number_of_states, int number_of_inputs, int number_of_outputs>
Brian Silverman273d8a32014-05-10 22:19:09 -070023class StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080024 public:
25 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
26
Austin Schuhe3490622013-03-13 01:24:30 -070027 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Brian Silverman273d8a32014-05-10 22:19:09 -070028 : A_(other.A()),
Austin Schuh6c20f202017-02-18 22:31:44 -080029 A_continuous_(other.A_continuous()),
Brian Silverman273d8a32014-05-10 22:19:09 -070030 B_(other.B()),
Austin Schuh6c20f202017-02-18 22:31:44 -080031 B_continuous_(other.B_continuous()),
Brian Silverman273d8a32014-05-10 22:19:09 -070032 C_(other.C()),
33 D_(other.D()),
34 U_min_(other.U_min()),
Austin Schuhb6a6d822016-02-08 00:20:40 -080035 U_max_(other.U_max()) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080036
Austin Schuhe3490622013-03-13 01:24:30 -070037 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080038 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
Austin Schuh6c20f202017-02-18 22:31:44 -080039 const Eigen::Matrix<double, number_of_states, number_of_states>
40 &A_continuous,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080041 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
Austin Schuh6c20f202017-02-18 22:31:44 -080042 const Eigen::Matrix<double, number_of_states, number_of_inputs>
43 &B_continuous,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080044 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
45 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
Brian Silverman5808bcb2014-09-14 21:40:43 -040046 const Eigen::Matrix<double, number_of_inputs, 1> &U_max,
47 const Eigen::Matrix<double, number_of_inputs, 1> &U_min)
Austin Schuh6c20f202017-02-18 22:31:44 -080048 : A_(A),
49 A_continuous_(A_continuous),
50 B_(B),
51 B_continuous_(B_continuous),
52 C_(C),
53 D_(D),
54 U_min_(U_min),
55 U_max_(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070056
Brian Silverman273d8a32014-05-10 22:19:09 -070057 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
58 return A_;
59 }
60 double A(int i, int j) const { return A()(i, j); }
Austin Schuh6c20f202017-02-18 22:31:44 -080061 const Eigen::Matrix<double, number_of_states, number_of_states> &A_continuous()
62 const {
63 return A_continuous_;
64 }
65 double A_continuous(int i, int j) const { return A_continuous()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -070066 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
67 return B_;
68 }
69 double B(int i, int j) const { return B()(i, j); }
Austin Schuh6c20f202017-02-18 22:31:44 -080070 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B_continuous() const {
71 return B_continuous_;
72 }
73 double B_continuous(int i, int j) const { return B_continuous()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -070074 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
75 return C_;
76 }
77 double C(int i, int j) const { return C()(i, j); }
78 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
79 return D_;
80 }
81 double D(int i, int j) const { return D()(i, j); }
82 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
83 return U_min_;
84 }
Brian Silvermana21c3a22014-06-12 21:49:15 -070085 double U_min(int i, int j) const { return U_min()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -070086 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
87 return U_max_;
88 }
Brian Silvermana21c3a22014-06-12 21:49:15 -070089 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -070090
91 private:
92 const Eigen::Matrix<double, number_of_states, number_of_states> A_;
Austin Schuh6c20f202017-02-18 22:31:44 -080093 const Eigen::Matrix<double, number_of_states, number_of_states> A_continuous_;
Brian Silverman273d8a32014-05-10 22:19:09 -070094 const Eigen::Matrix<double, number_of_states, number_of_inputs> B_;
Austin Schuh6c20f202017-02-18 22:31:44 -080095 const Eigen::Matrix<double, number_of_states, number_of_inputs> B_continuous_;
Brian Silverman273d8a32014-05-10 22:19:09 -070096 const Eigen::Matrix<double, number_of_outputs, number_of_states> C_;
97 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D_;
98 const Eigen::Matrix<double, number_of_inputs, 1> U_min_;
99 const Eigen::Matrix<double, number_of_inputs, 1> U_max_;
100
101 StateFeedbackPlantCoefficients &operator=(
102 StateFeedbackPlantCoefficients other) = delete;
Austin Schuhe3490622013-03-13 01:24:30 -0700103};
104
105template <int number_of_states, int number_of_inputs, int number_of_outputs>
106class StateFeedbackPlant {
107 public:
108 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -0700109
110 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -0800111 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh66c19882017-02-25 13:36:28 -0800112 number_of_states, number_of_inputs, number_of_outputs>>>
113 *coefficients)
Austin Schuh1a387962015-01-31 16:36:20 -0800114 : coefficients_(::std::move(*coefficients)), plant_index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -0700115 Reset();
116 }
117
118 StateFeedbackPlant(StateFeedbackPlant &&other)
119 : plant_index_(other.plant_index_) {
120 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700121 X_.swap(other.X_);
122 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -0700123 }
124
Austin Schuh1a387962015-01-31 16:36:20 -0800125 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700126
Austin Schuhe3490622013-03-13 01:24:30 -0700127 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700128 return coefficients().A();
Austin Schuhe3490622013-03-13 01:24:30 -0700129 }
130 double A(int i, int j) const { return A()(i, j); }
131 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700132 return coefficients().B();
Austin Schuhe3490622013-03-13 01:24:30 -0700133 }
134 double B(int i, int j) const { return B()(i, j); }
135 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700136 return coefficients().C();
Austin Schuhe3490622013-03-13 01:24:30 -0700137 }
138 double C(int i, int j) const { return C()(i, j); }
139 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700140 return coefficients().D();
Austin Schuhe3490622013-03-13 01:24:30 -0700141 }
142 double D(int i, int j) const { return D()(i, j); }
143 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700144 return coefficients().U_min();
Austin Schuhe3490622013-03-13 01:24:30 -0700145 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700146 double U_min(int i, int j) const { return U_min()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700147 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700148 return coefficients().U_max();
Austin Schuhe3490622013-03-13 01:24:30 -0700149 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700150 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700151
152 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700153 double X(int i, int j) const { return X()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700154 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700155 double Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700156
Brian Silverman0ca790b2014-06-12 21:33:08 -0700157 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700158 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700159 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700160 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700161
Austin Schuhb6a6d822016-02-08 00:20:40 -0800162 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
163 number_of_outputs> &
164 coefficients() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700165 return *coefficients_[plant_index_];
166 }
167
168 int plant_index() const { return plant_index_; }
169 void set_plant_index(int plant_index) {
Austin Schuh6ca0f792016-03-12 14:06:14 -0800170 assert(plant_index >= 0);
171 assert(plant_index < static_cast<int>(coefficients_.size()));
172 plant_index_ = plant_index;
Austin Schuhe3490622013-03-13 01:24:30 -0700173 }
174
175 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700176 X_.setZero();
177 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800178 }
179
Austin Schuh849f0032013-03-03 23:59:53 -0800180 // Assert that U is within the hardware range.
Austin Schuh66c19882017-02-25 13:36:28 -0800181 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400182 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh66c19882017-02-25 13:36:28 -0800183 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
184 LOG(FATAL, "U out of range\n");
185 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800186 }
187 }
Austin Schuh849f0032013-03-03 23:59:53 -0800188
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800189 // Computes the new X and Y given the control input.
Austin Schuh66c19882017-02-25 13:36:28 -0800190 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800191 // Powers outside of the range are more likely controller bugs than things
192 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800193 CheckU(U);
194 X_ = A() * X() + B() * U;
195 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800196 }
197
198 protected:
199 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800200 static const int kNumStates = number_of_states;
201 static const int kNumOutputs = number_of_outputs;
202 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700203
204 private:
Brian Silverman273d8a32014-05-10 22:19:09 -0700205 Eigen::Matrix<double, number_of_states, 1> X_;
206 Eigen::Matrix<double, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700207
Austin Schuhb6a6d822016-02-08 00:20:40 -0800208 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh1a387962015-01-31 16:36:20 -0800209 number_of_states, number_of_inputs, number_of_outputs>>> coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700210
Austin Schuhe3490622013-03-13 01:24:30 -0700211 int plant_index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700212
213 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800214};
215
Austin Schuh9644e1c2013-03-12 00:40:36 -0700216// A Controller is a structure which holds a plant and the K and L matrices.
217// This is designed such that multiple controllers can share one set of state to
218// support gain scheduling easily.
219template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh66c19882017-02-25 13:36:28 -0800220struct StateFeedbackControllerConstants final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700221 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700222
Austin Schuh9644e1c2013-03-12 00:40:36 -0700223 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
Brian Silverman5808bcb2014-09-14 21:40:43 -0400224 const Eigen::Matrix<double, number_of_inputs, number_of_states> K;
Austin Schuh86093ad2016-02-06 14:29:34 -0800225 const Eigen::Matrix<double, number_of_inputs, number_of_states> Kff;
Austin Schuh1a387962015-01-31 16:36:20 -0800226 const Eigen::Matrix<double, number_of_states, number_of_states> A_inv;
Austin Schuhe3490622013-03-13 01:24:30 -0700227 StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh66c19882017-02-25 13:36:28 -0800228 number_of_outputs>
229 plant;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700230
Austin Schuh66c19882017-02-25 13:36:28 -0800231 StateFeedbackControllerConstants(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700232 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
Brian Silverman5808bcb2014-09-14 21:40:43 -0400233 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
Austin Schuh86093ad2016-02-06 14:29:34 -0800234 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff,
Austin Schuh1a387962015-01-31 16:36:20 -0800235 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv,
Austin Schuhe3490622013-03-13 01:24:30 -0700236 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
237 number_of_outputs> &plant)
Austin Schuhb6a6d822016-02-08 00:20:40 -0800238 : L(L), K(K), Kff(Kff), A_inv(A_inv), plant(plant) {}
Brian Silverman2a04b262016-02-12 19:52:36 -0500239
240 // TODO(Brian): Remove this overload once they're all converted.
Austin Schuh66c19882017-02-25 13:36:28 -0800241 StateFeedbackControllerConstants(
Brian Silverman2a04b262016-02-12 19:52:36 -0500242 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
243 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
244 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv,
245 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
246 number_of_outputs> &plant)
247 : L(L),
248 K(K),
249 Kff(::Eigen::Matrix<double, number_of_inputs,
250 number_of_states>::Zero()),
251 A_inv(A_inv),
252 plant(plant) {}
Austin Schuh9644e1c2013-03-12 00:40:36 -0700253};
254
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800255template <int number_of_states, int number_of_inputs, int number_of_outputs>
256class StateFeedbackLoop {
257 public:
258 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
259
Austin Schuh66c19882017-02-25 13:36:28 -0800260 StateFeedbackLoop(
261 const StateFeedbackControllerConstants<number_of_states, number_of_inputs,
262 number_of_outputs> &controller)
Brian Silverman0a151c92014-05-02 15:28:44 -0700263 : controller_index_(0) {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800264 controllers_.emplace_back(
Austin Schuh66c19882017-02-25 13:36:28 -0800265 new StateFeedbackControllerConstants<number_of_states, number_of_inputs,
266 number_of_outputs>(controller));
Brian Silverman0a151c92014-05-02 15:28:44 -0700267 Reset();
268 }
269
Austin Schuh66c19882017-02-25 13:36:28 -0800270 StateFeedbackLoop(
271 ::std::vector<::std::unique_ptr<StateFeedbackControllerConstants<
272 number_of_states, number_of_inputs, number_of_outputs>>> *controllers)
Austin Schuh1a387962015-01-31 16:36:20 -0800273 : controllers_(::std::move(*controllers)), controller_index_(0) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700274 Reset();
275 }
276
277 StateFeedbackLoop(StateFeedbackLoop &&other) {
278 X_hat_.swap(other.X_hat_);
279 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800280 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700281 U_.swap(other.U_);
282 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800283 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700284 ::std::swap(controllers_, other.controllers_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700285 controller_index_ = other.controller_index_;
286 }
287
Austin Schuh1a387962015-01-31 16:36:20 -0800288 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700289
Austin Schuh9644e1c2013-03-12 00:40:36 -0700290 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700291 return controller().plant.A();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700292 }
293 double A(int i, int j) const { return A()(i, j); }
294 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700295 return controller().plant.B();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700296 }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800297 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv()
298 const {
Austin Schuh703b8d42015-02-01 14:56:34 -0800299 return controller().A_inv;
300 }
301 double A_inv(int i, int j) const { return A_inv()(i, j); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700302 double B(int i, int j) const { return B()(i, j); }
303 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700304 return controller().plant.C();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700305 }
306 double C(int i, int j) const { return C()(i, j); }
307 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700308 return controller().plant.D();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700309 }
310 double D(int i, int j) const { return D()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700311 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
312 return controller().plant.U_min();
313 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700314 double U_min(int i, int j) const { return U_min()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700315 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
316 return controller().plant.U_max();
317 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700318 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700319
Brian Silverman5808bcb2014-09-14 21:40:43 -0400320 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K() const {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700321 return controller().K;
322 }
323 double K(int i, int j) const { return K()(i, j); }
Austin Schuh86093ad2016-02-06 14:29:34 -0800324 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff() const {
325 return controller().Kff;
326 }
327 double Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700328 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
329 return controller().L;
330 }
331 double L(int i, int j) const { return L()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700332
333 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
334 return X_hat_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700335 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700336 double X_hat(int i, int j) const { return X_hat()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700337 const Eigen::Matrix<double, number_of_states, 1> &R() const { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700338 double R(int i, int j) const { return R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800339 const Eigen::Matrix<double, number_of_states, 1> &next_R() const {
340 return next_R_;
341 }
342 double next_R(int i, int j) const { return next_R()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700343 const Eigen::Matrix<double, number_of_inputs, 1> &U() const { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700344 double U(int i, int j) const { return U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700345 const Eigen::Matrix<double, number_of_inputs, 1> &U_uncapped() const {
346 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700347 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700348 double U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800349 const Eigen::Matrix<double, number_of_inputs, 1> &ff_U() const {
350 return ff_U_;
351 }
352 double ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700353
Brian Silverman0ca790b2014-06-12 21:33:08 -0700354 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700355 double &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700356 Eigen::Matrix<double, number_of_states, 1> &mutable_R() { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700357 double &mutable_R(int i, int j) { return mutable_R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800358 Eigen::Matrix<double, number_of_states, 1> &mutable_next_R() {
359 return next_R_;
360 }
361 double &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700362 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U() { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700363 double &mutable_U(int i, int j) { return mutable_U()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700364 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700365 return U_uncapped_;
366 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700367 double &mutable_U_uncapped(int i, int j) {
368 return mutable_U_uncapped()(i, j);
369 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800370
Austin Schuh66c19882017-02-25 13:36:28 -0800371 const StateFeedbackControllerConstants<number_of_states, number_of_inputs,
372 number_of_outputs>
373 &controller() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700374 return *controllers_[controller_index_];
Austin Schuh9644e1c2013-03-12 00:40:36 -0700375 }
376
Austin Schuh66c19882017-02-25 13:36:28 -0800377 const StateFeedbackControllerConstants<number_of_states, number_of_inputs,
378 number_of_outputs>
379 &controller(int index) const {
Austin Schuh2054f5f2013-10-27 14:54:10 -0700380 return *controllers_[index];
381 }
382
Austin Schuh9644e1c2013-03-12 00:40:36 -0700383 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700384 X_hat_.setZero();
385 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800386 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700387 U_.setZero();
388 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800389 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800390 }
391
392 // If U is outside the hardware range, limit it before the plant tries to use
393 // it.
394 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400395 for (int i = 0; i < kNumInputs; ++i) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700396 if (U(i, 0) > U_max(i, 0)) {
397 U_(i, 0) = U_max(i, 0);
398 } else if (U(i, 0) < U_min(i, 0)) {
399 U_(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800400 }
401 }
402 }
403
Austin Schuhf9286cd2014-02-11 00:51:09 -0800404 // Corrects X_hat given the observation in Y.
405 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuh703b8d42015-02-01 14:56:34 -0800406 X_hat_ += A_inv() * L() * (Y - C() * X_hat_ - D() * U());
Austin Schuhf9286cd2014-02-11 00:51:09 -0800407 }
408
Austin Schuh3f862bb2016-02-27 14:48:05 -0800409 const Eigen::Matrix<double, number_of_states, 1> error() const {
410 return R() - X_hat();
411 }
412
Austin Schuhb6a6d822016-02-08 00:20:40 -0800413 // Returns the calculated controller power.
414 virtual const Eigen::Matrix<double, number_of_inputs, 1> ControllerOutput() {
415 ff_U_ = FeedForward();
Austin Schuh3f862bb2016-02-27 14:48:05 -0800416 return K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800417 }
418
419 // Calculates the feed forwards power.
420 virtual const Eigen::Matrix<double, number_of_inputs, 1> FeedForward() {
421 return Kff() * (next_R() - A() * R());
422 }
423
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800424 // stop_motors is whether or not to output all 0s.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800425 void Update(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800426 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700427 U_.setZero();
428 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800429 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800430 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800431 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800432 CapU();
433 }
434
Austin Schuhc2b77742015-11-26 16:18:27 -0800435 UpdateObserver(U_);
Austin Schuh093535c2016-03-05 23:21:00 -0800436
437 UpdateFFReference();
438 }
439
440 // Updates R() after any CapU operations happen on U().
441 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800442 ff_U_ -= U_uncapped() - U();
443 if (!Kff().isZero(0)) {
444 R_ = A() * R() + B() * ff_U_;
445 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000446 }
447
Austin Schuhc2b77742015-11-26 16:18:27 -0800448 void UpdateObserver(const Eigen::Matrix<double, number_of_inputs, 1> &new_u) {
449 X_hat_ = A() * X_hat() + B() * new_u;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800450 }
451
Brian Silverman273d8a32014-05-10 22:19:09 -0700452 // Sets the current controller to be index, clamped to be within range.
Austin Schuh9644e1c2013-03-12 00:40:36 -0700453 void set_controller_index(int index) {
Austin Schuhe3490622013-03-13 01:24:30 -0700454 if (index < 0) {
455 controller_index_ = 0;
456 } else if (index >= static_cast<int>(controllers_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -0700457 controller_index_ = static_cast<int>(controllers_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -0700458 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700459 controller_index_ = index;
460 }
461 }
462
Austin Schuhd34569d2014-02-18 20:26:38 -0800463 int controller_index() const { return controller_index_; }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700464
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800465 protected:
Austin Schuh66c19882017-02-25 13:36:28 -0800466 ::std::vector<::std::unique_ptr<StateFeedbackControllerConstants<
467 number_of_states, number_of_inputs, number_of_outputs>>>
468 controllers_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700469
Brian Silverman273d8a32014-05-10 22:19:09 -0700470 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800471 static constexpr int kNumStates = number_of_states;
472 static constexpr int kNumOutputs = number_of_outputs;
473 static constexpr int kNumInputs = number_of_inputs;
474
475 // Portion of U which is based on the feed-forwards.
476 Eigen::Matrix<double, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700477
Brian Silverman273d8a32014-05-10 22:19:09 -0700478 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800479 // Internal state estimate.
Brian Silverman273d8a32014-05-10 22:19:09 -0700480 Eigen::Matrix<double, number_of_states, 1> X_hat_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800481 // Current goal (Used by the feed-back controller).
Brian Silverman273d8a32014-05-10 22:19:09 -0700482 Eigen::Matrix<double, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800483 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
484 Eigen::Matrix<double, number_of_states, 1> next_R_;
485 // Computed output after being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700486 Eigen::Matrix<double, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800487 // Computed output before being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700488 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped_;
489
Austin Schuh9644e1c2013-03-12 00:40:36 -0700490 int controller_index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700491
Brian Silverman0a151c92014-05-02 15:28:44 -0700492 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800493};
494
Brian Silverman273d8a32014-05-10 22:19:09 -0700495#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_