blob: 0e4be89a849b817e0db3801095cda9599bde746b [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
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cassert>
Tyler Chatow6738c362019-02-16 14:12:30 -08005#include <chrono>
Austin Schuhc5fceb82017-02-25 16:24:12 -08006#include <memory>
7#include <utility>
8#include <vector>
Brian Silvermanc571e052013-03-13 17:58:56 -07009
Austin Schuhdc1c84a2013-02-23 16:33:10 -080010#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080011#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080012
Brian Silverman6260c092018-01-14 15:21:36 -080013#if defined(__linux__)
John Park33858a32018-09-28 23:05:48 -070014#include "aos/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080015#endif
John Park33858a32018-09-28 23:05:48 -070016#include "aos/macros.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070017
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),
James Kuszmaul03be1242020-02-21 14:52:04 -080041 U_max(other.U_max),
Austin Schuh64433f12022-02-21 19:40:38 -080042 dt(other.dt),
43 delayed_u(other.delayed_u) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080044
Austin Schuhe3490622013-03-13 01:24:30 -070045 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080046 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080047 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
48 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
49 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
50 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080051 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
Austin Schuh64433f12022-02-21 19:40:38 -080052 const std::chrono::nanoseconds dt, bool delayed_u)
53 : A(A),
54 B(B),
55 C(C),
56 D(D),
57 U_min(U_min),
58 U_max(U_max),
59 dt(dt),
60 delayed_u(delayed_u) {}
Austin Schuhe3490622013-03-13 01:24:30 -070061
Austin Schuh20388b62017-11-23 22:40:46 -080062 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080063 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
64 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
65 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
66 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
67 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
James Kuszmaul03be1242020-02-21 14:52:04 -080068 const std::chrono::nanoseconds dt;
Austin Schuh64433f12022-02-21 19:40:38 -080069
70 // If true, this adds a single cycle output delay model to the plant. This is
71 // useful for modeling a control loop cycle where you sample, compute, and
72 // then queue the outputs to be ready to be executed when the next cycle
73 // happens.
74 const bool delayed_u;
Austin Schuhe3490622013-03-13 01:24:30 -070075};
76
Austin Schuh20388b62017-11-23 22:40:46 -080077template <int number_of_states, int number_of_inputs, int number_of_outputs,
78 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070079class StateFeedbackPlant {
80 public:
81 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070082
83 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080084 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080085 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -070086 &&coefficients)
87 : coefficients_(::std::move(coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070088 Reset();
89 }
90
Tyler Chatow6738c362019-02-16 14:12:30 -080091 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070092 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070093 X_.swap(other.X_);
94 Y_.swap(other.Y_);
Austin Schuh64433f12022-02-21 19:40:38 -080095 last_U_.swap(other.last_U_);
Brian Silverman0a151c92014-05-02 15:28:44 -070096 }
97
Austin Schuh1a387962015-01-31 16:36:20 -080098 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070099
Austin Schuh20388b62017-11-23 22:40:46 -0800100 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800101 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -0700102 }
Austin Schuh20388b62017-11-23 22:40:46 -0800103 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800104 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800105 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700106 }
Austin Schuh20388b62017-11-23 22:40:46 -0800107 Scalar B(int i, int j) const { return B()(i, j); }
108 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800109 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700110 }
Austin Schuh20388b62017-11-23 22:40:46 -0800111 Scalar C(int i, int j) const { return C()(i, j); }
112 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800113 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700114 }
Austin Schuh20388b62017-11-23 22:40:46 -0800115 Scalar D(int i, int j) const { return D()(i, j); }
116 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800117 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700118 }
Austin Schuh20388b62017-11-23 22:40:46 -0800119 Scalar U_min(int i, int j) const { return U_min()(i, j); }
120 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800121 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700122 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800123 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700124
Austin Schuh43b9ae92020-02-29 23:08:38 -0800125 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
126
Austin Schuh20388b62017-11-23 22:40:46 -0800127 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800128 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800129 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800130 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700131
Austin Schuh20388b62017-11-23 22:40:46 -0800132 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800133 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800134 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800135 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700136
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800137 size_t coefficients_size() const { return coefficients_.size(); }
138
Austin Schuhb6a6d822016-02-08 00:20:40 -0800139 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800140 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800141 &coefficients(int index) const {
142 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700143 }
144
Austin Schuhc5fceb82017-02-25 16:24:12 -0800145 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800146 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800147 &coefficients() const {
148 return *coefficients_[index_];
149 }
150
151 int index() const { return index_; }
152 void set_index(int index) {
153 assert(index >= 0);
154 assert(index < static_cast<int>(coefficients_.size()));
155 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700156 }
157
158 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700159 X_.setZero();
160 Y_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800161 last_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800162 }
163
Austin Schuh849f0032013-03-03 23:59:53 -0800164 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800165 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400166 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800167 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
168 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800169#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700170 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800171#else
172 abort();
173#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800174 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800175 }
176 }
Austin Schuh849f0032013-03-03 23:59:53 -0800177
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800178 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800179 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800180 // Powers outside of the range are more likely controller bugs than things
181 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800182 CheckU(U);
Austin Schuh64433f12022-02-21 19:40:38 -0800183 if (coefficients().delayed_u) {
184 X_ = Update(X(), last_U_);
185 UpdateY(last_U_);
186 last_U_ = U;
187 } else {
188 X_ = Update(X(), U);
189 UpdateY(U);
190 }
Austin Schuh01c7b252017-03-05 00:59:31 -0800191 }
192
193 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800194 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800195 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800196 }
197
Austin Schuh20388b62017-11-23 22:40:46 -0800198 Eigen::Matrix<Scalar, number_of_states, 1> Update(
199 const Eigen::Matrix<Scalar, number_of_states, 1> X,
200 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800201 return A() * X + B() * U;
202 }
203
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800204 protected:
205 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800206 static const int kNumStates = number_of_states;
207 static const int kNumOutputs = number_of_outputs;
208 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700209
210 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800211 Eigen::Matrix<Scalar, number_of_states, 1> X_;
212 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Austin Schuh64433f12022-02-21 19:40:38 -0800213 Eigen::Matrix<Scalar, number_of_inputs, 1> last_U_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700214
Austin Schuhb6a6d822016-02-08 00:20:40 -0800215 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800216 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800217 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700218
Austin Schuhc5fceb82017-02-25 16:24:12 -0800219 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700220
221 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800222};
223
Austin Schuh32501832017-02-25 18:32:56 -0800224// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800225template <int number_of_states, int number_of_inputs, int number_of_outputs,
226 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800227struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700228 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700229
Austin Schuh20388b62017-11-23 22:40:46 -0800230 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
231 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700232
Austin Schuh32501832017-02-25 18:32:56 -0800233 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800234 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
235 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800236 : K(K), Kff(Kff) {}
237};
238
Austin Schuh20388b62017-11-23 22:40:46 -0800239template <int number_of_states, int number_of_inputs, int number_of_outputs,
240 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800241class StateFeedbackController {
242 public:
243 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
244
245 explicit StateFeedbackController(
246 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800247 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700248 &&controllers)
249 : coefficients_(::std::move(controllers)) {}
Austin Schuh32501832017-02-25 18:32:56 -0800250
251 StateFeedbackController(StateFeedbackController &&other)
252 : index_(other.index_) {
253 ::std::swap(coefficients_, other.coefficients_);
254 }
255
Austin Schuh20388b62017-11-23 22:40:46 -0800256 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800257 return coefficients().K;
258 }
Austin Schuh20388b62017-11-23 22:40:46 -0800259 Scalar K(int i, int j) const { return K()(i, j); }
260 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800261 return coefficients().Kff;
262 }
Austin Schuh20388b62017-11-23 22:40:46 -0800263 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800264
Austin Schuhe91f14c2017-02-25 19:43:57 -0800265 void Reset() {}
266
Austin Schuh32501832017-02-25 18:32:56 -0800267 // Sets the current controller to be index, clamped to be within range.
268 void set_index(int index) {
269 if (index < 0) {
270 index_ = 0;
271 } else if (index >= static_cast<int>(coefficients_.size())) {
272 index_ = static_cast<int>(coefficients_.size()) - 1;
273 } else {
274 index_ = index;
275 }
276 }
277
278 int index() const { return index_; }
279
280 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800281 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800282 &coefficients(int index) const {
283 return *coefficients_[index];
284 }
285
286 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800287 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800288 &coefficients() const {
289 return *coefficients_[index_];
290 }
291
292 private:
293 int index_ = 0;
294 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800295 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800296 coefficients_;
297};
298
Austin Schuh32501832017-02-25 18:32:56 -0800299// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800300template <int number_of_states, int number_of_inputs, int number_of_outputs,
301 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800302struct StateFeedbackObserverCoefficients final {
303 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
304
Sabina Davis3922dfa2018-02-10 23:10:05 -0800305 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800306 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
307 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800308
Austin Schuh64433f12022-02-21 19:40:38 -0800309 // If true, this adds a single cycle output delay model to the plant. This is
310 // useful for modeling a control loop cycle where you sample, compute, and
311 // then queue the outputs to be ready to be executed when the next cycle
312 // happens.
313 const bool delayed_u;
314
Austin Schuh32501832017-02-25 18:32:56 -0800315 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800316 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
317 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800318 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
Austin Schuh64433f12022-02-21 19:40:38 -0800319 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R,
320 bool delayed_u)
321 : KalmanGain(KalmanGain), Q(Q), R(R), delayed_u(delayed_u) {}
Austin Schuh32501832017-02-25 18:32:56 -0800322};
323
Austin Schuh20388b62017-11-23 22:40:46 -0800324template <int number_of_states, int number_of_inputs, int number_of_outputs,
325 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800326class StateFeedbackObserver {
327 public:
328 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
329
330 explicit StateFeedbackObserver(
331 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800332 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700333 &&observers)
334 : coefficients_(::std::move(observers)) {}
Austin Schuh32501832017-02-25 18:32:56 -0800335
336 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuh64433f12022-02-21 19:40:38 -0800337 : X_hat_(other.X_hat_), last_U_(other.last_U_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800338 ::std::swap(coefficients_, other.coefficients_);
339 }
340
Tyler Chatow6738c362019-02-16 14:12:30 -0800341 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
342 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800343 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800344 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800345 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800346
Austin Schuh20388b62017-11-23 22:40:46 -0800347 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800348 return X_hat_;
349 }
Austin Schuh20388b62017-11-23 22:40:46 -0800350 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800351
Austin Schuh6501d232017-11-23 20:35:27 -0800352 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800353 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800354 X_hat_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800355 last_U_.setZero();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800356 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800357
Austin Schuh6501d232017-11-23 20:35:27 -0800358 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800359 number_of_outputs, Scalar> *plant,
360 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800361 ::std::chrono::nanoseconds /*dt*/) {
Austin Schuh64433f12022-02-21 19:40:38 -0800362 if (plant->coefficients().delayed_u) {
363 mutable_X_hat() = plant->Update(X_hat(), last_U_);
364 last_U_ = new_u;
365 } else {
366 mutable_X_hat() = plant->Update(X_hat(), new_u);
367 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800368 }
369
Austin Schuh6501d232017-11-23 20:35:27 -0800370 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800371 number_of_outputs, Scalar> &plant,
372 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
373 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Tyler Chatow6738c362019-02-16 14:12:30 -0800374 mutable_X_hat() += KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800375 }
376
Austin Schuh32501832017-02-25 18:32:56 -0800377 // Sets the current controller to be index, clamped to be within range.
378 void set_index(int index) {
379 if (index < 0) {
380 index_ = 0;
381 } else if (index >= static_cast<int>(coefficients_.size())) {
382 index_ = static_cast<int>(coefficients_.size()) - 1;
383 } else {
384 index_ = index;
385 }
386 }
387
388 int index() const { return index_; }
389
390 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800391 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800392 &coefficients(int index) const {
393 return *coefficients_[index];
394 }
395
396 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800397 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800398 &coefficients() const {
399 return *coefficients_[index_];
400 }
401
402 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800403 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800404 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuh64433f12022-02-21 19:40:38 -0800405 Eigen::Matrix<Scalar, number_of_inputs, 1> last_U_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800406
Austin Schuh32501832017-02-25 18:32:56 -0800407 int index_ = 0;
408 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800409 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800410 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700411};
412
Austin Schuhe91f14c2017-02-25 19:43:57 -0800413template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800414 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800415 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800416 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800417 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800418 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800419class StateFeedbackLoop {
420 public:
421 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
422
Austin Schuh32501832017-02-25 18:32:56 -0800423 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800424 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800425 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800426 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800427 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800428 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800429 controller_(::std::move(controller)),
430 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700431 Reset();
432 }
433
Austin Schuhc5fceb82017-02-25 16:24:12 -0800434 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800435 : plant_(::std::move(other.plant_)),
436 controller_(::std::move(other.controller_)),
437 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800438 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700439 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800440 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700441 U_.swap(other.U_);
442 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700443 }
444
Austin Schuh1a387962015-01-31 16:36:20 -0800445 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700446
Austin Schuh20388b62017-11-23 22:40:46 -0800447 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800448 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700449 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800450 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800451 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800452 Scalar R(int i, int j = 0) const { return R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800453 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800454 return next_R_;
455 }
Austin Schuh95771d92021-01-23 14:42:25 -0800456 Scalar next_R(int i, int j = 0) const { return next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800457 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800458 Scalar U(int i, int j = 0) const { return U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800459 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700460 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700461 }
Austin Schuh95771d92021-01-23 14:42:25 -0800462 Scalar U_uncapped(int i, int j = 0) const { return U_uncapped()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800463 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800464 return ff_U_;
465 }
Austin Schuh95771d92021-01-23 14:42:25 -0800466 Scalar ff_U(int i, int j = 0) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700467
Austin Schuh20388b62017-11-23 22:40:46 -0800468 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800469 return observer_.mutable_X_hat();
470 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800471 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800472 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800473 Scalar &mutable_R(int i, int j = 0) { return mutable_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800474 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800475 return next_R_;
476 }
Austin Schuh95771d92021-01-23 14:42:25 -0800477 Scalar &mutable_next_R(int i, int j = 0) { return mutable_next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800478 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800479 Scalar &mutable_U(int i, int j = 0) { return mutable_U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800480 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700481 return U_uncapped_;
482 }
Austin Schuh95771d92021-01-23 14:42:25 -0800483 Scalar &mutable_U_uncapped(int i, int j = 0) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700484 return mutable_U_uncapped()(i, j);
485 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800486
Austin Schuhe91f14c2017-02-25 19:43:57 -0800487 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800488 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800489
Austin Schuh32501832017-02-25 18:32:56 -0800490 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800491 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800492 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800493 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700494 }
495
Austin Schuhe91f14c2017-02-25 19:43:57 -0800496 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700497
Austin Schuh9644e1c2013-03-12 00:40:36 -0700498 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700499 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800500 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700501 U_.setZero();
502 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800503 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800504
505 plant_.Reset();
506 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800507 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800508 }
509
510 // If U is outside the hardware range, limit it before the plant tries to use
511 // it.
512 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400513 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800514 if (U(i, 0) > plant().U_max(i, 0)) {
515 U_(i, 0) = plant().U_max(i, 0);
516 } else if (U(i, 0) < plant().U_min(i, 0)) {
517 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800518 }
519 }
520 }
521
Austin Schuhf9286cd2014-02-11 00:51:09 -0800522 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800523 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800524 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800525 }
526
Austin Schuh20388b62017-11-23 22:40:46 -0800527 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800528 return R() - X_hat();
529 }
530
Austin Schuhb6a6d822016-02-08 00:20:40 -0800531 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800532 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800533 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800534 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800535 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800536 }
537
538 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800539 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800540 // TODO(austin): Should this live in StateSpaceController?
541 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800542 }
543
Austin Schuh43b9ae92020-02-29 23:08:38 -0800544 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800545 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700546 U_.setZero();
547 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800548 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800549 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800550 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800551 CapU();
552 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800553 UpdateFFReference();
554 }
555
556 // stop_motors is whether or not to output all 0s.
557 void Update(bool stop_motors,
558 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
559 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800560
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800561 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800562 }
563
564 // Updates R() after any CapU operations happen on U().
565 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800566 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800567 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800568 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800569 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000570 }
571
Austin Schuh20388b62017-11-23 22:40:46 -0800572 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800573 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800574 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800575 }
576
Austin Schuh32501832017-02-25 18:32:56 -0800577 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800578 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800579 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800580 controller_.set_index(index);
581 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700582 }
583
Austin Schuh32501832017-02-25 18:32:56 -0800584 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700585
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800586 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800587 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800588
Austin Schuh20388b62017-11-23 22:40:46 -0800589 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
590 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800591 controller_;
592
Austin Schuhe91f14c2017-02-25 19:43:57 -0800593 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700594
Brian Silverman273d8a32014-05-10 22:19:09 -0700595 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800596 static constexpr int kNumStates = number_of_states;
597 static constexpr int kNumOutputs = number_of_outputs;
598 static constexpr int kNumInputs = number_of_inputs;
599
600 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800601 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700602
Brian Silverman273d8a32014-05-10 22:19:09 -0700603 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800604 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800605 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800606 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800607 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800608 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800609 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800610 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800611 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700612
Brian Silverman0a151c92014-05-02 15:28:44 -0700613 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800614};
615
Brian Silverman273d8a32014-05-10 22:19:09 -0700616#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_