blob: 32f27f8173c44d2094dbf3ab15a390bf48507341 [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 Schuh99f7c6a2024-06-25 22:07:44 -070015#include "absl/log/check.h"
16#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070017
18#include "aos/logging/logging.h"
Brian Silverman6260c092018-01-14 15:21:36 -080019#endif
John Park33858a32018-09-28 23:05:48 -070020#include "aos/macros.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070021
Austin Schuhe91f14c2017-02-25 19:43:57 -080022template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080023 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080024class StateFeedbackLoop;
25
Brian Silverman5808bcb2014-09-14 21:40:43 -040026// For everything in this file, "inputs" and "outputs" are defined from the
27// perspective of the plant. This means U is an input and Y is an output
28// (because you give the plant U (powers) and it gives you back a Y (sensor
29// values). This is the opposite of what they mean from the perspective of the
30// controller (U is an output because that's what goes to the motors and Y is an
31// input because that's what comes back from the sensors).
32
Austin Schuh20388b62017-11-23 22:40:46 -080033template <int number_of_states, int number_of_inputs, int number_of_outputs,
34 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080035struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080036 public:
37 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
38
Austin Schuhe3490622013-03-13 01:24:30 -070039 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080040 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080041 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080042 C(other.C),
43 D(other.D),
44 U_min(other.U_min),
James Kuszmaul03be1242020-02-21 14:52:04 -080045 U_max(other.U_max),
Ravago Jonesc471ebe2023-07-05 20:37:00 -070046 U_limit_coefficient(other.U_limit_coefficient),
47 U_limit_constant(other.U_limit_constant),
Austin Schuh64433f12022-02-21 19:40:38 -080048 dt(other.dt),
49 delayed_u(other.delayed_u) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080050
Austin Schuhe3490622013-03-13 01:24:30 -070051 StateFeedbackPlantCoefficients(
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_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080057 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
Ravago Jonesc471ebe2023-07-05 20:37:00 -070058 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
59 &U_limit_coefficient,
60 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant,
Austin Schuhb39f4522022-03-27 13:29:42 -070061 const std::chrono::nanoseconds dt, size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -080062 : A(A),
63 B(B),
64 C(C),
65 D(D),
66 U_min(U_min),
67 U_max(U_max),
Ravago Jonesc471ebe2023-07-05 20:37:00 -070068 U_limit_coefficient(U_limit_coefficient),
69 U_limit_constant(U_limit_constant),
Austin Schuh64433f12022-02-21 19:40:38 -080070 dt(dt),
71 delayed_u(delayed_u) {}
Austin Schuhe3490622013-03-13 01:24:30 -070072
Austin Schuh20388b62017-11-23 22:40:46 -080073 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080074 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
75 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
76 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
77 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
78 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
Ravago Jonesc471ebe2023-07-05 20:37:00 -070079 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
80 U_limit_coefficient;
81 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_limit_constant;
James Kuszmaul03be1242020-02-21 14:52:04 -080082 const std::chrono::nanoseconds dt;
Austin Schuh64433f12022-02-21 19:40:38 -080083
84 // If true, this adds a single cycle output delay model to the plant. This is
85 // useful for modeling a control loop cycle where you sample, compute, and
86 // then queue the outputs to be ready to be executed when the next cycle
87 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -070088 const size_t delayed_u;
Austin Schuhe3490622013-03-13 01:24:30 -070089};
90
Austin Schuh20388b62017-11-23 22:40:46 -080091template <int number_of_states, int number_of_inputs, int number_of_outputs,
92 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070093class StateFeedbackPlant {
94 public:
95 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070096
97 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080098 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080099 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700100 &&coefficients)
101 : coefficients_(::std::move(coefficients)), index_(0) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700102 if (coefficients_.size() > 1u) {
103 for (size_t i = 1; i < coefficients_.size(); ++i) {
104 if (coefficients_[i]->delayed_u != coefficients_[0]->delayed_u) {
105 abort();
106 }
107 }
108 }
109 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
110 number_of_inputs,
111 std::max(static_cast<size_t>(1u), coefficients_[0]->delayed_u));
Brian Silverman0a151c92014-05-02 15:28:44 -0700112 Reset();
113 }
114
Tyler Chatow6738c362019-02-16 14:12:30 -0800115 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -0700116 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700117 X_.swap(other.X_);
118 Y_.swap(other.Y_);
Austin Schuh64433f12022-02-21 19:40:38 -0800119 last_U_.swap(other.last_U_);
Brian Silverman0a151c92014-05-02 15:28:44 -0700120 }
121
Austin Schuh1a387962015-01-31 16:36:20 -0800122 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700123
Austin Schuh20388b62017-11-23 22:40:46 -0800124 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800125 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -0700126 }
Austin Schuh20388b62017-11-23 22:40:46 -0800127 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800128 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800129 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700130 }
Austin Schuh20388b62017-11-23 22:40:46 -0800131 Scalar B(int i, int j) const { return B()(i, j); }
132 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800133 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700134 }
Austin Schuh20388b62017-11-23 22:40:46 -0800135 Scalar C(int i, int j) const { return C()(i, j); }
136 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800137 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700138 }
Austin Schuh20388b62017-11-23 22:40:46 -0800139 Scalar D(int i, int j) const { return D()(i, j); }
140 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800141 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700142 }
Austin Schuh20388b62017-11-23 22:40:46 -0800143 Scalar U_min(int i, int j) const { return U_min()(i, j); }
144 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800145 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700146 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800147 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Austin Schuh50e3dca2023-07-23 14:34:27 -0700148 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &
149 U_limit_coefficient() const {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700150 return coefficients().U_limit_coefficient;
151 }
152 Scalar U_limit_coefficient(int i, int j) const {
153 return U_limit_coefficient()(i, j);
154 }
155 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant() const {
156 return coefficients().U_limit_constant;
157 }
158 Scalar U_limit_constant(int i, int j = 0) const {
159 return U_limit_constant()(i, j);
160 }
Brian Silverman273d8a32014-05-10 22:19:09 -0700161
Austin Schuh43b9ae92020-02-29 23:08:38 -0800162 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
163
Austin Schuh20388b62017-11-23 22:40:46 -0800164 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800165 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800166 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800167 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700168
Austin Schuh20388b62017-11-23 22:40:46 -0800169 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800170 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800171 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800172 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700173
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800174 size_t coefficients_size() const { return coefficients_.size(); }
175
Austin Schuhb6a6d822016-02-08 00:20:40 -0800176 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700177 number_of_outputs, Scalar> &
178 coefficients(int index) const {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800179 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700180 }
181
Austin Schuhc5fceb82017-02-25 16:24:12 -0800182 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700183 number_of_outputs, Scalar> &
184 coefficients() const {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800185 return *coefficients_[index_];
186 }
187
188 int index() const { return index_; }
189 void set_index(int index) {
190 assert(index >= 0);
191 assert(index < static_cast<int>(coefficients_.size()));
192 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700193 }
194
195 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700196 X_.setZero();
197 Y_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800198 last_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800199 }
200
Austin Schuh849f0032013-03-03 23:59:53 -0800201 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800202 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400203 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800204 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
205 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800206#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700207 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800208#else
209 abort();
210#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800211 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800212 }
213 }
Austin Schuh849f0032013-03-03 23:59:53 -0800214
Austin Schuhb39f4522022-03-27 13:29:42 -0700215 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
216 size_t index = 0) const {
217 return last_U_.template block<number_of_inputs, 1>(0, index);
218 }
219
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800220 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800221 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800222 // Powers outside of the range are more likely controller bugs than things
223 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800224 CheckU(U);
Austin Schuhb39f4522022-03-27 13:29:42 -0700225 if (coefficients().delayed_u > 0) {
226#if defined(__linux__)
227 DCHECK_EQ(static_cast<ssize_t>(coefficients().delayed_u), last_U_.cols());
228#endif
229 X_ = Update(X(), last_U(coefficients().delayed_u - 1));
230 UpdateY(last_U(coefficients().delayed_u - 1));
231 for (int i = coefficients().delayed_u; i > 1; --i) {
232 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
233 last_U_.template block<number_of_inputs, 1>(0, i - 2);
234 }
235 last_U_.template block<number_of_inputs, 1>(0, 0) = U;
Austin Schuh64433f12022-02-21 19:40:38 -0800236 } else {
237 X_ = Update(X(), U);
238 UpdateY(U);
239 }
Austin Schuh01c7b252017-03-05 00:59:31 -0800240 }
241
242 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800243 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800244 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800245 }
246
Austin Schuh20388b62017-11-23 22:40:46 -0800247 Eigen::Matrix<Scalar, number_of_states, 1> Update(
248 const Eigen::Matrix<Scalar, number_of_states, 1> X,
249 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800250 return A() * X + B() * U;
251 }
252
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800253 protected:
254 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800255 static const int kNumStates = number_of_states;
256 static const int kNumOutputs = number_of_outputs;
257 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700258
259 private:
Nathan Leongdd728002024-02-03 15:26:53 -0800260 // X_ and Y_ must be explicitly initialized to avoid having gcc complain about
261 // uninitialized values when using the move constructor.
262 Eigen::Matrix<Scalar, number_of_states, 1> X_ =
263 Eigen::Matrix<Scalar, number_of_states, 1>::Zero();
264 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_ =
265 Eigen::Matrix<Scalar, number_of_outputs, 1>::Zero();
Austin Schuhb39f4522022-03-27 13:29:42 -0700266 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700267
Austin Schuhb6a6d822016-02-08 00:20:40 -0800268 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800269 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800270 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700271
Austin Schuhc5fceb82017-02-25 16:24:12 -0800272 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700273
274 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800275};
276
Austin Schuh32501832017-02-25 18:32:56 -0800277// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800278template <int number_of_states, int number_of_inputs, int number_of_outputs,
279 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800280struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700281 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700282
Austin Schuh20388b62017-11-23 22:40:46 -0800283 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
284 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700285
Austin Schuh32501832017-02-25 18:32:56 -0800286 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800287 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
288 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800289 : K(K), Kff(Kff) {}
290};
291
Austin Schuh20388b62017-11-23 22:40:46 -0800292template <int number_of_states, int number_of_inputs, int number_of_outputs,
293 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800294class StateFeedbackController {
295 public:
296 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
297
298 explicit StateFeedbackController(
299 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800300 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700301 &&controllers)
302 : coefficients_(::std::move(controllers)) {}
Austin Schuh32501832017-02-25 18:32:56 -0800303
304 StateFeedbackController(StateFeedbackController &&other)
305 : index_(other.index_) {
306 ::std::swap(coefficients_, other.coefficients_);
307 }
308
Austin Schuh20388b62017-11-23 22:40:46 -0800309 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800310 return coefficients().K;
311 }
Austin Schuh20388b62017-11-23 22:40:46 -0800312 Scalar K(int i, int j) const { return K()(i, j); }
313 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800314 return coefficients().Kff;
315 }
Austin Schuh20388b62017-11-23 22:40:46 -0800316 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800317
Austin Schuhe91f14c2017-02-25 19:43:57 -0800318 void Reset() {}
319
Austin Schuh32501832017-02-25 18:32:56 -0800320 // Sets the current controller to be index, clamped to be within range.
321 void set_index(int index) {
322 if (index < 0) {
323 index_ = 0;
324 } else if (index >= static_cast<int>(coefficients_.size())) {
325 index_ = static_cast<int>(coefficients_.size()) - 1;
326 } else {
327 index_ = index;
328 }
329 }
330
331 int index() const { return index_; }
332
333 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700334 number_of_outputs, Scalar> &
335 coefficients(int index) const {
Austin Schuh32501832017-02-25 18:32:56 -0800336 return *coefficients_[index];
337 }
338
339 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700340 number_of_outputs, Scalar> &
341 coefficients() const {
Austin Schuh32501832017-02-25 18:32:56 -0800342 return *coefficients_[index_];
343 }
344
345 private:
346 int index_ = 0;
347 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800348 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800349 coefficients_;
350};
351
Austin Schuh32501832017-02-25 18:32:56 -0800352// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800353template <int number_of_states, int number_of_inputs, int number_of_outputs,
354 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800355struct StateFeedbackObserverCoefficients final {
356 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
357
Sabina Davis3922dfa2018-02-10 23:10:05 -0800358 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800359 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
360 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800361
Austin Schuh64433f12022-02-21 19:40:38 -0800362 // If true, this adds a single cycle output delay model to the plant. This is
363 // useful for modeling a control loop cycle where you sample, compute, and
364 // then queue the outputs to be ready to be executed when the next cycle
365 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -0700366 const size_t delayed_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800367
Austin Schuh32501832017-02-25 18:32:56 -0800368 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800369 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
370 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800371 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
Austin Schuh64433f12022-02-21 19:40:38 -0800372 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R,
Austin Schuhb39f4522022-03-27 13:29:42 -0700373 size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -0800374 : KalmanGain(KalmanGain), Q(Q), R(R), delayed_u(delayed_u) {}
Austin Schuh32501832017-02-25 18:32:56 -0800375};
376
Austin Schuh20388b62017-11-23 22:40:46 -0800377template <int number_of_states, int number_of_inputs, int number_of_outputs,
378 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800379class StateFeedbackObserver {
380 public:
381 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
382
383 explicit StateFeedbackObserver(
384 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800385 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700386 &&observers)
Austin Schuhb39f4522022-03-27 13:29:42 -0700387 : coefficients_(::std::move(observers)) {
388 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
Philipp Schrader790cb542023-07-05 21:06:52 -0700389 number_of_inputs,
390 std::max(static_cast<size_t>(1u), coefficients().delayed_u));
Austin Schuhb39f4522022-03-27 13:29:42 -0700391 }
Austin Schuh32501832017-02-25 18:32:56 -0800392
393 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuh64433f12022-02-21 19:40:38 -0800394 : X_hat_(other.X_hat_), last_U_(other.last_U_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800395 ::std::swap(coefficients_, other.coefficients_);
396 }
397
Tyler Chatow6738c362019-02-16 14:12:30 -0800398 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
399 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800400 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800401 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800402 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800403
Austin Schuh20388b62017-11-23 22:40:46 -0800404 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800405 return X_hat_;
406 }
Austin Schuh20388b62017-11-23 22:40:46 -0800407 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800408
Austin Schuhb39f4522022-03-27 13:29:42 -0700409 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
410 size_t index = 0) const {
411 return last_U_.template block<number_of_inputs, 1>(0, index);
Austin Schuh482a9142022-02-23 16:54:39 -0800412 }
413
Austin Schuh6501d232017-11-23 20:35:27 -0800414 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800415 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800416 X_hat_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800417 last_U_.setZero();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800418 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800419
Austin Schuh6501d232017-11-23 20:35:27 -0800420 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800421 number_of_outputs, Scalar> *plant,
422 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800423 ::std::chrono::nanoseconds /*dt*/) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700424 if (plant->coefficients().delayed_u > 0) {
425 mutable_X_hat() =
426 plant->Update(X_hat(), last_U(coefficients().delayed_u - 1));
427 for (int i = coefficients().delayed_u; i > 1; --i) {
428 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
429 last_U_.template block<number_of_inputs, 1>(0, i - 2);
430 }
431 last_U_.template block<number_of_inputs, 1>(0, 0) = new_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800432 } else {
433 mutable_X_hat() = plant->Update(X_hat(), new_u);
434 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800435 }
436
Austin Schuh6501d232017-11-23 20:35:27 -0800437 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800438 number_of_outputs, Scalar> &plant,
439 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
440 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Tyler Chatow6738c362019-02-16 14:12:30 -0800441 mutable_X_hat() += KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800442 }
443
Austin Schuh32501832017-02-25 18:32:56 -0800444 // Sets the current controller to be index, clamped to be within range.
445 void set_index(int index) {
446 if (index < 0) {
447 index_ = 0;
448 } else if (index >= static_cast<int>(coefficients_.size())) {
449 index_ = static_cast<int>(coefficients_.size()) - 1;
450 } else {
451 index_ = index;
452 }
453 }
454
455 int index() const { return index_; }
456
457 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700458 number_of_outputs, Scalar> &
459 coefficients(int index) const {
Austin Schuh32501832017-02-25 18:32:56 -0800460 return *coefficients_[index];
461 }
462
463 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700464 number_of_outputs, Scalar> &
465 coefficients() const {
Austin Schuh32501832017-02-25 18:32:56 -0800466 return *coefficients_[index_];
467 }
468
469 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800470 // Internal state estimate.
James Kuszmauleeb98e92024-01-14 22:15:32 -0800471 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_ =
472 Eigen::Matrix<Scalar, number_of_states, 1>::Zero();
Austin Schuhb39f4522022-03-27 13:29:42 -0700473 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800474
Austin Schuh32501832017-02-25 18:32:56 -0800475 int index_ = 0;
476 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800477 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800478 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700479};
480
Austin Schuhe91f14c2017-02-25 19:43:57 -0800481template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800482 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800483 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800484 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800485 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800486 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800487class StateFeedbackLoop {
488 public:
489 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
490
Austin Schuh32501832017-02-25 18:32:56 -0800491 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800492 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800493 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800494 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800495 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800496 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800497 controller_(::std::move(controller)),
498 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700499 Reset();
500 }
501
Austin Schuhc5fceb82017-02-25 16:24:12 -0800502 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800503 : plant_(::std::move(other.plant_)),
504 controller_(::std::move(other.controller_)),
505 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800506 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700507 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800508 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700509 U_.swap(other.U_);
510 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700511 }
512
Austin Schuh1a387962015-01-31 16:36:20 -0800513 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700514
Austin Schuh20388b62017-11-23 22:40:46 -0800515 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800516 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700517 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800518 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800519 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800520 Scalar R(int i, int j = 0) const { return R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800521 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800522 return next_R_;
523 }
Austin Schuh95771d92021-01-23 14:42:25 -0800524 Scalar next_R(int i, int j = 0) const { return next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800525 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800526 Scalar U(int i, int j = 0) const { return U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800527 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700528 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700529 }
Austin Schuh95771d92021-01-23 14:42:25 -0800530 Scalar U_uncapped(int i, int j = 0) const { return U_uncapped()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800531 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800532 return ff_U_;
533 }
Austin Schuh95771d92021-01-23 14:42:25 -0800534 Scalar ff_U(int i, int j = 0) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700535
Austin Schuh20388b62017-11-23 22:40:46 -0800536 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800537 return observer_.mutable_X_hat();
538 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800539 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800540 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800541 Scalar &mutable_R(int i, int j = 0) { return mutable_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800542 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800543 return next_R_;
544 }
Austin Schuh95771d92021-01-23 14:42:25 -0800545 Scalar &mutable_next_R(int i, int j = 0) { return mutable_next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800546 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800547 Scalar &mutable_U(int i, int j = 0) { return mutable_U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800548 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700549 return U_uncapped_;
550 }
Austin Schuh95771d92021-01-23 14:42:25 -0800551 Scalar &mutable_U_uncapped(int i, int j = 0) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700552 return mutable_U_uncapped()(i, j);
553 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800554
Austin Schuhe91f14c2017-02-25 19:43:57 -0800555 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800556 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800557
Austin Schuh32501832017-02-25 18:32:56 -0800558 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700559 number_of_outputs, Scalar> &
560 controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800561 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700562 }
563
Austin Schuhe91f14c2017-02-25 19:43:57 -0800564 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700565
Austin Schuh9644e1c2013-03-12 00:40:36 -0700566 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700567 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800568 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700569 U_.setZero();
570 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800571 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800572
573 plant_.Reset();
574 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800575 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800576 }
577
578 // If U is outside the hardware range, limit it before the plant tries to use
579 // it.
580 virtual void CapU() {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700581 // TODO(Ravago): this runs before the state update step, so it's limiting
582 // the future control based on the old state. This gets even worse when we
583 // have delayed_u.
584 Eigen::Matrix<Scalar, number_of_inputs, 1> U_max_computed =
585 plant().U_limit_coefficient() * plant().X() +
586 plant().U_limit_constant();
587 Eigen::Matrix<Scalar, number_of_inputs, 1> U_min_computed =
588 plant().U_limit_coefficient() * plant().X() -
589 plant().U_limit_constant();
590
591 U_max_computed = U_max_computed.cwiseMin(plant().U_max());
592 U_min_computed = U_min_computed.cwiseMax(plant().U_min());
593
Brian Silverman5808bcb2014-09-14 21:40:43 -0400594 for (int i = 0; i < kNumInputs; ++i) {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700595 if (U(i, 0) > U_max_computed(i, 0)) {
596 U_(i, 0) = U_max_computed(i, 0);
597 } else if (U(i, 0) < U_min_computed(i, 0)) {
598 U_(i, 0) = U_min_computed(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800599 }
600 }
601 }
602
Austin Schuhf9286cd2014-02-11 00:51:09 -0800603 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800604 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800605 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800606 }
607
Austin Schuh20388b62017-11-23 22:40:46 -0800608 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800609 return R() - X_hat();
610 }
611
Austin Schuhb6a6d822016-02-08 00:20:40 -0800612 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800613 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800614 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800615 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800616 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800617 }
618
619 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800620 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800621 // TODO(austin): Should this live in StateSpaceController?
622 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800623 }
624
Austin Schuh43b9ae92020-02-29 23:08:38 -0800625 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800626 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700627 U_.setZero();
628 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800629 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800630 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800631 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800632 CapU();
633 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800634 UpdateFFReference();
635 }
636
637 // stop_motors is whether or not to output all 0s.
638 void Update(bool stop_motors,
639 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
640 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800641
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800642 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800643 }
644
645 // Updates R() after any CapU operations happen on U().
646 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800647 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800648 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800649 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800650 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000651 }
652
Austin Schuh20388b62017-11-23 22:40:46 -0800653 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800654 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800655 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800656 }
657
Austin Schuh32501832017-02-25 18:32:56 -0800658 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800659 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800660 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800661 controller_.set_index(index);
662 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700663 }
664
Austin Schuh32501832017-02-25 18:32:56 -0800665 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700666
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800667 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800668 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800669
Austin Schuh20388b62017-11-23 22:40:46 -0800670 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
671 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800672 controller_;
673
Austin Schuhe91f14c2017-02-25 19:43:57 -0800674 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700675
Brian Silverman273d8a32014-05-10 22:19:09 -0700676 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800677 static constexpr int kNumStates = number_of_states;
678 static constexpr int kNumOutputs = number_of_outputs;
679 static constexpr int kNumInputs = number_of_inputs;
680
681 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800682 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700683
Brian Silverman273d8a32014-05-10 22:19:09 -0700684 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800685 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800686 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800687 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800688 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800689 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800690 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800691 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800692 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700693
Brian Silverman0a151c92014-05-02 15:28:44 -0700694 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800695};
696
Brian Silverman273d8a32014-05-10 22:19:09 -0700697#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_