blob: 65e0ba16447b10e111819ac76483c2d8ff1d8fc4 [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"
Philipp Schrader790cb542023-07-05 21:06:52 -070011
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__)
Austin Schuhb39f4522022-03-27 13:29:42 -070015#include "glog/logging.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070016
17#include "aos/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080018#endif
John Park33858a32018-09-28 23:05:48 -070019#include "aos/macros.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070020
Austin Schuhe91f14c2017-02-25 19:43:57 -080021template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080022 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080023class StateFeedbackLoop;
24
Brian Silverman5808bcb2014-09-14 21:40:43 -040025// For everything in this file, "inputs" and "outputs" are defined from the
26// perspective of the plant. This means U is an input and Y is an output
27// (because you give the plant U (powers) and it gives you back a Y (sensor
28// values). This is the opposite of what they mean from the perspective of the
29// controller (U is an output because that's what goes to the motors and Y is an
30// input because that's what comes back from the sensors).
31
Austin Schuh20388b62017-11-23 22:40:46 -080032template <int number_of_states, int number_of_inputs, int number_of_outputs,
33 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080034struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080035 public:
36 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
37
Austin Schuhe3490622013-03-13 01:24:30 -070038 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080039 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080040 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080041 C(other.C),
42 D(other.D),
43 U_min(other.U_min),
James Kuszmaul03be1242020-02-21 14:52:04 -080044 U_max(other.U_max),
Austin Schuh64433f12022-02-21 19:40:38 -080045 dt(other.dt),
46 delayed_u(other.delayed_u) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080047
Austin Schuhe3490622013-03-13 01:24:30 -070048 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080049 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080050 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
51 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
52 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
53 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080054 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
Austin Schuhb39f4522022-03-27 13:29:42 -070055 const std::chrono::nanoseconds dt, size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -080056 : A(A),
57 B(B),
58 C(C),
59 D(D),
60 U_min(U_min),
61 U_max(U_max),
62 dt(dt),
63 delayed_u(delayed_u) {}
Austin Schuhe3490622013-03-13 01:24:30 -070064
Austin Schuh20388b62017-11-23 22:40:46 -080065 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080066 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
67 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
68 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
69 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
70 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
James Kuszmaul03be1242020-02-21 14:52:04 -080071 const std::chrono::nanoseconds dt;
Austin Schuh64433f12022-02-21 19:40:38 -080072
73 // If true, this adds a single cycle output delay model to the plant. This is
74 // useful for modeling a control loop cycle where you sample, compute, and
75 // then queue the outputs to be ready to be executed when the next cycle
76 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -070077 const size_t delayed_u;
Austin Schuhe3490622013-03-13 01:24:30 -070078};
79
Austin Schuh20388b62017-11-23 22:40:46 -080080template <int number_of_states, int number_of_inputs, int number_of_outputs,
81 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070082class StateFeedbackPlant {
83 public:
84 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070085
86 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080087 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080088 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -070089 &&coefficients)
90 : coefficients_(::std::move(coefficients)), index_(0) {
Austin Schuhb39f4522022-03-27 13:29:42 -070091 if (coefficients_.size() > 1u) {
92 for (size_t i = 1; i < coefficients_.size(); ++i) {
93 if (coefficients_[i]->delayed_u != coefficients_[0]->delayed_u) {
94 abort();
95 }
96 }
97 }
98 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
99 number_of_inputs,
100 std::max(static_cast<size_t>(1u), coefficients_[0]->delayed_u));
Brian Silverman0a151c92014-05-02 15:28:44 -0700101 Reset();
102 }
103
Tyler Chatow6738c362019-02-16 14:12:30 -0800104 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -0700105 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700106 X_.swap(other.X_);
107 Y_.swap(other.Y_);
Austin Schuh64433f12022-02-21 19:40:38 -0800108 last_U_.swap(other.last_U_);
Brian Silverman0a151c92014-05-02 15:28:44 -0700109 }
110
Austin Schuh1a387962015-01-31 16:36:20 -0800111 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700112
Austin Schuh20388b62017-11-23 22:40:46 -0800113 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800114 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -0700115 }
Austin Schuh20388b62017-11-23 22:40:46 -0800116 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800117 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800118 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700119 }
Austin Schuh20388b62017-11-23 22:40:46 -0800120 Scalar B(int i, int j) const { return B()(i, j); }
121 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800122 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700123 }
Austin Schuh20388b62017-11-23 22:40:46 -0800124 Scalar C(int i, int j) const { return C()(i, j); }
125 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800126 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700127 }
Austin Schuh20388b62017-11-23 22:40:46 -0800128 Scalar D(int i, int j) const { return D()(i, j); }
129 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800130 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700131 }
Austin Schuh20388b62017-11-23 22:40:46 -0800132 Scalar U_min(int i, int j) const { return U_min()(i, j); }
133 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800134 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700135 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800136 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700137
Austin Schuh43b9ae92020-02-29 23:08:38 -0800138 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
139
Austin Schuh20388b62017-11-23 22:40:46 -0800140 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800141 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800142 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800143 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700144
Austin Schuh20388b62017-11-23 22:40:46 -0800145 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800146 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800147 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800148 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700149
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800150 size_t coefficients_size() const { return coefficients_.size(); }
151
Austin Schuhb6a6d822016-02-08 00:20:40 -0800152 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800153 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800154 &coefficients(int index) const {
155 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700156 }
157
Austin Schuhc5fceb82017-02-25 16:24:12 -0800158 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800159 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800160 &coefficients() const {
161 return *coefficients_[index_];
162 }
163
164 int index() const { return index_; }
165 void set_index(int index) {
166 assert(index >= 0);
167 assert(index < static_cast<int>(coefficients_.size()));
168 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700169 }
170
171 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700172 X_.setZero();
173 Y_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800174 last_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800175 }
176
Austin Schuh849f0032013-03-03 23:59:53 -0800177 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800178 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400179 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800180 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
181 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800182#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700183 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800184#else
185 abort();
186#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800187 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800188 }
189 }
Austin Schuh849f0032013-03-03 23:59:53 -0800190
Austin Schuhb39f4522022-03-27 13:29:42 -0700191 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
192 size_t index = 0) const {
193 return last_U_.template block<number_of_inputs, 1>(0, index);
194 }
195
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800196 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800197 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800198 // Powers outside of the range are more likely controller bugs than things
199 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800200 CheckU(U);
Austin Schuhb39f4522022-03-27 13:29:42 -0700201 if (coefficients().delayed_u > 0) {
202#if defined(__linux__)
203 DCHECK_EQ(static_cast<ssize_t>(coefficients().delayed_u), last_U_.cols());
204#endif
205 X_ = Update(X(), last_U(coefficients().delayed_u - 1));
206 UpdateY(last_U(coefficients().delayed_u - 1));
207 for (int i = coefficients().delayed_u; i > 1; --i) {
208 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
209 last_U_.template block<number_of_inputs, 1>(0, i - 2);
210 }
211 last_U_.template block<number_of_inputs, 1>(0, 0) = U;
Austin Schuh64433f12022-02-21 19:40:38 -0800212 } else {
213 X_ = Update(X(), U);
214 UpdateY(U);
215 }
Austin Schuh01c7b252017-03-05 00:59:31 -0800216 }
217
218 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800219 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800220 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800221 }
222
Austin Schuh20388b62017-11-23 22:40:46 -0800223 Eigen::Matrix<Scalar, number_of_states, 1> Update(
224 const Eigen::Matrix<Scalar, number_of_states, 1> X,
225 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800226 return A() * X + B() * U;
227 }
228
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800229 protected:
230 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800231 static const int kNumStates = number_of_states;
232 static const int kNumOutputs = number_of_outputs;
233 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700234
235 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800236 Eigen::Matrix<Scalar, number_of_states, 1> X_;
237 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Austin Schuhb39f4522022-03-27 13:29:42 -0700238 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700239
Austin Schuhb6a6d822016-02-08 00:20:40 -0800240 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800241 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800242 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700243
Austin Schuhc5fceb82017-02-25 16:24:12 -0800244 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700245
246 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800247};
248
Austin Schuh32501832017-02-25 18:32:56 -0800249// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800250template <int number_of_states, int number_of_inputs, int number_of_outputs,
251 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800252struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700253 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700254
Austin Schuh20388b62017-11-23 22:40:46 -0800255 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
256 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700257
Austin Schuh32501832017-02-25 18:32:56 -0800258 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800259 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
260 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800261 : K(K), Kff(Kff) {}
262};
263
Austin Schuh20388b62017-11-23 22:40:46 -0800264template <int number_of_states, int number_of_inputs, int number_of_outputs,
265 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800266class StateFeedbackController {
267 public:
268 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
269
270 explicit StateFeedbackController(
271 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800272 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700273 &&controllers)
274 : coefficients_(::std::move(controllers)) {}
Austin Schuh32501832017-02-25 18:32:56 -0800275
276 StateFeedbackController(StateFeedbackController &&other)
277 : index_(other.index_) {
278 ::std::swap(coefficients_, other.coefficients_);
279 }
280
Austin Schuh20388b62017-11-23 22:40:46 -0800281 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800282 return coefficients().K;
283 }
Austin Schuh20388b62017-11-23 22:40:46 -0800284 Scalar K(int i, int j) const { return K()(i, j); }
285 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800286 return coefficients().Kff;
287 }
Austin Schuh20388b62017-11-23 22:40:46 -0800288 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800289
Austin Schuhe91f14c2017-02-25 19:43:57 -0800290 void Reset() {}
291
Austin Schuh32501832017-02-25 18:32:56 -0800292 // Sets the current controller to be index, clamped to be within range.
293 void set_index(int index) {
294 if (index < 0) {
295 index_ = 0;
296 } else if (index >= static_cast<int>(coefficients_.size())) {
297 index_ = static_cast<int>(coefficients_.size()) - 1;
298 } else {
299 index_ = index;
300 }
301 }
302
303 int index() const { return index_; }
304
305 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800306 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800307 &coefficients(int index) const {
308 return *coefficients_[index];
309 }
310
311 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800312 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800313 &coefficients() const {
314 return *coefficients_[index_];
315 }
316
317 private:
318 int index_ = 0;
319 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800320 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800321 coefficients_;
322};
323
Austin Schuh32501832017-02-25 18:32:56 -0800324// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800325template <int number_of_states, int number_of_inputs, int number_of_outputs,
326 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800327struct StateFeedbackObserverCoefficients final {
328 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
329
Sabina Davis3922dfa2018-02-10 23:10:05 -0800330 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800331 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
332 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800333
Austin Schuh64433f12022-02-21 19:40:38 -0800334 // If true, this adds a single cycle output delay model to the plant. This is
335 // useful for modeling a control loop cycle where you sample, compute, and
336 // then queue the outputs to be ready to be executed when the next cycle
337 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -0700338 const size_t delayed_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800339
Austin Schuh32501832017-02-25 18:32:56 -0800340 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800341 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
342 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800343 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
Austin Schuh64433f12022-02-21 19:40:38 -0800344 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R,
Austin Schuhb39f4522022-03-27 13:29:42 -0700345 size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -0800346 : KalmanGain(KalmanGain), Q(Q), R(R), delayed_u(delayed_u) {}
Austin Schuh32501832017-02-25 18:32:56 -0800347};
348
Austin Schuh20388b62017-11-23 22:40:46 -0800349template <int number_of_states, int number_of_inputs, int number_of_outputs,
350 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800351class StateFeedbackObserver {
352 public:
353 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
354
355 explicit StateFeedbackObserver(
356 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800357 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700358 &&observers)
Austin Schuhb39f4522022-03-27 13:29:42 -0700359 : coefficients_(::std::move(observers)) {
360 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
Philipp Schrader790cb542023-07-05 21:06:52 -0700361 number_of_inputs,
362 std::max(static_cast<size_t>(1u), coefficients().delayed_u));
Austin Schuhb39f4522022-03-27 13:29:42 -0700363 }
Austin Schuh32501832017-02-25 18:32:56 -0800364
365 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuh64433f12022-02-21 19:40:38 -0800366 : X_hat_(other.X_hat_), last_U_(other.last_U_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800367 ::std::swap(coefficients_, other.coefficients_);
368 }
369
Tyler Chatow6738c362019-02-16 14:12:30 -0800370 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
371 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800372 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800373 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800374 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800375
Austin Schuh20388b62017-11-23 22:40:46 -0800376 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800377 return X_hat_;
378 }
Austin Schuh20388b62017-11-23 22:40:46 -0800379 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800380
Austin Schuhb39f4522022-03-27 13:29:42 -0700381 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
382 size_t index = 0) const {
383 return last_U_.template block<number_of_inputs, 1>(0, index);
Austin Schuh482a9142022-02-23 16:54:39 -0800384 }
385
Austin Schuh6501d232017-11-23 20:35:27 -0800386 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800387 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800388 X_hat_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800389 last_U_.setZero();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800390 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800391
Austin Schuh6501d232017-11-23 20:35:27 -0800392 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800393 number_of_outputs, Scalar> *plant,
394 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800395 ::std::chrono::nanoseconds /*dt*/) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700396 if (plant->coefficients().delayed_u > 0) {
397 mutable_X_hat() =
398 plant->Update(X_hat(), last_U(coefficients().delayed_u - 1));
399 for (int i = coefficients().delayed_u; i > 1; --i) {
400 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
401 last_U_.template block<number_of_inputs, 1>(0, i - 2);
402 }
403 last_U_.template block<number_of_inputs, 1>(0, 0) = new_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800404 } else {
405 mutable_X_hat() = plant->Update(X_hat(), new_u);
406 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800407 }
408
Austin Schuh6501d232017-11-23 20:35:27 -0800409 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800410 number_of_outputs, Scalar> &plant,
411 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
412 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Tyler Chatow6738c362019-02-16 14:12:30 -0800413 mutable_X_hat() += KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800414 }
415
Austin Schuh32501832017-02-25 18:32:56 -0800416 // Sets the current controller to be index, clamped to be within range.
417 void set_index(int index) {
418 if (index < 0) {
419 index_ = 0;
420 } else if (index >= static_cast<int>(coefficients_.size())) {
421 index_ = static_cast<int>(coefficients_.size()) - 1;
422 } else {
423 index_ = index;
424 }
425 }
426
427 int index() const { return index_; }
428
429 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800430 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800431 &coefficients(int index) const {
432 return *coefficients_[index];
433 }
434
435 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800436 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800437 &coefficients() const {
438 return *coefficients_[index_];
439 }
440
441 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800442 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800443 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhb39f4522022-03-27 13:29:42 -0700444 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800445
Austin Schuh32501832017-02-25 18:32:56 -0800446 int index_ = 0;
447 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800448 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800449 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700450};
451
Austin Schuhe91f14c2017-02-25 19:43:57 -0800452template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800453 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800454 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800455 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800456 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800457 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800458class StateFeedbackLoop {
459 public:
460 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
461
Austin Schuh32501832017-02-25 18:32:56 -0800462 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800463 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800464 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800465 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800466 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800467 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800468 controller_(::std::move(controller)),
469 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700470 Reset();
471 }
472
Austin Schuhc5fceb82017-02-25 16:24:12 -0800473 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800474 : plant_(::std::move(other.plant_)),
475 controller_(::std::move(other.controller_)),
476 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800477 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700478 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800479 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700480 U_.swap(other.U_);
481 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700482 }
483
Austin Schuh1a387962015-01-31 16:36:20 -0800484 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700485
Austin Schuh20388b62017-11-23 22:40:46 -0800486 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800487 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700488 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800489 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800490 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800491 Scalar R(int i, int j = 0) const { return R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800492 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800493 return next_R_;
494 }
Austin Schuh95771d92021-01-23 14:42:25 -0800495 Scalar next_R(int i, int j = 0) const { return next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800496 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800497 Scalar U(int i, int j = 0) const { return U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800498 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700499 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700500 }
Austin Schuh95771d92021-01-23 14:42:25 -0800501 Scalar U_uncapped(int i, int j = 0) const { return U_uncapped()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800502 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800503 return ff_U_;
504 }
Austin Schuh95771d92021-01-23 14:42:25 -0800505 Scalar ff_U(int i, int j = 0) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700506
Austin Schuh20388b62017-11-23 22:40:46 -0800507 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800508 return observer_.mutable_X_hat();
509 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800510 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800511 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800512 Scalar &mutable_R(int i, int j = 0) { return mutable_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800513 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800514 return next_R_;
515 }
Austin Schuh95771d92021-01-23 14:42:25 -0800516 Scalar &mutable_next_R(int i, int j = 0) { return mutable_next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800517 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800518 Scalar &mutable_U(int i, int j = 0) { return mutable_U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800519 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700520 return U_uncapped_;
521 }
Austin Schuh95771d92021-01-23 14:42:25 -0800522 Scalar &mutable_U_uncapped(int i, int j = 0) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700523 return mutable_U_uncapped()(i, j);
524 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800525
Austin Schuhe91f14c2017-02-25 19:43:57 -0800526 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800527 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800528
Austin Schuh32501832017-02-25 18:32:56 -0800529 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800530 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800531 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800532 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700533 }
534
Austin Schuhe91f14c2017-02-25 19:43:57 -0800535 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700536
Austin Schuh9644e1c2013-03-12 00:40:36 -0700537 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700538 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800539 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700540 U_.setZero();
541 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800542 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800543
544 plant_.Reset();
545 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800546 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800547 }
548
549 // If U is outside the hardware range, limit it before the plant tries to use
550 // it.
551 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400552 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800553 if (U(i, 0) > plant().U_max(i, 0)) {
554 U_(i, 0) = plant().U_max(i, 0);
555 } else if (U(i, 0) < plant().U_min(i, 0)) {
556 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800557 }
558 }
559 }
560
Austin Schuhf9286cd2014-02-11 00:51:09 -0800561 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800562 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800563 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800564 }
565
Austin Schuh20388b62017-11-23 22:40:46 -0800566 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800567 return R() - X_hat();
568 }
569
Austin Schuhb6a6d822016-02-08 00:20:40 -0800570 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800571 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800572 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800573 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800574 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800575 }
576
577 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800578 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800579 // TODO(austin): Should this live in StateSpaceController?
580 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800581 }
582
Austin Schuh43b9ae92020-02-29 23:08:38 -0800583 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800584 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700585 U_.setZero();
586 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800587 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800588 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800589 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800590 CapU();
591 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800592 UpdateFFReference();
593 }
594
595 // stop_motors is whether or not to output all 0s.
596 void Update(bool stop_motors,
597 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
598 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800599
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800600 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800601 }
602
603 // Updates R() after any CapU operations happen on U().
604 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800605 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800606 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800607 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800608 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000609 }
610
Austin Schuh20388b62017-11-23 22:40:46 -0800611 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800612 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800613 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800614 }
615
Austin Schuh32501832017-02-25 18:32:56 -0800616 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800617 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800618 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800619 controller_.set_index(index);
620 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700621 }
622
Austin Schuh32501832017-02-25 18:32:56 -0800623 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700624
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800625 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800626 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800627
Austin Schuh20388b62017-11-23 22:40:46 -0800628 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
629 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800630 controller_;
631
Austin Schuhe91f14c2017-02-25 19:43:57 -0800632 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700633
Brian Silverman273d8a32014-05-10 22:19:09 -0700634 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800635 static constexpr int kNumStates = number_of_states;
636 static constexpr int kNumOutputs = number_of_outputs;
637 static constexpr int kNumInputs = number_of_inputs;
638
639 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800640 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700641
Brian Silverman273d8a32014-05-10 22:19:09 -0700642 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800643 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800644 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800645 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800646 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800647 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800648 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800649 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800650 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700651
Brian Silverman0a151c92014-05-02 15:28:44 -0700652 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800653};
654
Brian Silverman273d8a32014-05-10 22:19:09 -0700655#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_