blob: 295becafa58d9c8fd6e0f53c18fcdf726bb00012 [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),
Ravago Jonesc471ebe2023-07-05 20:37:00 -070045 U_limit_coefficient(other.U_limit_coefficient),
46 U_limit_constant(other.U_limit_constant),
Austin Schuh64433f12022-02-21 19:40:38 -080047 dt(other.dt),
48 delayed_u(other.delayed_u) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080049
Austin Schuhe3490622013-03-13 01:24:30 -070050 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080051 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080052 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
53 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
54 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
55 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080056 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
Ravago Jonesc471ebe2023-07-05 20:37:00 -070057 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
58 &U_limit_coefficient,
59 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant,
Austin Schuhb39f4522022-03-27 13:29:42 -070060 const std::chrono::nanoseconds dt, size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -080061 : A(A),
62 B(B),
63 C(C),
64 D(D),
65 U_min(U_min),
66 U_max(U_max),
Ravago Jonesc471ebe2023-07-05 20:37:00 -070067 U_limit_coefficient(U_limit_coefficient),
68 U_limit_constant(U_limit_constant),
Austin Schuh64433f12022-02-21 19:40:38 -080069 dt(dt),
70 delayed_u(delayed_u) {}
Austin Schuhe3490622013-03-13 01:24:30 -070071
Austin Schuh20388b62017-11-23 22:40:46 -080072 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080073 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
74 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
75 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
76 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
77 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
Ravago Jonesc471ebe2023-07-05 20:37:00 -070078 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
79 U_limit_coefficient;
80 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_limit_constant;
James Kuszmaul03be1242020-02-21 14:52:04 -080081 const std::chrono::nanoseconds dt;
Austin Schuh64433f12022-02-21 19:40:38 -080082
83 // If true, this adds a single cycle output delay model to the plant. This is
84 // useful for modeling a control loop cycle where you sample, compute, and
85 // then queue the outputs to be ready to be executed when the next cycle
86 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -070087 const size_t delayed_u;
Austin Schuhe3490622013-03-13 01:24:30 -070088};
89
Austin Schuh20388b62017-11-23 22:40:46 -080090template <int number_of_states, int number_of_inputs, int number_of_outputs,
91 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -070092class StateFeedbackPlant {
93 public:
94 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070095
96 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080097 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -080098 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -070099 &&coefficients)
100 : coefficients_(::std::move(coefficients)), index_(0) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700101 if (coefficients_.size() > 1u) {
102 for (size_t i = 1; i < coefficients_.size(); ++i) {
103 if (coefficients_[i]->delayed_u != coefficients_[0]->delayed_u) {
104 abort();
105 }
106 }
107 }
108 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
109 number_of_inputs,
110 std::max(static_cast<size_t>(1u), coefficients_[0]->delayed_u));
Brian Silverman0a151c92014-05-02 15:28:44 -0700111 Reset();
112 }
113
Tyler Chatow6738c362019-02-16 14:12:30 -0800114 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -0700115 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700116 X_.swap(other.X_);
117 Y_.swap(other.Y_);
Austin Schuh64433f12022-02-21 19:40:38 -0800118 last_U_.swap(other.last_U_);
Brian Silverman0a151c92014-05-02 15:28:44 -0700119 }
120
Austin Schuh1a387962015-01-31 16:36:20 -0800121 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700122
Austin Schuh20388b62017-11-23 22:40:46 -0800123 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800124 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -0700125 }
Austin Schuh20388b62017-11-23 22:40:46 -0800126 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800127 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800128 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700129 }
Austin Schuh20388b62017-11-23 22:40:46 -0800130 Scalar B(int i, int j) const { return B()(i, j); }
131 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800132 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700133 }
Austin Schuh20388b62017-11-23 22:40:46 -0800134 Scalar C(int i, int j) const { return C()(i, j); }
135 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800136 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700137 }
Austin Schuh20388b62017-11-23 22:40:46 -0800138 Scalar D(int i, int j) const { return D()(i, j); }
139 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800140 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700141 }
Austin Schuh20388b62017-11-23 22:40:46 -0800142 Scalar U_min(int i, int j) const { return U_min()(i, j); }
143 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800144 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700145 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800146 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700147 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
148 &U_limit_coefficient() const {
149 return coefficients().U_limit_coefficient;
150 }
151 Scalar U_limit_coefficient(int i, int j) const {
152 return U_limit_coefficient()(i, j);
153 }
154 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant() const {
155 return coefficients().U_limit_constant;
156 }
157 Scalar U_limit_constant(int i, int j = 0) const {
158 return U_limit_constant()(i, j);
159 }
Brian Silverman273d8a32014-05-10 22:19:09 -0700160
Austin Schuh43b9ae92020-02-29 23:08:38 -0800161 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
162
Austin Schuh20388b62017-11-23 22:40:46 -0800163 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800164 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800165 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800166 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700167
Austin Schuh20388b62017-11-23 22:40:46 -0800168 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800169 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800170 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800171 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700172
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800173 size_t coefficients_size() const { return coefficients_.size(); }
174
Austin Schuhb6a6d822016-02-08 00:20:40 -0800175 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800176 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800177 &coefficients(int index) const {
178 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700179 }
180
Austin Schuhc5fceb82017-02-25 16:24:12 -0800181 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800182 number_of_outputs, Scalar>
Austin Schuhc5fceb82017-02-25 16:24:12 -0800183 &coefficients() const {
184 return *coefficients_[index_];
185 }
186
187 int index() const { return index_; }
188 void set_index(int index) {
189 assert(index >= 0);
190 assert(index < static_cast<int>(coefficients_.size()));
191 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700192 }
193
194 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700195 X_.setZero();
196 Y_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800197 last_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800198 }
199
Austin Schuh849f0032013-03-03 23:59:53 -0800200 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800201 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400202 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800203 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
204 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800205#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700206 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800207#else
208 abort();
209#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800210 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800211 }
212 }
Austin Schuh849f0032013-03-03 23:59:53 -0800213
Austin Schuhb39f4522022-03-27 13:29:42 -0700214 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
215 size_t index = 0) const {
216 return last_U_.template block<number_of_inputs, 1>(0, index);
217 }
218
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800219 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800220 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800221 // Powers outside of the range are more likely controller bugs than things
222 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800223 CheckU(U);
Austin Schuhb39f4522022-03-27 13:29:42 -0700224 if (coefficients().delayed_u > 0) {
225#if defined(__linux__)
226 DCHECK_EQ(static_cast<ssize_t>(coefficients().delayed_u), last_U_.cols());
227#endif
228 X_ = Update(X(), last_U(coefficients().delayed_u - 1));
229 UpdateY(last_U(coefficients().delayed_u - 1));
230 for (int i = coefficients().delayed_u; i > 1; --i) {
231 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
232 last_U_.template block<number_of_inputs, 1>(0, i - 2);
233 }
234 last_U_.template block<number_of_inputs, 1>(0, 0) = U;
Austin Schuh64433f12022-02-21 19:40:38 -0800235 } else {
236 X_ = Update(X(), U);
237 UpdateY(U);
238 }
Austin Schuh01c7b252017-03-05 00:59:31 -0800239 }
240
241 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800242 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800243 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800244 }
245
Austin Schuh20388b62017-11-23 22:40:46 -0800246 Eigen::Matrix<Scalar, number_of_states, 1> Update(
247 const Eigen::Matrix<Scalar, number_of_states, 1> X,
248 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800249 return A() * X + B() * U;
250 }
251
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800252 protected:
253 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800254 static const int kNumStates = number_of_states;
255 static const int kNumOutputs = number_of_outputs;
256 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700257
258 private:
Austin Schuh20388b62017-11-23 22:40:46 -0800259 Eigen::Matrix<Scalar, number_of_states, 1> X_;
260 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_;
Austin Schuhb39f4522022-03-27 13:29:42 -0700261 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700262
Austin Schuhb6a6d822016-02-08 00:20:40 -0800263 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800264 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800265 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700266
Austin Schuhc5fceb82017-02-25 16:24:12 -0800267 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700268
269 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800270};
271
Austin Schuh32501832017-02-25 18:32:56 -0800272// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800273template <int number_of_states, int number_of_inputs, int number_of_outputs,
274 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800275struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700276 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700277
Austin Schuh20388b62017-11-23 22:40:46 -0800278 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
279 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700280
Austin Schuh32501832017-02-25 18:32:56 -0800281 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800282 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
283 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800284 : K(K), Kff(Kff) {}
285};
286
Austin Schuh20388b62017-11-23 22:40:46 -0800287template <int number_of_states, int number_of_inputs, int number_of_outputs,
288 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800289class StateFeedbackController {
290 public:
291 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
292
293 explicit StateFeedbackController(
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 Schuhb02bf5b2021-07-31 21:28:21 -0700296 &&controllers)
297 : coefficients_(::std::move(controllers)) {}
Austin Schuh32501832017-02-25 18:32:56 -0800298
299 StateFeedbackController(StateFeedbackController &&other)
300 : index_(other.index_) {
301 ::std::swap(coefficients_, other.coefficients_);
302 }
303
Austin Schuh20388b62017-11-23 22:40:46 -0800304 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800305 return coefficients().K;
306 }
Austin Schuh20388b62017-11-23 22:40:46 -0800307 Scalar K(int i, int j) const { return K()(i, j); }
308 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800309 return coefficients().Kff;
310 }
Austin Schuh20388b62017-11-23 22:40:46 -0800311 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800312
Austin Schuhe91f14c2017-02-25 19:43:57 -0800313 void Reset() {}
314
Austin Schuh32501832017-02-25 18:32:56 -0800315 // Sets the current controller to be index, clamped to be within range.
316 void set_index(int index) {
317 if (index < 0) {
318 index_ = 0;
319 } else if (index >= static_cast<int>(coefficients_.size())) {
320 index_ = static_cast<int>(coefficients_.size()) - 1;
321 } else {
322 index_ = index;
323 }
324 }
325
326 int index() const { return index_; }
327
328 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800329 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800330 &coefficients(int index) const {
331 return *coefficients_[index];
332 }
333
334 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800335 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800336 &coefficients() const {
337 return *coefficients_[index_];
338 }
339
340 private:
341 int index_ = 0;
342 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800343 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800344 coefficients_;
345};
346
Austin Schuh32501832017-02-25 18:32:56 -0800347// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800348template <int number_of_states, int number_of_inputs, int number_of_outputs,
349 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800350struct StateFeedbackObserverCoefficients final {
351 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
352
Sabina Davis3922dfa2018-02-10 23:10:05 -0800353 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800354 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
355 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800356
Austin Schuh64433f12022-02-21 19:40:38 -0800357 // If true, this adds a single cycle output delay model to the plant. This is
358 // useful for modeling a control loop cycle where you sample, compute, and
359 // then queue the outputs to be ready to be executed when the next cycle
360 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -0700361 const size_t delayed_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800362
Austin Schuh32501832017-02-25 18:32:56 -0800363 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800364 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
365 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800366 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
Austin Schuh64433f12022-02-21 19:40:38 -0800367 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R,
Austin Schuhb39f4522022-03-27 13:29:42 -0700368 size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -0800369 : KalmanGain(KalmanGain), Q(Q), R(R), delayed_u(delayed_u) {}
Austin Schuh32501832017-02-25 18:32:56 -0800370};
371
Austin Schuh20388b62017-11-23 22:40:46 -0800372template <int number_of_states, int number_of_inputs, int number_of_outputs,
373 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800374class StateFeedbackObserver {
375 public:
376 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
377
378 explicit StateFeedbackObserver(
379 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800380 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700381 &&observers)
Austin Schuhb39f4522022-03-27 13:29:42 -0700382 : coefficients_(::std::move(observers)) {
383 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
Philipp Schrader790cb542023-07-05 21:06:52 -0700384 number_of_inputs,
385 std::max(static_cast<size_t>(1u), coefficients().delayed_u));
Austin Schuhb39f4522022-03-27 13:29:42 -0700386 }
Austin Schuh32501832017-02-25 18:32:56 -0800387
388 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuh64433f12022-02-21 19:40:38 -0800389 : X_hat_(other.X_hat_), last_U_(other.last_U_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800390 ::std::swap(coefficients_, other.coefficients_);
391 }
392
Tyler Chatow6738c362019-02-16 14:12:30 -0800393 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
394 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800395 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800396 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800397 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800398
Austin Schuh20388b62017-11-23 22:40:46 -0800399 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800400 return X_hat_;
401 }
Austin Schuh20388b62017-11-23 22:40:46 -0800402 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800403
Austin Schuhb39f4522022-03-27 13:29:42 -0700404 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
405 size_t index = 0) const {
406 return last_U_.template block<number_of_inputs, 1>(0, index);
Austin Schuh482a9142022-02-23 16:54:39 -0800407 }
408
Austin Schuh6501d232017-11-23 20:35:27 -0800409 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800410 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800411 X_hat_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800412 last_U_.setZero();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800413 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800414
Austin Schuh6501d232017-11-23 20:35:27 -0800415 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800416 number_of_outputs, Scalar> *plant,
417 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800418 ::std::chrono::nanoseconds /*dt*/) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700419 if (plant->coefficients().delayed_u > 0) {
420 mutable_X_hat() =
421 plant->Update(X_hat(), last_U(coefficients().delayed_u - 1));
422 for (int i = coefficients().delayed_u; i > 1; --i) {
423 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
424 last_U_.template block<number_of_inputs, 1>(0, i - 2);
425 }
426 last_U_.template block<number_of_inputs, 1>(0, 0) = new_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800427 } else {
428 mutable_X_hat() = plant->Update(X_hat(), new_u);
429 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800430 }
431
Austin Schuh6501d232017-11-23 20:35:27 -0800432 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800433 number_of_outputs, Scalar> &plant,
434 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
435 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Tyler Chatow6738c362019-02-16 14:12:30 -0800436 mutable_X_hat() += KalmanGain() * (Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800437 }
438
Austin Schuh32501832017-02-25 18:32:56 -0800439 // Sets the current controller to be index, clamped to be within range.
440 void set_index(int index) {
441 if (index < 0) {
442 index_ = 0;
443 } else if (index >= static_cast<int>(coefficients_.size())) {
444 index_ = static_cast<int>(coefficients_.size()) - 1;
445 } else {
446 index_ = index;
447 }
448 }
449
450 int index() const { return index_; }
451
452 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800453 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800454 &coefficients(int index) const {
455 return *coefficients_[index];
456 }
457
458 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800459 number_of_outputs, Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800460 &coefficients() const {
461 return *coefficients_[index_];
462 }
463
464 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800465 // Internal state estimate.
Austin Schuh20388b62017-11-23 22:40:46 -0800466 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_;
Austin Schuhb39f4522022-03-27 13:29:42 -0700467 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800468
Austin Schuh32501832017-02-25 18:32:56 -0800469 int index_ = 0;
470 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800471 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800472 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700473};
474
Austin Schuhe91f14c2017-02-25 19:43:57 -0800475template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800476 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800477 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800478 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800479 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800480 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800481class StateFeedbackLoop {
482 public:
483 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
484
Austin Schuh32501832017-02-25 18:32:56 -0800485 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800486 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800487 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800488 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800489 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800490 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800491 controller_(::std::move(controller)),
492 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700493 Reset();
494 }
495
Austin Schuhc5fceb82017-02-25 16:24:12 -0800496 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800497 : plant_(::std::move(other.plant_)),
498 controller_(::std::move(other.controller_)),
499 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800500 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700501 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800502 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700503 U_.swap(other.U_);
504 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700505 }
506
Austin Schuh1a387962015-01-31 16:36:20 -0800507 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700508
Austin Schuh20388b62017-11-23 22:40:46 -0800509 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800510 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700511 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800512 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800513 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800514 Scalar R(int i, int j = 0) const { return R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800515 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800516 return next_R_;
517 }
Austin Schuh95771d92021-01-23 14:42:25 -0800518 Scalar next_R(int i, int j = 0) const { return next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800519 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800520 Scalar U(int i, int j = 0) const { return U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800521 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700522 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700523 }
Austin Schuh95771d92021-01-23 14:42:25 -0800524 Scalar U_uncapped(int i, int j = 0) const { return U_uncapped()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800525 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800526 return ff_U_;
527 }
Austin Schuh95771d92021-01-23 14:42:25 -0800528 Scalar ff_U(int i, int j = 0) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700529
Austin Schuh20388b62017-11-23 22:40:46 -0800530 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800531 return observer_.mutable_X_hat();
532 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800533 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800534 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800535 Scalar &mutable_R(int i, int j = 0) { return mutable_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800536 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800537 return next_R_;
538 }
Austin Schuh95771d92021-01-23 14:42:25 -0800539 Scalar &mutable_next_R(int i, int j = 0) { return mutable_next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800540 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800541 Scalar &mutable_U(int i, int j = 0) { return mutable_U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800542 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700543 return U_uncapped_;
544 }
Austin Schuh95771d92021-01-23 14:42:25 -0800545 Scalar &mutable_U_uncapped(int i, int j = 0) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700546 return mutable_U_uncapped()(i, j);
547 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800548
Austin Schuhe91f14c2017-02-25 19:43:57 -0800549 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800550 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800551
Austin Schuh32501832017-02-25 18:32:56 -0800552 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800553 number_of_outputs, Scalar>
Austin Schuh66c19882017-02-25 13:36:28 -0800554 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800555 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700556 }
557
Austin Schuhe91f14c2017-02-25 19:43:57 -0800558 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700559
Austin Schuh9644e1c2013-03-12 00:40:36 -0700560 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700561 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800562 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700563 U_.setZero();
564 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800565 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800566
567 plant_.Reset();
568 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800569 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800570 }
571
572 // If U is outside the hardware range, limit it before the plant tries to use
573 // it.
574 virtual void CapU() {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700575 // TODO(Ravago): this runs before the state update step, so it's limiting
576 // the future control based on the old state. This gets even worse when we
577 // have delayed_u.
578 Eigen::Matrix<Scalar, number_of_inputs, 1> U_max_computed =
579 plant().U_limit_coefficient() * plant().X() +
580 plant().U_limit_constant();
581 Eigen::Matrix<Scalar, number_of_inputs, 1> U_min_computed =
582 plant().U_limit_coefficient() * plant().X() -
583 plant().U_limit_constant();
584
585 U_max_computed = U_max_computed.cwiseMin(plant().U_max());
586 U_min_computed = U_min_computed.cwiseMax(plant().U_min());
587
Brian Silverman5808bcb2014-09-14 21:40:43 -0400588 for (int i = 0; i < kNumInputs; ++i) {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700589 if (U(i, 0) > U_max_computed(i, 0)) {
590 U_(i, 0) = U_max_computed(i, 0);
591 } else if (U(i, 0) < U_min_computed(i, 0)) {
592 U_(i, 0) = U_min_computed(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800593 }
594 }
595 }
596
Austin Schuhf9286cd2014-02-11 00:51:09 -0800597 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800598 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800599 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800600 }
601
Austin Schuh20388b62017-11-23 22:40:46 -0800602 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800603 return R() - X_hat();
604 }
605
Austin Schuhb6a6d822016-02-08 00:20:40 -0800606 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800607 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800608 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800609 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800610 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800611 }
612
613 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800614 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800615 // TODO(austin): Should this live in StateSpaceController?
616 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800617 }
618
Austin Schuh43b9ae92020-02-29 23:08:38 -0800619 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800620 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700621 U_.setZero();
622 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800623 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800624 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800625 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800626 CapU();
627 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800628 UpdateFFReference();
629 }
630
631 // stop_motors is whether or not to output all 0s.
632 void Update(bool stop_motors,
633 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
634 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800635
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800636 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800637 }
638
639 // Updates R() after any CapU operations happen on U().
640 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800641 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800642 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800643 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800644 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000645 }
646
Austin Schuh20388b62017-11-23 22:40:46 -0800647 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800648 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800649 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800650 }
651
Austin Schuh32501832017-02-25 18:32:56 -0800652 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800653 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800654 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800655 controller_.set_index(index);
656 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700657 }
658
Austin Schuh32501832017-02-25 18:32:56 -0800659 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700660
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800661 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800662 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800663
Austin Schuh20388b62017-11-23 22:40:46 -0800664 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
665 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800666 controller_;
667
Austin Schuhe91f14c2017-02-25 19:43:57 -0800668 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700669
Brian Silverman273d8a32014-05-10 22:19:09 -0700670 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800671 static constexpr int kNumStates = number_of_states;
672 static constexpr int kNumOutputs = number_of_outputs;
673 static constexpr int kNumInputs = number_of_inputs;
674
675 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800676 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700677
Brian Silverman273d8a32014-05-10 22:19:09 -0700678 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800679 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800680 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800681 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800682 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800683 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800684 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800685 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800686 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700687
Brian Silverman0a151c92014-05-02 15:28:44 -0700688 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800689};
690
Brian Silverman273d8a32014-05-10 22:19:09 -0700691#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_