blob: 2511d9854b322b95dce0f986d5a89cc3492ee45f [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 Schuhc5fceb82017-02-25 16:24:12 -08006#include <memory>
7#include <utility>
8#include <vector>
Austin Schuh3ad5ed82017-02-25 21:36:19 -08009#include <chrono>
Brian Silvermanc571e052013-03-13 17:58:56 -070010
Austin Schuhdc1c84a2013-02-23 16:33:10 -080011#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080012#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080013
Brian Silverman6260c092018-01-14 15:21:36 -080014#if defined(__linux__)
John Park33858a32018-09-28 23:05:48 -070015#include "aos/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080016#endif
John Park33858a32018-09-28 23:05:48 -070017#include "aos/macros.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070018
Austin Schuhe91f14c2017-02-25 19:43:57 -080019template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080020 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080021class StateFeedbackLoop;
22
Brian Silverman5808bcb2014-09-14 21:40:43 -040023// For everything in this file, "inputs" and "outputs" are defined from the
24// perspective of the plant. This means U is an input and Y is an output
25// (because you give the plant U (powers) and it gives you back a Y (sensor
26// values). This is the opposite of what they mean from the perspective of the
27// controller (U is an output because that's what goes to the motors and Y is an
28// input because that's what comes back from the sensors).
29
Austin Schuh20388b62017-11-23 22:40:46 -080030template <int number_of_states, int number_of_inputs, int number_of_outputs,
31 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080032struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080033 public:
34 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
35
Austin Schuhe3490622013-03-13 01:24:30 -070036 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080037 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080038 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080039 C(other.C),
40 D(other.D),
41 U_min(other.U_min),
42 U_max(other.U_max) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080043
Austin Schuhe3490622013-03-13 01:24:30 -070044 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080045 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080046 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
47 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
48 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
49 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
50 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min)
Sabina Davis3922dfa2018-02-10 23:10:05 -080051 : A(A), B(B), C(C), D(D), U_min(U_min), U_max(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070052
Austin Schuh20388b62017-11-23 22:40:46 -080053 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080054 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
55 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
56 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
57 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
58 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070059};
60
Austin Schuh20388b62017-11-23 22:40:46 -080061template <int number_of_states, int number_of_inputs, int number_of_outputs,
62 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070063class 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 Schuh20388b62017-11-23 22:40:46 -080069 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh66c19882017-02-25 13:36:28 -080070 *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 Schuh20388b62017-11-23 22:40:46 -080084 const Eigen::Matrix<Scalar, 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 }
Austin Schuh20388b62017-11-23 22:40:46 -080087 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -080088 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080089 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070090 }
Austin Schuh20388b62017-11-23 22:40:46 -080091 Scalar B(int i, int j) const { return B()(i, j); }
92 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080093 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -070094 }
Austin Schuh20388b62017-11-23 22:40:46 -080095 Scalar C(int i, int j) const { return C()(i, j); }
96 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080097 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -070098 }
Austin Schuh20388b62017-11-23 22:40:46 -080099 Scalar D(int i, int j) const { return D()(i, j); }
100 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800101 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700102 }
Austin Schuh20388b62017-11-23 22:40:46 -0800103 Scalar U_min(int i, int j) const { return U_min()(i, j); }
104 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800105 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700106 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800107 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700108
Austin Schuh20388b62017-11-23 22:40:46 -0800109 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800110 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800111 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800112 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700113
Austin Schuh20388b62017-11-23 22:40:46 -0800114 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800115 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800116 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800117 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700118
Austin Schuhb6a6d822016-02-08 00:20:40 -0800119 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800120 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800121 &coefficients(int index) const {
122 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700123 }
124
Austin Schuhc5fceb82017-02-25 16:24:12 -0800125 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800126 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800127 &coefficients() const {
128 return *coefficients_[index_];
129 }
130
131 int index() const { return index_; }
132 void set_index(int index) {
133 assert(index >= 0);
134 assert(index < static_cast<int>(coefficients_.size()));
135 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700136 }
137
138 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700139 X_.setZero();
140 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800141 }
142
Austin Schuh849f0032013-03-03 23:59:53 -0800143 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800144 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400145 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800146 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
147 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800148#if defined(__linux__)
Austin Schuh66c19882017-02-25 13:36:28 -0800149 LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800150#else
151 abort();
152#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800153 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800154 }
155 }
Austin Schuh849f0032013-03-03 23:59:53 -0800156
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800157 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800158 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800159 // Powers outside of the range are more likely controller bugs than things
160 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800161 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800162 X_ = Update(X(), U);
Austin Schuh01c7b252017-03-05 00:59:31 -0800163 UpdateY(U);
164 }
165
166 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800167 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800168 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800169 }
170
Austin Schuh20388b62017-11-23 22:40:46 -0800171 Eigen::Matrix<Scalar, number_of_states, 1> Update(
172 const Eigen::Matrix<Scalar, number_of_states, 1> X,
173 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800174 return A() * X + B() * U;
175 }
176
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800177 protected:
178 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800179 static const int kNumStates = number_of_states;
180 static const int kNumOutputs = number_of_outputs;
181 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700182
183 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800184 Eigen::Matrix<Scalar, number_of_states, 1> X_;
185 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700186
Austin Schuhb6a6d822016-02-08 00:20:40 -0800187 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800188 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800189 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700190
Austin Schuhc5fceb82017-02-25 16:24:12 -0800191 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700192
193 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800194};
195
Austin Schuh32501832017-02-25 18:32:56 -0800196// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800197template <int number_of_states, int number_of_inputs, int number_of_outputs,
198 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800199struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700200 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700201
Austin Schuh20388b62017-11-23 22:40:46 -0800202 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
203 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700204
Austin Schuh32501832017-02-25 18:32:56 -0800205 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800206 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
207 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800208 : K(K), Kff(Kff) {}
209};
210
Austin Schuh20388b62017-11-23 22:40:46 -0800211template <int number_of_states, int number_of_inputs, int number_of_outputs,
212 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800213class StateFeedbackController {
214 public:
215 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
216
217 explicit StateFeedbackController(
218 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800219 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
220 *controllers)
Austin Schuh32501832017-02-25 18:32:56 -0800221 : coefficients_(::std::move(*controllers)) {}
222
223 StateFeedbackController(StateFeedbackController &&other)
224 : index_(other.index_) {
225 ::std::swap(coefficients_, other.coefficients_);
226 }
227
Austin Schuh20388b62017-11-23 22:40:46 -0800228 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800229 return coefficients().K;
230 }
Austin Schuh20388b62017-11-23 22:40:46 -0800231 Scalar K(int i, int j) const { return K()(i, j); }
232 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800233 return coefficients().Kff;
234 }
Austin Schuh20388b62017-11-23 22:40:46 -0800235 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800236
Austin Schuhe91f14c2017-02-25 19:43:57 -0800237 void Reset() {}
238
Austin Schuh32501832017-02-25 18:32:56 -0800239 // Sets the current controller to be index, clamped to be within range.
240 void set_index(int index) {
241 if (index < 0) {
242 index_ = 0;
243 } else if (index >= static_cast<int>(coefficients_.size())) {
244 index_ = static_cast<int>(coefficients_.size()) - 1;
245 } else {
246 index_ = index;
247 }
248 }
249
250 int index() const { return index_; }
251
252 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800253 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800254 &coefficients(int index) const {
255 return *coefficients_[index];
256 }
257
258 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800259 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800260 &coefficients() const {
261 return *coefficients_[index_];
262 }
263
264 private:
265 int index_ = 0;
266 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800267 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800268 coefficients_;
269};
270
Austin Schuh32501832017-02-25 18:32:56 -0800271// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800272template <int number_of_states, int number_of_inputs, int number_of_outputs,
273 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800274struct StateFeedbackObserverCoefficients final {
275 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
276
Sabina Davis3922dfa2018-02-10 23:10:05 -0800277 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800278
279 StateFeedbackObserverCoefficients(
Sabina Davis3922dfa2018-02-10 23:10:05 -0800280 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain)
281 : KalmanGain(KalmanGain) {}
Austin Schuh32501832017-02-25 18:32:56 -0800282};
283
Austin Schuh20388b62017-11-23 22:40:46 -0800284template <int number_of_states, int number_of_inputs, int number_of_outputs,
285 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800286class StateFeedbackObserver {
287 public:
288 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
289
290 explicit StateFeedbackObserver(
291 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800292 number_of_states, number_of_inputs, number_of_outputs, Scalar>>> *observers)
Austin Schuh32501832017-02-25 18:32:56 -0800293 : coefficients_(::std::move(*observers)) {}
294
295 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800296 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800297 ::std::swap(coefficients_, other.coefficients_);
298 }
299
Sabina Davis3922dfa2018-02-10 23:10:05 -0800300 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain() const {
301 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800302 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800303 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800304
Austin Schuh20388b62017-11-23 22:40:46 -0800305 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800306 return X_hat_;
307 }
Austin Schuh20388b62017-11-23 22:40:46 -0800308 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800309
Austin Schuh6501d232017-11-23 20:35:27 -0800310 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800311 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800312 X_hat_.setZero();
313 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800314
Austin Schuh6501d232017-11-23 20:35:27 -0800315 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800316 number_of_outputs, Scalar> *plant,
317 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800318 ::std::chrono::nanoseconds /*dt*/) {
319 mutable_X_hat() = plant->Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800320 }
321
Austin Schuh6501d232017-11-23 20:35:27 -0800322 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800323 number_of_outputs, Scalar> &plant,
324 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
325 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800326 mutable_X_hat() +=
Sabina Davis3922dfa2018-02-10 23:10:05 -0800327 KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800328 }
329
Austin Schuh32501832017-02-25 18:32:56 -0800330 // Sets the current controller to be index, clamped to be within range.
331 void set_index(int index) {
332 if (index < 0) {
333 index_ = 0;
334 } else if (index >= static_cast<int>(coefficients_.size())) {
335 index_ = static_cast<int>(coefficients_.size()) - 1;
336 } else {
337 index_ = index;
338 }
339 }
340
341 int index() const { return index_; }
342
343 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800344 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800345 &coefficients(int index) const {
346 return *coefficients_[index];
347 }
348
349 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800350 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800351 &coefficients() const {
352 return *coefficients_[index_];
353 }
354
355 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800356 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800357 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800358
Austin Schuh32501832017-02-25 18:32:56 -0800359 int index_ = 0;
360 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800361 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800362 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700363};
364
Austin Schuhe91f14c2017-02-25 19:43:57 -0800365template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800366 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800367 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800368 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800369 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800370 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800371class StateFeedbackLoop {
372 public:
373 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
374
Austin Schuh32501832017-02-25 18:32:56 -0800375 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800376 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800377 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800378 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800379 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800380 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800381 controller_(::std::move(controller)),
382 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700383 Reset();
384 }
385
Austin Schuhc5fceb82017-02-25 16:24:12 -0800386 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800387 : plant_(::std::move(other.plant_)),
388 controller_(::std::move(other.controller_)),
389 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700390 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800391 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700392 U_.swap(other.U_);
393 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800394 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700395 }
396
Austin Schuh1a387962015-01-31 16:36:20 -0800397 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700398
Austin Schuh20388b62017-11-23 22:40:46 -0800399 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800400 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700401 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800402 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800403 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
404 Scalar R(int i, int j) const { return R()(i, j); }
405 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800406 return next_R_;
407 }
Austin Schuh20388b62017-11-23 22:40:46 -0800408 Scalar next_R(int i, int j) const { return next_R()(i, j); }
409 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
410 Scalar U(int i, int j) const { return U()(i, j); }
411 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700412 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700413 }
Austin Schuh20388b62017-11-23 22:40:46 -0800414 Scalar U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
415 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800416 return ff_U_;
417 }
Austin Schuh20388b62017-11-23 22:40:46 -0800418 Scalar ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700419
Austin Schuh20388b62017-11-23 22:40:46 -0800420 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800421 return observer_.mutable_X_hat();
422 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800423 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800424 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
425 Scalar &mutable_R(int i, int j) { return mutable_R()(i, j); }
426 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800427 return next_R_;
428 }
Austin Schuh20388b62017-11-23 22:40:46 -0800429 Scalar &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
430 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
431 Scalar &mutable_U(int i, int j) { return mutable_U()(i, j); }
432 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700433 return U_uncapped_;
434 }
Austin Schuh20388b62017-11-23 22:40:46 -0800435 Scalar &mutable_U_uncapped(int i, int j) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700436 return mutable_U_uncapped()(i, j);
437 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800438
Austin Schuhe91f14c2017-02-25 19:43:57 -0800439 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800440 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800441
Austin Schuh32501832017-02-25 18:32:56 -0800442 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800443 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800444 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800445 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700446 }
447
Austin Schuhe91f14c2017-02-25 19:43:57 -0800448 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700449
Austin Schuh9644e1c2013-03-12 00:40:36 -0700450 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700451 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800452 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700453 U_.setZero();
454 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800455 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800456
457 plant_.Reset();
458 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800459 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800460 }
461
462 // If U is outside the hardware range, limit it before the plant tries to use
463 // it.
464 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400465 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800466 if (U(i, 0) > plant().U_max(i, 0)) {
467 U_(i, 0) = plant().U_max(i, 0);
468 } else if (U(i, 0) < plant().U_min(i, 0)) {
469 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800470 }
471 }
472 }
473
Austin Schuhf9286cd2014-02-11 00:51:09 -0800474 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800475 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800476 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800477 }
478
Austin Schuh20388b62017-11-23 22:40:46 -0800479 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800480 return R() - X_hat();
481 }
482
Austin Schuhb6a6d822016-02-08 00:20:40 -0800483 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800484 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800485 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800486 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800487 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800488 }
489
490 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800491 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800492 // TODO(austin): Should this live in StateSpaceController?
493 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800494 }
495
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800496 // stop_motors is whether or not to output all 0s.
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800497 void Update(bool stop_motors,
498 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(5)) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800499 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700500 U_.setZero();
501 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800502 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800503 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800504 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800505 CapU();
506 }
507
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800508 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800509
510 UpdateFFReference();
511 }
512
513 // Updates R() after any CapU operations happen on U().
514 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800515 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800516 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800517 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800518 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000519 }
520
Austin Schuh20388b62017-11-23 22:40:46 -0800521 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800522 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800523 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800524 }
525
Austin Schuh32501832017-02-25 18:32:56 -0800526 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800527 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800528 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800529 controller_.set_index(index);
530 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700531 }
532
Austin Schuh32501832017-02-25 18:32:56 -0800533 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700534
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800535 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800536 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800537
Austin Schuh20388b62017-11-23 22:40:46 -0800538 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
539 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800540 controller_;
541
Austin Schuhe91f14c2017-02-25 19:43:57 -0800542 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700543
Brian Silverman273d8a32014-05-10 22:19:09 -0700544 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800545 static constexpr int kNumStates = number_of_states;
546 static constexpr int kNumOutputs = number_of_outputs;
547 static constexpr int kNumInputs = number_of_inputs;
548
549 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800550 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700551
Brian Silverman273d8a32014-05-10 22:19:09 -0700552 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800553 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800554 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800555 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800556 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800557 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800558 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800559 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800560 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700561
Brian Silverman0a151c92014-05-02 15:28:44 -0700562 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800563};
564
Brian Silverman273d8a32014-05-10 22:19:09 -0700565#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_