blob: 30da8f1be9b508c63cb0ee2eb0ff975a8d43572d [file] [log] [blame]
Brian Silverman273d8a32014-05-10 22:19:09 -07001#ifndef FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_
2#define FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_
Austin Schuhdc1c84a2013-02-23 16:33:10 -08003
Austin Schuh849f0032013-03-03 23:59:53 -08004#include <assert.h>
Austin Schuhdc1c84a2013-02-23 16:33:10 -08005
Austin Schuhcda86af2014-02-16 16:16:39 -08006#include <iostream>
Austin Schuhc5fceb82017-02-25 16:24:12 -08007#include <memory>
8#include <utility>
9#include <vector>
Austin Schuh3ad5ed82017-02-25 21:36:19 -080010#include <chrono>
Brian Silvermanc571e052013-03-13 17:58:56 -070011
Austin Schuhdc1c84a2013-02-23 16:33:10 -080012#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080013#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080014
Austin Schuhcda86af2014-02-16 16:16:39 -080015#include "aos/common/logging/logging.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070016#include "aos/common/macros.h"
17
Austin Schuhe91f14c2017-02-25 19:43:57 -080018template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080019 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080020class StateFeedbackLoop;
21
Brian Silverman5808bcb2014-09-14 21:40:43 -040022// For everything in this file, "inputs" and "outputs" are defined from the
23// perspective of the plant. This means U is an input and Y is an output
24// (because you give the plant U (powers) and it gives you back a Y (sensor
25// values). This is the opposite of what they mean from the perspective of the
26// controller (U is an output because that's what goes to the motors and Y is an
27// input because that's what comes back from the sensors).
28
Austin Schuh20388b62017-11-23 22:40:46 -080029template <int number_of_states, int number_of_inputs, int number_of_outputs,
30 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080031struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080032 public:
33 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
34
Austin Schuhe3490622013-03-13 01:24:30 -070035 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080036 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080037 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080038 C(other.C),
39 D(other.D),
40 U_min(other.U_min),
41 U_max(other.U_max) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080042
Austin Schuhe3490622013-03-13 01:24:30 -070043 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080044 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080045 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
46 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
47 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
48 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
49 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min)
Sabina Davis3922dfa2018-02-10 23:10:05 -080050 : A(A), B(B), C(C), D(D), U_min(U_min), U_max(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070051
Austin Schuh20388b62017-11-23 22:40:46 -080052 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080053 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
54 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
55 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
56 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
57 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070058};
59
Austin Schuh20388b62017-11-23 22:40:46 -080060template <int number_of_states, int number_of_inputs, int number_of_outputs,
61 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070062class StateFeedbackPlant {
63 public:
64 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070065
66 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080067 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080068 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh66c19882017-02-25 13:36:28 -080069 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080070 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070071 Reset();
72 }
73
74 StateFeedbackPlant(StateFeedbackPlant &&other)
Austin Schuhc5fceb82017-02-25 16:24:12 -080075 : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070076 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070077 X_.swap(other.X_);
78 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070079 }
80
Austin Schuh1a387962015-01-31 16:36:20 -080081 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070082
Austin Schuh20388b62017-11-23 22:40:46 -080083 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080084 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070085 }
Austin Schuh20388b62017-11-23 22:40:46 -080086 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -080087 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080088 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070089 }
Austin Schuh20388b62017-11-23 22:40:46 -080090 Scalar B(int i, int j) const { return B()(i, j); }
91 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080092 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -070093 }
Austin Schuh20388b62017-11-23 22:40:46 -080094 Scalar C(int i, int j) const { return C()(i, j); }
95 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080096 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -070097 }
Austin Schuh20388b62017-11-23 22:40:46 -080098 Scalar D(int i, int j) const { return D()(i, j); }
99 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800100 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700101 }
Austin Schuh20388b62017-11-23 22:40:46 -0800102 Scalar U_min(int i, int j) const { return U_min()(i, j); }
103 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800104 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700105 }
Austin Schuh20388b62017-11-23 22:40:46 -0800106 Scalar U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700107
Austin Schuh20388b62017-11-23 22:40:46 -0800108 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
109 Scalar X(int i, int j) const { return X()(i, j); }
110 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
111 Scalar Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700112
Austin Schuh20388b62017-11-23 22:40:46 -0800113 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
114 Scalar &mutable_X(int i, int j) { return mutable_X()(i, j); }
115 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
116 Scalar &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700117
Austin Schuhb6a6d822016-02-08 00:20:40 -0800118 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800119 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800120 &coefficients(int index) const {
121 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700122 }
123
Austin Schuhc5fceb82017-02-25 16:24:12 -0800124 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800125 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800126 &coefficients() const {
127 return *coefficients_[index_];
128 }
129
130 int index() const { return index_; }
131 void set_index(int index) {
132 assert(index >= 0);
133 assert(index < static_cast<int>(coefficients_.size()));
134 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700135 }
136
137 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700138 X_.setZero();
139 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800140 }
141
Austin Schuh849f0032013-03-03 23:59:53 -0800142 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800143 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400144 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800145 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
146 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Austin Schuh66c19882017-02-25 13:36:28 -0800147 LOG(FATAL, "U out of range\n");
148 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800149 }
150 }
Austin Schuh849f0032013-03-03 23:59:53 -0800151
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800152 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800153 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800154 // Powers outside of the range are more likely controller bugs than things
155 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800156 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800157 X_ = Update(X(), U);
Austin Schuh01c7b252017-03-05 00:59:31 -0800158 UpdateY(U);
159 }
160
161 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800162 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800163 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800164 }
165
Austin Schuh20388b62017-11-23 22:40:46 -0800166 Eigen::Matrix<Scalar, number_of_states, 1> Update(
167 const Eigen::Matrix<Scalar, number_of_states, 1> X,
168 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800169 return A() * X + B() * U;
170 }
171
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800172 protected:
173 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800174 static const int kNumStates = number_of_states;
175 static const int kNumOutputs = number_of_outputs;
176 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700177
178 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800179 Eigen::Matrix<Scalar, number_of_states, 1> X_;
180 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700181
Austin Schuhb6a6d822016-02-08 00:20:40 -0800182 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800183 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800184 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700185
Austin Schuhc5fceb82017-02-25 16:24:12 -0800186 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700187
188 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800189};
190
Austin Schuh32501832017-02-25 18:32:56 -0800191// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800192template <int number_of_states, int number_of_inputs, int number_of_outputs,
193 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800194struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700195 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700196
Austin Schuh20388b62017-11-23 22:40:46 -0800197 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
198 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700199
Austin Schuh32501832017-02-25 18:32:56 -0800200 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800201 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
202 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800203 : K(K), Kff(Kff) {}
204};
205
Austin Schuh20388b62017-11-23 22:40:46 -0800206template <int number_of_states, int number_of_inputs, int number_of_outputs,
207 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800208class StateFeedbackController {
209 public:
210 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
211
212 explicit StateFeedbackController(
213 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800214 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
215 *controllers)
Austin Schuh32501832017-02-25 18:32:56 -0800216 : coefficients_(::std::move(*controllers)) {}
217
218 StateFeedbackController(StateFeedbackController &&other)
219 : index_(other.index_) {
220 ::std::swap(coefficients_, other.coefficients_);
221 }
222
Austin Schuh20388b62017-11-23 22:40:46 -0800223 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800224 return coefficients().K;
225 }
Austin Schuh20388b62017-11-23 22:40:46 -0800226 Scalar K(int i, int j) const { return K()(i, j); }
227 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800228 return coefficients().Kff;
229 }
Austin Schuh20388b62017-11-23 22:40:46 -0800230 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800231
Austin Schuhe91f14c2017-02-25 19:43:57 -0800232 void Reset() {}
233
Austin Schuh32501832017-02-25 18:32:56 -0800234 // Sets the current controller to be index, clamped to be within range.
235 void set_index(int index) {
236 if (index < 0) {
237 index_ = 0;
238 } else if (index >= static_cast<int>(coefficients_.size())) {
239 index_ = static_cast<int>(coefficients_.size()) - 1;
240 } else {
241 index_ = index;
242 }
243 }
244
245 int index() const { return index_; }
246
247 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800248 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800249 &coefficients(int index) const {
250 return *coefficients_[index];
251 }
252
253 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800254 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800255 &coefficients() const {
256 return *coefficients_[index_];
257 }
258
259 private:
260 int index_ = 0;
261 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800262 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800263 coefficients_;
264};
265
Austin Schuh32501832017-02-25 18:32:56 -0800266// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800267template <int number_of_states, int number_of_inputs, int number_of_outputs,
268 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800269struct StateFeedbackObserverCoefficients final {
270 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
271
Sabina Davis3922dfa2018-02-10 23:10:05 -0800272 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800273
274 StateFeedbackObserverCoefficients(
Sabina Davis3922dfa2018-02-10 23:10:05 -0800275 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain)
276 : KalmanGain(KalmanGain) {}
Austin Schuh32501832017-02-25 18:32:56 -0800277};
278
Austin Schuh20388b62017-11-23 22:40:46 -0800279template <int number_of_states, int number_of_inputs, int number_of_outputs,
280 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800281class StateFeedbackObserver {
282 public:
283 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
284
285 explicit StateFeedbackObserver(
286 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800287 number_of_states, number_of_inputs, number_of_outputs, Scalar>>> *observers)
Austin Schuh32501832017-02-25 18:32:56 -0800288 : coefficients_(::std::move(*observers)) {}
289
290 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800291 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800292 ::std::swap(coefficients_, other.coefficients_);
293 }
294
Sabina Davis3922dfa2018-02-10 23:10:05 -0800295 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain() const {
296 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800297 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800298 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800299
Austin Schuh20388b62017-11-23 22:40:46 -0800300 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800301 return X_hat_;
302 }
Austin Schuh20388b62017-11-23 22:40:46 -0800303 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800304
Austin Schuh6501d232017-11-23 20:35:27 -0800305 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800306 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800307 X_hat_.setZero();
308 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800309
Austin Schuh6501d232017-11-23 20:35:27 -0800310 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800311 number_of_outputs, Scalar> *plant,
312 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800313 ::std::chrono::nanoseconds /*dt*/) {
314 mutable_X_hat() = plant->Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800315 }
316
Austin Schuh6501d232017-11-23 20:35:27 -0800317 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800318 number_of_outputs, Scalar> &plant,
319 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
320 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800321 mutable_X_hat() +=
Sabina Davis3922dfa2018-02-10 23:10:05 -0800322 KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800323 }
324
Austin Schuh32501832017-02-25 18:32:56 -0800325 // Sets the current controller to be index, clamped to be within range.
326 void set_index(int index) {
327 if (index < 0) {
328 index_ = 0;
329 } else if (index >= static_cast<int>(coefficients_.size())) {
330 index_ = static_cast<int>(coefficients_.size()) - 1;
331 } else {
332 index_ = index;
333 }
334 }
335
336 int index() const { return index_; }
337
338 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800339 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800340 &coefficients(int index) const {
341 return *coefficients_[index];
342 }
343
344 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800345 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800346 &coefficients() const {
347 return *coefficients_[index_];
348 }
349
350 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800351 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800352 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800353
Austin Schuh32501832017-02-25 18:32:56 -0800354 int index_ = 0;
355 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800356 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800357 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700358};
359
Austin Schuhe91f14c2017-02-25 19:43:57 -0800360template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800361 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800362 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800363 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800364 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800365 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800366class StateFeedbackLoop {
367 public:
368 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
369
Austin Schuh32501832017-02-25 18:32:56 -0800370 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800371 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800372 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800373 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800374 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800375 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800376 controller_(::std::move(controller)),
377 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700378 Reset();
379 }
380
Austin Schuhc5fceb82017-02-25 16:24:12 -0800381 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800382 : plant_(::std::move(other.plant_)),
383 controller_(::std::move(other.controller_)),
384 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700385 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800386 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700387 U_.swap(other.U_);
388 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800389 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700390 }
391
Austin Schuh1a387962015-01-31 16:36:20 -0800392 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700393
Austin Schuh20388b62017-11-23 22:40:46 -0800394 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800395 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700396 }
Austin Schuh20388b62017-11-23 22:40:46 -0800397 Scalar X_hat(int i, int j) const { return X_hat()(i, j); }
398 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
399 Scalar R(int i, int j) const { return R()(i, j); }
400 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800401 return next_R_;
402 }
Austin Schuh20388b62017-11-23 22:40:46 -0800403 Scalar next_R(int i, int j) const { return next_R()(i, j); }
404 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
405 Scalar U(int i, int j) const { return U()(i, j); }
406 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700407 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700408 }
Austin Schuh20388b62017-11-23 22:40:46 -0800409 Scalar U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
410 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800411 return ff_U_;
412 }
Austin Schuh20388b62017-11-23 22:40:46 -0800413 Scalar ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700414
Austin Schuh20388b62017-11-23 22:40:46 -0800415 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800416 return observer_.mutable_X_hat();
417 }
Austin Schuh20388b62017-11-23 22:40:46 -0800418 Scalar &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
419 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
420 Scalar &mutable_R(int i, int j) { return mutable_R()(i, j); }
421 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800422 return next_R_;
423 }
Austin Schuh20388b62017-11-23 22:40:46 -0800424 Scalar &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
425 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
426 Scalar &mutable_U(int i, int j) { return mutable_U()(i, j); }
427 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700428 return U_uncapped_;
429 }
Austin Schuh20388b62017-11-23 22:40:46 -0800430 Scalar &mutable_U_uncapped(int i, int j) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700431 return mutable_U_uncapped()(i, j);
432 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800433
Austin Schuhe91f14c2017-02-25 19:43:57 -0800434 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800435 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800436
Austin Schuh32501832017-02-25 18:32:56 -0800437 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800438 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800439 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800440 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700441 }
442
Austin Schuhe91f14c2017-02-25 19:43:57 -0800443 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700444
Austin Schuh9644e1c2013-03-12 00:40:36 -0700445 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700446 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800447 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700448 U_.setZero();
449 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800450 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800451
452 plant_.Reset();
453 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800454 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800455 }
456
457 // If U is outside the hardware range, limit it before the plant tries to use
458 // it.
459 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400460 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800461 if (U(i, 0) > plant().U_max(i, 0)) {
462 U_(i, 0) = plant().U_max(i, 0);
463 } else if (U(i, 0) < plant().U_min(i, 0)) {
464 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800465 }
466 }
467 }
468
Austin Schuhf9286cd2014-02-11 00:51:09 -0800469 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800470 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800471 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800472 }
473
Austin Schuh20388b62017-11-23 22:40:46 -0800474 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800475 return R() - X_hat();
476 }
477
Austin Schuhb6a6d822016-02-08 00:20:40 -0800478 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800479 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800480 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800481 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800482 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800483 }
484
485 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800486 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800487 // TODO(austin): Should this live in StateSpaceController?
488 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800489 }
490
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800491 // stop_motors is whether or not to output all 0s.
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800492 void Update(bool stop_motors,
493 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(5)) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800494 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700495 U_.setZero();
496 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800497 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800498 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800499 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800500 CapU();
501 }
502
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800503 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800504
505 UpdateFFReference();
506 }
507
508 // Updates R() after any CapU operations happen on U().
509 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800510 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800511 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800512 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800513 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000514 }
515
Austin Schuh20388b62017-11-23 22:40:46 -0800516 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800517 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800518 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800519 }
520
Austin Schuh32501832017-02-25 18:32:56 -0800521 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800522 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800523 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800524 controller_.set_index(index);
525 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700526 }
527
Austin Schuh32501832017-02-25 18:32:56 -0800528 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700529
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800530 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800531 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800532
Austin Schuh20388b62017-11-23 22:40:46 -0800533 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
534 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800535 controller_;
536
Austin Schuhe91f14c2017-02-25 19:43:57 -0800537 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700538
Brian Silverman273d8a32014-05-10 22:19:09 -0700539 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800540 static constexpr int kNumStates = number_of_states;
541 static constexpr int kNumOutputs = number_of_outputs;
542 static constexpr int kNumInputs = number_of_inputs;
543
544 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800545 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700546
Brian Silverman273d8a32014-05-10 22:19:09 -0700547 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800548 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800549 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800550 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800551 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800552 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800553 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800554 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800555 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700556
Brian Silverman0a151c92014-05-02 15:28:44 -0700557 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800558};
559
Brian Silverman273d8a32014-05-10 22:19:09 -0700560#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_