blob: b6604d48ed9d2f4ff8027b19a324a396f3bcabf9 [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"
James Kuszmaul9ea3ff92024-06-14 15:02:15 -070021#include "frc971/zeroing/wrap.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070022
Austin Schuhe91f14c2017-02-25 19:43:57 -080023template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -080024 typename PlantType, typename ObserverType, typename Scalar>
Austin Schuhe91f14c2017-02-25 19:43:57 -080025class StateFeedbackLoop;
26
Brian Silverman5808bcb2014-09-14 21:40:43 -040027// For everything in this file, "inputs" and "outputs" are defined from the
28// perspective of the plant. This means U is an input and Y is an output
29// (because you give the plant U (powers) and it gives you back a Y (sensor
30// values). This is the opposite of what they mean from the perspective of the
31// controller (U is an output because that's what goes to the motors and Y is an
32// input because that's what comes back from the sensors).
33
Austin Schuh20388b62017-11-23 22:40:46 -080034template <int number_of_states, int number_of_inputs, int number_of_outputs,
35 typename Scalar = double>
Austin Schuh64f17a52017-02-25 14:41:58 -080036struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080037 public:
38 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
39
Austin Schuhe3490622013-03-13 01:24:30 -070040 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080041 : A(other.A),
Austin Schuh64f17a52017-02-25 14:41:58 -080042 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080043 C(other.C),
44 D(other.D),
45 U_min(other.U_min),
James Kuszmaul03be1242020-02-21 14:52:04 -080046 U_max(other.U_max),
Ravago Jonesc471ebe2023-07-05 20:37:00 -070047 U_limit_coefficient(other.U_limit_coefficient),
48 U_limit_constant(other.U_limit_constant),
Austin Schuh64433f12022-02-21 19:40:38 -080049 dt(other.dt),
James Kuszmaul9ea3ff92024-06-14 15:02:15 -070050 delayed_u(other.delayed_u),
51 wrap_point(other.wrap_point) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080052
Austin Schuhe3490622013-03-13 01:24:30 -070053 StateFeedbackPlantCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -080054 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A,
Austin Schuh20388b62017-11-23 22:40:46 -080055 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B,
56 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C,
57 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
58 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
James Kuszmaul03be1242020-02-21 14:52:04 -080059 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
Ravago Jonesc471ebe2023-07-05 20:37:00 -070060 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
61 &U_limit_coefficient,
62 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant,
James Kuszmaul9ea3ff92024-06-14 15:02:15 -070063 const std::chrono::nanoseconds dt, size_t delayed_u,
64 const Eigen::Matrix<Scalar, number_of_outputs, 1> &wrap_point)
Austin Schuh64433f12022-02-21 19:40:38 -080065 : A(A),
66 B(B),
67 C(C),
68 D(D),
69 U_min(U_min),
70 U_max(U_max),
Ravago Jonesc471ebe2023-07-05 20:37:00 -070071 U_limit_coefficient(U_limit_coefficient),
72 U_limit_constant(U_limit_constant),
Austin Schuh64433f12022-02-21 19:40:38 -080073 dt(dt),
James Kuszmaul9ea3ff92024-06-14 15:02:15 -070074 delayed_u(delayed_u),
75 wrap_point(wrap_point) {}
Austin Schuhe3490622013-03-13 01:24:30 -070076
Austin Schuh20388b62017-11-23 22:40:46 -080077 const Eigen::Matrix<Scalar, number_of_states, number_of_states> A;
Austin Schuh20388b62017-11-23 22:40:46 -080078 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> B;
79 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> C;
80 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
81 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
82 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
Ravago Jonesc471ebe2023-07-05 20:37:00 -070083 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
84 U_limit_coefficient;
85 const Eigen::Matrix<Scalar, number_of_inputs, 1> U_limit_constant;
James Kuszmaul9ea3ff92024-06-14 15:02:15 -070086
James Kuszmaul03be1242020-02-21 14:52:04 -080087 const std::chrono::nanoseconds dt;
Austin Schuh64433f12022-02-21 19:40:38 -080088
89 // If true, this adds a single cycle output delay model to the plant. This is
90 // useful for modeling a control loop cycle where you sample, compute, and
91 // then queue the outputs to be ready to be executed when the next cycle
92 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -070093 const size_t delayed_u;
James Kuszmaul9ea3ff92024-06-14 15:02:15 -070094
95 // We will assume that each element of the Y vector wraps at the
96 // specified point. For any given element that is zero, we will
97 // assume no wrapping.
98 const Eigen::Matrix<Scalar, number_of_outputs, 1> wrap_point;
Austin Schuhe3490622013-03-13 01:24:30 -070099};
100
Austin Schuh20388b62017-11-23 22:40:46 -0800101template <int number_of_states, int number_of_inputs, int number_of_outputs,
102 typename Scalar = double>
Austin Schuhe3490622013-03-13 01:24:30 -0700103class StateFeedbackPlant {
104 public:
105 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -0700106
107 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -0800108 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800109 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700110 &&coefficients)
111 : coefficients_(::std::move(coefficients)), index_(0) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700112 if (coefficients_.size() > 1u) {
113 for (size_t i = 1; i < coefficients_.size(); ++i) {
114 if (coefficients_[i]->delayed_u != coefficients_[0]->delayed_u) {
115 abort();
116 }
117 }
118 }
119 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
120 number_of_inputs,
121 std::max(static_cast<size_t>(1u), coefficients_[0]->delayed_u));
Brian Silverman0a151c92014-05-02 15:28:44 -0700122 Reset();
123 }
124
Tyler Chatow6738c362019-02-16 14:12:30 -0800125 StateFeedbackPlant(StateFeedbackPlant &&other) : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -0700126 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700127 X_.swap(other.X_);
128 Y_.swap(other.Y_);
Austin Schuh64433f12022-02-21 19:40:38 -0800129 last_U_.swap(other.last_U_);
Brian Silverman0a151c92014-05-02 15:28:44 -0700130 }
131
Austin Schuh1a387962015-01-31 16:36:20 -0800132 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700133
Austin Schuh20388b62017-11-23 22:40:46 -0800134 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800135 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -0700136 }
Austin Schuh20388b62017-11-23 22:40:46 -0800137 Scalar A(int i, int j) const { return A()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800138 const Eigen::Matrix<Scalar, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800139 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -0700140 }
Austin Schuh20388b62017-11-23 22:40:46 -0800141 Scalar B(int i, int j) const { return B()(i, j); }
142 const Eigen::Matrix<Scalar, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800143 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -0700144 }
Austin Schuh20388b62017-11-23 22:40:46 -0800145 Scalar C(int i, int j) const { return C()(i, j); }
146 const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800147 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700148 }
Austin Schuh20388b62017-11-23 22:40:46 -0800149 Scalar D(int i, int j) const { return D()(i, j); }
150 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800151 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700152 }
Austin Schuh20388b62017-11-23 22:40:46 -0800153 Scalar U_min(int i, int j) const { return U_min()(i, j); }
154 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800155 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700156 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800157 Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
Austin Schuh50e3dca2023-07-23 14:34:27 -0700158 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &
159 U_limit_coefficient() const {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700160 return coefficients().U_limit_coefficient;
161 }
162 Scalar U_limit_coefficient(int i, int j) const {
163 return U_limit_coefficient()(i, j);
164 }
165 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant() const {
166 return coefficients().U_limit_constant;
167 }
168 Scalar U_limit_constant(int i, int j = 0) const {
169 return U_limit_constant()(i, j);
170 }
Brian Silverman273d8a32014-05-10 22:19:09 -0700171
Austin Schuh43b9ae92020-02-29 23:08:38 -0800172 const std::chrono::nanoseconds dt() const { return coefficients().dt; }
173
Austin Schuh20388b62017-11-23 22:40:46 -0800174 const Eigen::Matrix<Scalar, number_of_states, 1> &X() const { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800175 Scalar X(int i, int j = 0) const { return X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800176 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y() const { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800177 Scalar Y(int i, int j = 0) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700178
Austin Schuh20388b62017-11-23 22:40:46 -0800179 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X() { return X_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800180 Scalar &mutable_X(int i, int j = 0) { return mutable_X()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800181 Eigen::Matrix<Scalar, number_of_outputs, 1> &mutable_Y() { return Y_; }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800182 Scalar &mutable_Y(int i, int j = 0) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700183
James Kuszmaul109ed8d2019-02-17 21:41:04 -0800184 size_t coefficients_size() const { return coefficients_.size(); }
185
Austin Schuhb6a6d822016-02-08 00:20:40 -0800186 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700187 number_of_outputs, Scalar> &
188 coefficients(int index) const {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800189 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700190 }
191
Austin Schuhc5fceb82017-02-25 16:24:12 -0800192 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700193 number_of_outputs, Scalar> &
194 coefficients() const {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800195 return *coefficients_[index_];
196 }
197
198 int index() const { return index_; }
199 void set_index(int index) {
200 assert(index >= 0);
201 assert(index < static_cast<int>(coefficients_.size()));
202 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700203 }
204
205 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700206 X_.setZero();
207 Y_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800208 last_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800209 }
210
Austin Schuh849f0032013-03-03 23:59:53 -0800211 // Assert that U is within the hardware range.
Austin Schuh20388b62017-11-23 22:40:46 -0800212 virtual void CheckU(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400213 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh20388b62017-11-23 22:40:46 -0800214 if (U(i, 0) > U_max(i, 0) + static_cast<Scalar>(0.00001) ||
215 U(i, 0) < U_min(i, 0) - static_cast<Scalar>(0.00001)) {
Brian Silverman6260c092018-01-14 15:21:36 -0800216#if defined(__linux__)
Austin Schuhf257f3c2019-10-27 21:00:43 -0700217 AOS_LOG(FATAL, "U out of range\n");
Brian Silverman6260c092018-01-14 15:21:36 -0800218#else
219 abort();
220#endif
Austin Schuh66c19882017-02-25 13:36:28 -0800221 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800222 }
223 }
Austin Schuh849f0032013-03-03 23:59:53 -0800224
Austin Schuhb39f4522022-03-27 13:29:42 -0700225 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
226 size_t index = 0) const {
227 return last_U_.template block<number_of_inputs, 1>(0, index);
228 }
229
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800230 // Computes the new X and Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800231 void Update(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800232 // Powers outside of the range are more likely controller bugs than things
233 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800234 CheckU(U);
Austin Schuhb39f4522022-03-27 13:29:42 -0700235 if (coefficients().delayed_u > 0) {
236#if defined(__linux__)
237 DCHECK_EQ(static_cast<ssize_t>(coefficients().delayed_u), last_U_.cols());
238#endif
239 X_ = Update(X(), last_U(coefficients().delayed_u - 1));
240 UpdateY(last_U(coefficients().delayed_u - 1));
241 for (int i = coefficients().delayed_u; i > 1; --i) {
242 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
243 last_U_.template block<number_of_inputs, 1>(0, i - 2);
244 }
245 last_U_.template block<number_of_inputs, 1>(0, 0) = U;
Austin Schuh64433f12022-02-21 19:40:38 -0800246 } else {
247 X_ = Update(X(), U);
248 UpdateY(U);
249 }
Austin Schuh01c7b252017-03-05 00:59:31 -0800250 }
251
252 // Computes the new Y given the control input.
Austin Schuh20388b62017-11-23 22:40:46 -0800253 void UpdateY(const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800254 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800255 }
256
Austin Schuh20388b62017-11-23 22:40:46 -0800257 Eigen::Matrix<Scalar, number_of_states, 1> Update(
258 const Eigen::Matrix<Scalar, number_of_states, 1> X,
259 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800260 return A() * X + B() * U;
261 }
262
James Kuszmaul9ea3ff92024-06-14 15:02:15 -0700263 // Takes the provided state and wraps all the individual values such that,
264 // for any given i in [0, number_of_states), the wrapped X[i] will be in
265 // the range [-wrap_point[i] / 2, wrap_point[i] / 2] if wrap_point[i] > 0.
266 Eigen::Matrix<Scalar, number_of_outputs, 1> HandleWrapping(
267 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) const {
268 Eigen::Matrix<Scalar, number_of_outputs, 1> wrapped;
269 for (int index = 0; index < number_of_outputs; ++index) {
270 const Scalar wrap_point = coefficients().wrap_point[index];
271 wrapped[index] =
272 wrap_point > 0
273 ? frc971::zeroing::Wrap(/*nearest=*/static_cast<Scalar>(0.0),
274 Y(index), wrap_point)
275 : Y(index);
276 }
277 return wrapped;
278 }
279
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800280 protected:
281 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800282 static const int kNumStates = number_of_states;
283 static const int kNumOutputs = number_of_outputs;
284 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700285
286 private:
Nathan Leongdd728002024-02-03 15:26:53 -0800287 // X_ and Y_ must be explicitly initialized to avoid having gcc complain about
288 // uninitialized values when using the move constructor.
289 Eigen::Matrix<Scalar, number_of_states, 1> X_ =
290 Eigen::Matrix<Scalar, number_of_states, 1>::Zero();
291 Eigen::Matrix<Scalar, number_of_outputs, 1> Y_ =
292 Eigen::Matrix<Scalar, number_of_outputs, 1>::Zero();
Austin Schuhb39f4522022-03-27 13:29:42 -0700293 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700294
Austin Schuhb6a6d822016-02-08 00:20:40 -0800295 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800296 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh64f17a52017-02-25 14:41:58 -0800297 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700298
Austin Schuhc5fceb82017-02-25 16:24:12 -0800299 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700300
301 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800302};
303
Austin Schuh32501832017-02-25 18:32:56 -0800304// A container for all the controller coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800305template <int number_of_states, int number_of_inputs, int number_of_outputs,
306 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800307struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700308 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700309
Austin Schuh20388b62017-11-23 22:40:46 -0800310 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> K;
311 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700312
Austin Schuh32501832017-02-25 18:32:56 -0800313 StateFeedbackControllerCoefficients(
Austin Schuh20388b62017-11-23 22:40:46 -0800314 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K,
315 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800316 : K(K), Kff(Kff) {}
317};
318
Austin Schuh20388b62017-11-23 22:40:46 -0800319template <int number_of_states, int number_of_inputs, int number_of_outputs,
320 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800321class StateFeedbackController {
322 public:
323 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
324
325 explicit StateFeedbackController(
326 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800327 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700328 &&controllers)
329 : coefficients_(::std::move(controllers)) {}
Austin Schuh32501832017-02-25 18:32:56 -0800330
331 StateFeedbackController(StateFeedbackController &&other)
332 : index_(other.index_) {
333 ::std::swap(coefficients_, other.coefficients_);
334 }
335
Austin Schuh20388b62017-11-23 22:40:46 -0800336 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &K() const {
Austin Schuh32501832017-02-25 18:32:56 -0800337 return coefficients().K;
338 }
Austin Schuh20388b62017-11-23 22:40:46 -0800339 Scalar K(int i, int j) const { return K()(i, j); }
340 const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &Kff() const {
Austin Schuh32501832017-02-25 18:32:56 -0800341 return coefficients().Kff;
342 }
Austin Schuh20388b62017-11-23 22:40:46 -0800343 Scalar Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800344
Austin Schuhe91f14c2017-02-25 19:43:57 -0800345 void Reset() {}
346
Austin Schuh32501832017-02-25 18:32:56 -0800347 // Sets the current controller to be index, clamped to be within range.
348 void set_index(int index) {
349 if (index < 0) {
350 index_ = 0;
351 } else if (index >= static_cast<int>(coefficients_.size())) {
352 index_ = static_cast<int>(coefficients_.size()) - 1;
353 } else {
354 index_ = index;
355 }
356 }
357
358 int index() const { return index_; }
359
360 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700361 number_of_outputs, Scalar> &
362 coefficients(int index) const {
Austin Schuh32501832017-02-25 18:32:56 -0800363 return *coefficients_[index];
364 }
365
366 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700367 number_of_outputs, Scalar> &
368 coefficients() const {
Austin Schuh32501832017-02-25 18:32:56 -0800369 return *coefficients_[index_];
370 }
371
372 private:
373 int index_ = 0;
374 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800375 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800376 coefficients_;
377};
378
Austin Schuh32501832017-02-25 18:32:56 -0800379// A container for all the observer coefficients.
Austin Schuh20388b62017-11-23 22:40:46 -0800380template <int number_of_states, int number_of_inputs, int number_of_outputs,
381 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800382struct StateFeedbackObserverCoefficients final {
383 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
384
Sabina Davis3922dfa2018-02-10 23:10:05 -0800385 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> KalmanGain;
James Kuszmaul4d752d52019-02-09 17:27:55 -0800386 const Eigen::Matrix<Scalar, number_of_states, number_of_states> Q;
387 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> R;
Austin Schuh32501832017-02-25 18:32:56 -0800388
Austin Schuh64433f12022-02-21 19:40:38 -0800389 // If true, this adds a single cycle output delay model to the plant. This is
390 // useful for modeling a control loop cycle where you sample, compute, and
391 // then queue the outputs to be ready to be executed when the next cycle
392 // happens.
Austin Schuhb39f4522022-03-27 13:29:42 -0700393 const size_t delayed_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800394
Austin Schuh32501832017-02-25 18:32:56 -0800395 StateFeedbackObserverCoefficients(
Tyler Chatow6738c362019-02-16 14:12:30 -0800396 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs>
397 &KalmanGain,
James Kuszmaul4d752d52019-02-09 17:27:55 -0800398 const Eigen::Matrix<Scalar, number_of_states, number_of_states> &Q,
Austin Schuh64433f12022-02-21 19:40:38 -0800399 const Eigen::Matrix<Scalar, number_of_outputs, number_of_outputs> &R,
Austin Schuhb39f4522022-03-27 13:29:42 -0700400 size_t delayed_u)
Austin Schuh64433f12022-02-21 19:40:38 -0800401 : KalmanGain(KalmanGain), Q(Q), R(R), delayed_u(delayed_u) {}
Austin Schuh32501832017-02-25 18:32:56 -0800402};
403
Austin Schuh20388b62017-11-23 22:40:46 -0800404template <int number_of_states, int number_of_inputs, int number_of_outputs,
405 typename Scalar = double>
Austin Schuh32501832017-02-25 18:32:56 -0800406class StateFeedbackObserver {
407 public:
408 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
409
410 explicit StateFeedbackObserver(
411 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Tyler Chatow6738c362019-02-16 14:12:30 -0800412 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuhb02bf5b2021-07-31 21:28:21 -0700413 &&observers)
Austin Schuhb39f4522022-03-27 13:29:42 -0700414 : coefficients_(::std::move(observers)) {
415 last_U_ = Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic>(
Philipp Schrader790cb542023-07-05 21:06:52 -0700416 number_of_inputs,
417 std::max(static_cast<size_t>(1u), coefficients().delayed_u));
Austin Schuhb39f4522022-03-27 13:29:42 -0700418 }
Austin Schuh32501832017-02-25 18:32:56 -0800419
420 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuh64433f12022-02-21 19:40:38 -0800421 : X_hat_(other.X_hat_), last_U_(other.last_U_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800422 ::std::swap(coefficients_, other.coefficients_);
423 }
424
Tyler Chatow6738c362019-02-16 14:12:30 -0800425 const Eigen::Matrix<Scalar, number_of_states, number_of_outputs> &KalmanGain()
426 const {
Sabina Davis3922dfa2018-02-10 23:10:05 -0800427 return coefficients().KalmanGain;
Austin Schuh32501832017-02-25 18:32:56 -0800428 }
Sabina Davis3922dfa2018-02-10 23:10:05 -0800429 Scalar KalmanGain(int i, int j) const { return KalmanGain()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800430
Austin Schuh20388b62017-11-23 22:40:46 -0800431 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800432 return X_hat_;
433 }
Austin Schuh20388b62017-11-23 22:40:46 -0800434 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800435
Austin Schuhb39f4522022-03-27 13:29:42 -0700436 const Eigen::Matrix<Scalar, number_of_inputs, 1> last_U(
437 size_t index = 0) const {
438 return last_U_.template block<number_of_inputs, 1>(0, index);
Austin Schuh482a9142022-02-23 16:54:39 -0800439 }
440
Austin Schuh6501d232017-11-23 20:35:27 -0800441 void Reset(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800442 number_of_outputs, Scalar> * /*loop*/) {
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800443 X_hat_.setZero();
Austin Schuh64433f12022-02-21 19:40:38 -0800444 last_U_.setZero();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800445 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800446
Austin Schuh6501d232017-11-23 20:35:27 -0800447 void Predict(StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800448 number_of_outputs, Scalar> *plant,
449 const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh6501d232017-11-23 20:35:27 -0800450 ::std::chrono::nanoseconds /*dt*/) {
Austin Schuhb39f4522022-03-27 13:29:42 -0700451 if (plant->coefficients().delayed_u > 0) {
452 mutable_X_hat() =
453 plant->Update(X_hat(), last_U(coefficients().delayed_u - 1));
454 for (int i = coefficients().delayed_u; i > 1; --i) {
455 last_U_.template block<number_of_inputs, 1>(0, i - 1) =
456 last_U_.template block<number_of_inputs, 1>(0, i - 2);
457 }
458 last_U_.template block<number_of_inputs, 1>(0, 0) = new_u;
Austin Schuh64433f12022-02-21 19:40:38 -0800459 } else {
460 mutable_X_hat() = plant->Update(X_hat(), new_u);
461 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800462 }
463
Austin Schuh6501d232017-11-23 20:35:27 -0800464 void Correct(const StateFeedbackPlant<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800465 number_of_outputs, Scalar> &plant,
466 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U,
467 const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
James Kuszmaul9ea3ff92024-06-14 15:02:15 -0700468 mutable_X_hat() +=
469 KalmanGain() *
470 plant.HandleWrapping(Y - plant.C() * X_hat() - plant.D() * U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800471 }
472
Austin Schuh32501832017-02-25 18:32:56 -0800473 // Sets the current controller to be index, clamped to be within range.
474 void set_index(int index) {
475 if (index < 0) {
476 index_ = 0;
477 } else if (index >= static_cast<int>(coefficients_.size())) {
478 index_ = static_cast<int>(coefficients_.size()) - 1;
479 } else {
480 index_ = index;
481 }
482 }
483
484 int index() const { return index_; }
485
486 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700487 number_of_outputs, Scalar> &
488 coefficients(int index) const {
Austin Schuh32501832017-02-25 18:32:56 -0800489 return *coefficients_[index];
490 }
491
492 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700493 number_of_outputs, Scalar> &
494 coefficients() const {
Austin Schuh32501832017-02-25 18:32:56 -0800495 return *coefficients_[index_];
496 }
497
498 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800499 // Internal state estimate.
James Kuszmauleeb98e92024-01-14 22:15:32 -0800500 Eigen::Matrix<Scalar, number_of_states, 1> X_hat_ =
501 Eigen::Matrix<Scalar, number_of_states, 1>::Zero();
Austin Schuhb39f4522022-03-27 13:29:42 -0700502 Eigen::Matrix<Scalar, number_of_inputs, Eigen::Dynamic> last_U_;
Austin Schuhe91f14c2017-02-25 19:43:57 -0800503
Austin Schuh32501832017-02-25 18:32:56 -0800504 int index_ = 0;
505 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
Austin Schuh20388b62017-11-23 22:40:46 -0800506 number_of_states, number_of_inputs, number_of_outputs, Scalar>>>
Austin Schuh32501832017-02-25 18:32:56 -0800507 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700508};
509
Austin Schuhe91f14c2017-02-25 19:43:57 -0800510template <int number_of_states, int number_of_inputs, int number_of_outputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800511 typename Scalar = double,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800512 typename PlantType = StateFeedbackPlant<
Austin Schuh20388b62017-11-23 22:40:46 -0800513 number_of_states, number_of_inputs, number_of_outputs, Scalar>,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800514 typename ObserverType = StateFeedbackObserver<
Austin Schuh20388b62017-11-23 22:40:46 -0800515 number_of_states, number_of_inputs, number_of_outputs, Scalar>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800516class StateFeedbackLoop {
517 public:
518 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
519
Austin Schuh32501832017-02-25 18:32:56 -0800520 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800521 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800522 StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh20388b62017-11-23 22:40:46 -0800523 number_of_outputs, Scalar> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800524 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800525 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800526 controller_(::std::move(controller)),
527 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700528 Reset();
529 }
530
Austin Schuhc5fceb82017-02-25 16:24:12 -0800531 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800532 : plant_(::std::move(other.plant_)),
533 controller_(::std::move(other.controller_)),
534 observer_(::std::move(other.observer_)) {
Austin Schuh36f8c4e2020-02-29 20:29:41 -0800535 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700536 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800537 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700538 U_.swap(other.U_);
539 U_uncapped_.swap(other.U_uncapped_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700540 }
541
Austin Schuh1a387962015-01-31 16:36:20 -0800542 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700543
Austin Schuh20388b62017-11-23 22:40:46 -0800544 const Eigen::Matrix<Scalar, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800545 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700546 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800547 Scalar X_hat(int i, int j = 0) const { return X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800548 const Eigen::Matrix<Scalar, number_of_states, 1> &R() const { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800549 Scalar R(int i, int j = 0) const { return R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800550 const Eigen::Matrix<Scalar, number_of_states, 1> &next_R() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800551 return next_R_;
552 }
Austin Schuh95771d92021-01-23 14:42:25 -0800553 Scalar next_R(int i, int j = 0) const { return next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800554 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U() const { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800555 Scalar U(int i, int j = 0) const { return U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800556 const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_uncapped() const {
Brian Silverman273d8a32014-05-10 22:19:09 -0700557 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700558 }
Austin Schuh95771d92021-01-23 14:42:25 -0800559 Scalar U_uncapped(int i, int j = 0) const { return U_uncapped()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800560 const Eigen::Matrix<Scalar, number_of_inputs, 1> &ff_U() const {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800561 return ff_U_;
562 }
Austin Schuh95771d92021-01-23 14:42:25 -0800563 Scalar ff_U(int i, int j = 0) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700564
Austin Schuh20388b62017-11-23 22:40:46 -0800565 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_X_hat() {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800566 return observer_.mutable_X_hat();
567 }
Sabina Davis8d20ca82018-02-19 13:17:45 -0800568 Scalar &mutable_X_hat(int i, int j = 0) { return mutable_X_hat()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800569 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_R() { return R_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800570 Scalar &mutable_R(int i, int j = 0) { return mutable_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800571 Eigen::Matrix<Scalar, number_of_states, 1> &mutable_next_R() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800572 return next_R_;
573 }
Austin Schuh95771d92021-01-23 14:42:25 -0800574 Scalar &mutable_next_R(int i, int j = 0) { return mutable_next_R()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800575 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U() { return U_; }
Austin Schuh95771d92021-01-23 14:42:25 -0800576 Scalar &mutable_U(int i, int j = 0) { return mutable_U()(i, j); }
Austin Schuh20388b62017-11-23 22:40:46 -0800577 Eigen::Matrix<Scalar, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700578 return U_uncapped_;
579 }
Austin Schuh95771d92021-01-23 14:42:25 -0800580 Scalar &mutable_U_uncapped(int i, int j = 0) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700581 return mutable_U_uncapped()(i, j);
582 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800583
Austin Schuhe91f14c2017-02-25 19:43:57 -0800584 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800585 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800586
Austin Schuh32501832017-02-25 18:32:56 -0800587 const StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuh50e3dca2023-07-23 14:34:27 -0700588 number_of_outputs, Scalar> &
589 controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800590 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700591 }
592
Austin Schuhe91f14c2017-02-25 19:43:57 -0800593 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700594
Austin Schuh9644e1c2013-03-12 00:40:36 -0700595 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700596 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800597 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700598 U_.setZero();
599 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800600 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800601
602 plant_.Reset();
603 controller_.Reset();
Austin Schuh6501d232017-11-23 20:35:27 -0800604 observer_.Reset(this->mutable_plant());
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800605 }
606
607 // If U is outside the hardware range, limit it before the plant tries to use
608 // it.
609 virtual void CapU() {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700610 // TODO(Ravago): this runs before the state update step, so it's limiting
611 // the future control based on the old state. This gets even worse when we
612 // have delayed_u.
613 Eigen::Matrix<Scalar, number_of_inputs, 1> U_max_computed =
614 plant().U_limit_coefficient() * plant().X() +
615 plant().U_limit_constant();
616 Eigen::Matrix<Scalar, number_of_inputs, 1> U_min_computed =
617 plant().U_limit_coefficient() * plant().X() -
618 plant().U_limit_constant();
619
620 U_max_computed = U_max_computed.cwiseMin(plant().U_max());
621 U_min_computed = U_min_computed.cwiseMax(plant().U_min());
622
Brian Silverman5808bcb2014-09-14 21:40:43 -0400623 for (int i = 0; i < kNumInputs; ++i) {
Ravago Jonesc471ebe2023-07-05 20:37:00 -0700624 if (U(i, 0) > U_max_computed(i, 0)) {
625 U_(i, 0) = U_max_computed(i, 0);
626 } else if (U(i, 0) < U_min_computed(i, 0)) {
627 U_(i, 0) = U_min_computed(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800628 }
629 }
630 }
631
Austin Schuhf9286cd2014-02-11 00:51:09 -0800632 // Corrects X_hat given the observation in Y.
Austin Schuh20388b62017-11-23 22:40:46 -0800633 void Correct(const Eigen::Matrix<Scalar, number_of_outputs, 1> &Y) {
Austin Schuh6501d232017-11-23 20:35:27 -0800634 observer_.Correct(this->plant(), U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800635 }
636
Austin Schuh20388b62017-11-23 22:40:46 -0800637 const Eigen::Matrix<Scalar, number_of_states, 1> error() const {
Austin Schuh3f862bb2016-02-27 14:48:05 -0800638 return R() - X_hat();
639 }
640
Austin Schuhb6a6d822016-02-08 00:20:40 -0800641 // Returns the calculated controller power.
Austin Schuh20388b62017-11-23 22:40:46 -0800642 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800643 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800644 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800645 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800646 }
647
648 // Calculates the feed forwards power.
Austin Schuh20388b62017-11-23 22:40:46 -0800649 virtual const Eigen::Matrix<Scalar, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800650 // TODO(austin): Should this live in StateSpaceController?
651 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800652 }
653
Austin Schuh43b9ae92020-02-29 23:08:38 -0800654 void UpdateController(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800655 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700656 U_.setZero();
657 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800658 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800659 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800660 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800661 CapU();
662 }
Austin Schuh43b9ae92020-02-29 23:08:38 -0800663 UpdateFFReference();
664 }
665
666 // stop_motors is whether or not to output all 0s.
667 void Update(bool stop_motors,
668 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(0)) {
669 UpdateController(stop_motors);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800670
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800671 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800672 }
673
674 // Updates R() after any CapU operations happen on U().
675 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800676 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800677 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800678 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800679 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000680 }
681
Austin Schuh20388b62017-11-23 22:40:46 -0800682 void UpdateObserver(const Eigen::Matrix<Scalar, number_of_inputs, 1> &new_u,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800683 ::std::chrono::nanoseconds dt) {
Austin Schuh6501d232017-11-23 20:35:27 -0800684 observer_.Predict(this->mutable_plant(), new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800685 }
686
Austin Schuh32501832017-02-25 18:32:56 -0800687 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800688 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800689 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800690 controller_.set_index(index);
691 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700692 }
693
Austin Schuh32501832017-02-25 18:32:56 -0800694 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700695
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800696 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800697 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800698
Austin Schuh20388b62017-11-23 22:40:46 -0800699 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs,
700 Scalar>
Austin Schuh32501832017-02-25 18:32:56 -0800701 controller_;
702
Austin Schuhe91f14c2017-02-25 19:43:57 -0800703 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700704
Brian Silverman273d8a32014-05-10 22:19:09 -0700705 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800706 static constexpr int kNumStates = number_of_states;
707 static constexpr int kNumOutputs = number_of_outputs;
708 static constexpr int kNumInputs = number_of_inputs;
709
710 // Portion of U which is based on the feed-forwards.
Austin Schuh20388b62017-11-23 22:40:46 -0800711 Eigen::Matrix<Scalar, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700712
Brian Silverman273d8a32014-05-10 22:19:09 -0700713 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800714 // Current goal (Used by the feed-back controller).
Austin Schuh20388b62017-11-23 22:40:46 -0800715 Eigen::Matrix<Scalar, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800716 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
Austin Schuh20388b62017-11-23 22:40:46 -0800717 Eigen::Matrix<Scalar, number_of_states, 1> next_R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800718 // Computed output after being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800719 Eigen::Matrix<Scalar, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800720 // Computed output before being capped.
Austin Schuh20388b62017-11-23 22:40:46 -0800721 Eigen::Matrix<Scalar, number_of_inputs, 1> U_uncapped_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700722
Brian Silverman0a151c92014-05-02 15:28:44 -0700723 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800724};
725
Brian Silverman273d8a32014-05-10 22:19:09 -0700726#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_