blob: 6d054444f0fd4b79d55574ee8c4519083db23387 [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
Austin Schuh849f0032013-03-03 23:59:53 -08004#include <assert.h>
Austin Schuhdc1c84a2013-02-23 16:33:10 -08005
Austin Schuhcda86af2014-02-16 16:16:39 -08006#include <iostream>
Austin Schuhc5fceb82017-02-25 16:24:12 -08007#include <memory>
8#include <utility>
9#include <vector>
Austin Schuh3ad5ed82017-02-25 21:36:19 -080010#include <chrono>
Brian Silvermanc571e052013-03-13 17:58:56 -070011
Austin Schuhdc1c84a2013-02-23 16:33:10 -080012#include "Eigen/Dense"
Austin Schuh3ad5ed82017-02-25 21:36:19 -080013#include "unsupported/Eigen/MatrixFunctions"
Austin Schuhdc1c84a2013-02-23 16:33:10 -080014
Austin Schuh3ad5ed82017-02-25 21:36:19 -080015#include "aos/common/controls/control_loop.h"
Austin Schuhcda86af2014-02-16 16:16:39 -080016#include "aos/common/logging/logging.h"
Brian Silverman0a151c92014-05-02 15:28:44 -070017#include "aos/common/macros.h"
18
Austin Schuhe91f14c2017-02-25 19:43:57 -080019template <int number_of_states, int number_of_inputs, int number_of_outputs,
20 typename PlantType, typename ObserverType>
21class StateFeedbackLoop;
22
Brian Silverman5808bcb2014-09-14 21:40:43 -040023// For everything in this file, "inputs" and "outputs" are defined from the
24// perspective of the plant. This means U is an input and Y is an output
25// (because you give the plant U (powers) and it gives you back a Y (sensor
26// values). This is the opposite of what they mean from the perspective of the
27// controller (U is an output because that's what goes to the motors and Y is an
28// input because that's what comes back from the sensors).
29
Austin Schuhdc1c84a2013-02-23 16:33:10 -080030template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh64f17a52017-02-25 14:41:58 -080031struct StateFeedbackPlantCoefficients final {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080032 public:
33 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
34
Austin Schuhe3490622013-03-13 01:24:30 -070035 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuh64f17a52017-02-25 14:41:58 -080036 : A(other.A),
Austin Schuhc5fceb82017-02-25 16:24:12 -080037 A_inv(other.A_inv),
Austin Schuh64f17a52017-02-25 14:41:58 -080038 B(other.B),
Austin Schuh64f17a52017-02-25 14:41:58 -080039 C(other.C),
40 D(other.D),
41 U_min(other.U_min),
42 U_max(other.U_max) {}
Austin Schuhdc1c84a2013-02-23 16:33:10 -080043
Austin Schuhe3490622013-03-13 01:24:30 -070044 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080045 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
Austin Schuhc5fceb82017-02-25 16:24:12 -080046 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv,
Austin Schuhdc1c84a2013-02-23 16:33:10 -080047 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
48 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
49 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
Brian Silverman5808bcb2014-09-14 21:40:43 -040050 const Eigen::Matrix<double, number_of_inputs, 1> &U_max,
51 const Eigen::Matrix<double, number_of_inputs, 1> &U_min)
Austin Schuh3ad5ed82017-02-25 21:36:19 -080052 : A(A), A_inv(A_inv), B(B), C(C), D(D), U_min(U_min), U_max(U_max) {}
Austin Schuhe3490622013-03-13 01:24:30 -070053
Austin Schuh64f17a52017-02-25 14:41:58 -080054 const Eigen::Matrix<double, number_of_states, number_of_states> A;
Austin Schuhc5fceb82017-02-25 16:24:12 -080055 const Eigen::Matrix<double, number_of_states, number_of_states> A_inv;
Austin Schuh64f17a52017-02-25 14:41:58 -080056 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
Austin Schuh64f17a52017-02-25 14:41:58 -080057 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
58 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
59 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
60 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
Austin Schuhe3490622013-03-13 01:24:30 -070061};
62
63template <int number_of_states, int number_of_inputs, int number_of_outputs>
64class StateFeedbackPlant {
65 public:
66 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman0a151c92014-05-02 15:28:44 -070067
68 StateFeedbackPlant(
Austin Schuhb6a6d822016-02-08 00:20:40 -080069 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh66c19882017-02-25 13:36:28 -080070 number_of_states, number_of_inputs, number_of_outputs>>>
71 *coefficients)
Austin Schuhc5fceb82017-02-25 16:24:12 -080072 : coefficients_(::std::move(*coefficients)), index_(0) {
Brian Silverman0a151c92014-05-02 15:28:44 -070073 Reset();
74 }
75
76 StateFeedbackPlant(StateFeedbackPlant &&other)
Austin Schuhc5fceb82017-02-25 16:24:12 -080077 : index_(other.index_) {
Brian Silverman0a151c92014-05-02 15:28:44 -070078 ::std::swap(coefficients_, other.coefficients_);
Brian Silverman273d8a32014-05-10 22:19:09 -070079 X_.swap(other.X_);
80 Y_.swap(other.Y_);
Brian Silverman0a151c92014-05-02 15:28:44 -070081 }
82
Austin Schuh1a387962015-01-31 16:36:20 -080083 virtual ~StateFeedbackPlant() {}
Brian Silverman0a151c92014-05-02 15:28:44 -070084
Austin Schuhe3490622013-03-13 01:24:30 -070085 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080086 return coefficients().A;
Austin Schuhe3490622013-03-13 01:24:30 -070087 }
88 double A(int i, int j) const { return A()(i, j); }
Austin Schuhc5fceb82017-02-25 16:24:12 -080089 const Eigen::Matrix<double, number_of_states, number_of_states> &A_inv() const {
90 return coefficients().A_inv;
91 }
92 double A_inv(int i, int j) const { return A_inv()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -070093 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080094 return coefficients().B;
Austin Schuhe3490622013-03-13 01:24:30 -070095 }
96 double B(int i, int j) const { return B()(i, j); }
97 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
Austin Schuh64f17a52017-02-25 14:41:58 -080098 return coefficients().C;
Austin Schuhe3490622013-03-13 01:24:30 -070099 }
100 double C(int i, int j) const { return C()(i, j); }
101 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800102 return coefficients().D;
Austin Schuhe3490622013-03-13 01:24:30 -0700103 }
104 double D(int i, int j) const { return D()(i, j); }
105 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800106 return coefficients().U_min;
Austin Schuhe3490622013-03-13 01:24:30 -0700107 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700108 double U_min(int i, int j) const { return U_min()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700109 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
Austin Schuh64f17a52017-02-25 14:41:58 -0800110 return coefficients().U_max;
Austin Schuhe3490622013-03-13 01:24:30 -0700111 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700112 double U_max(int i, int j) const { return U_max()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700113
114 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700115 double X(int i, int j) const { return X()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700116 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700117 double Y(int i, int j) const { return Y()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700118
Brian Silverman0ca790b2014-06-12 21:33:08 -0700119 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700120 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700121 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700122 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
Austin Schuhe3490622013-03-13 01:24:30 -0700123
Austin Schuhb6a6d822016-02-08 00:20:40 -0800124 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800125 number_of_outputs>
126 &coefficients(int index) const {
127 return *coefficients_[index];
Austin Schuhe3490622013-03-13 01:24:30 -0700128 }
129
Austin Schuhc5fceb82017-02-25 16:24:12 -0800130 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
131 number_of_outputs>
132 &coefficients() const {
133 return *coefficients_[index_];
134 }
135
136 int index() const { return index_; }
137 void set_index(int index) {
138 assert(index >= 0);
139 assert(index < static_cast<int>(coefficients_.size()));
140 index_ = index;
Austin Schuhe3490622013-03-13 01:24:30 -0700141 }
142
143 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700144 X_.setZero();
145 Y_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800146 }
147
Austin Schuh849f0032013-03-03 23:59:53 -0800148 // Assert that U is within the hardware range.
Austin Schuh66c19882017-02-25 13:36:28 -0800149 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400150 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuh66c19882017-02-25 13:36:28 -0800151 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
152 LOG(FATAL, "U out of range\n");
153 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800154 }
155 }
Austin Schuh849f0032013-03-03 23:59:53 -0800156
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800157 // Computes the new X and Y given the control input.
Austin Schuh66c19882017-02-25 13:36:28 -0800158 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh849f0032013-03-03 23:59:53 -0800159 // Powers outside of the range are more likely controller bugs than things
160 // that the plant should deal with.
Austin Schuh66c19882017-02-25 13:36:28 -0800161 CheckU(U);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800162 X_ = Update(X(), U);
Austin Schuh66c19882017-02-25 13:36:28 -0800163 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800164 }
165
Austin Schuhe91f14c2017-02-25 19:43:57 -0800166 Eigen::Matrix<double, number_of_states, 1> Update(
167 const Eigen::Matrix<double, number_of_states, 1> X,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800168 const Eigen::Matrix<double, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800169 return A() * X + B() * U;
170 }
171
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800172 protected:
173 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800174 static const int kNumStates = number_of_states;
175 static const int kNumOutputs = number_of_outputs;
176 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700177
178 private:
Brian Silverman273d8a32014-05-10 22:19:09 -0700179 Eigen::Matrix<double, number_of_states, 1> X_;
180 Eigen::Matrix<double, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700181
Austin Schuhb6a6d822016-02-08 00:20:40 -0800182 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh64f17a52017-02-25 14:41:58 -0800183 number_of_states, number_of_inputs, number_of_outputs>>>
184 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700185
Austin Schuhc5fceb82017-02-25 16:24:12 -0800186 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700187
188 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800189};
190
Austin Schuh32501832017-02-25 18:32:56 -0800191// A container for all the controller coefficients.
Austin Schuh9644e1c2013-03-12 00:40:36 -0700192template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800193struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700194 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700195
Brian Silverman5808bcb2014-09-14 21:40:43 -0400196 const Eigen::Matrix<double, number_of_inputs, number_of_states> K;
Austin Schuh86093ad2016-02-06 14:29:34 -0800197 const Eigen::Matrix<double, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700198
Austin Schuh32501832017-02-25 18:32:56 -0800199 StateFeedbackControllerCoefficients(
Brian Silverman5808bcb2014-09-14 21:40:43 -0400200 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800201 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800202 : K(K), Kff(Kff) {}
203};
204
205template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800206struct StateFeedbackHybridPlantCoefficients final {
207 public:
208 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
209
210 StateFeedbackHybridPlantCoefficients(
211 const StateFeedbackHybridPlantCoefficients &other)
212 : A_continuous(other.A_continuous),
213 B_continuous(other.B_continuous),
214 C(other.C),
215 D(other.D),
216 U_min(other.U_min),
217 U_max(other.U_max) {}
218
219 StateFeedbackHybridPlantCoefficients(
220 const Eigen::Matrix<double, number_of_states, number_of_states>
221 &A_continuous,
222 const Eigen::Matrix<double, number_of_states, number_of_inputs>
223 &B_continuous,
224 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
225 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
226 const Eigen::Matrix<double, number_of_inputs, 1> &U_max,
227 const Eigen::Matrix<double, number_of_inputs, 1> &U_min)
228 : A_continuous(A_continuous),
229 B_continuous(B_continuous),
230 C(C),
231 D(D),
232 U_min(U_min),
233 U_max(U_max) {}
234
235 const Eigen::Matrix<double, number_of_states, number_of_states> A_continuous;
236 const Eigen::Matrix<double, number_of_states, number_of_inputs> B_continuous;
237 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
238 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
239 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
240 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
241};
242
243template <int number_of_states, int number_of_inputs, int number_of_outputs>
244class StateFeedbackHybridPlant {
245 public:
246 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
247
248 StateFeedbackHybridPlant(
249 ::std::vector<::std::unique_ptr<StateFeedbackHybridPlantCoefficients<
250 number_of_states, number_of_inputs, number_of_outputs>>>
251 *coefficients)
252 : coefficients_(::std::move(*coefficients)), index_(0) {
253 Reset();
254 }
255
256 StateFeedbackHybridPlant(StateFeedbackHybridPlant &&other)
257 : index_(other.index_) {
258 ::std::swap(coefficients_, other.coefficients_);
259 X_.swap(other.X_);
260 Y_.swap(other.Y_);
261 }
262
263 virtual ~StateFeedbackHybridPlant() {}
264
265 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
266 return A_;
267 }
268 double A(int i, int j) const { return A()(i, j); }
269 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
270 return B_;
271 }
272 double B(int i, int j) const { return B()(i, j); }
273 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
274 return coefficients().C;
275 }
276 double C(int i, int j) const { return C()(i, j); }
277 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
278 return coefficients().D;
279 }
280 double D(int i, int j) const { return D()(i, j); }
281 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
282 return coefficients().U_min;
283 }
284 double U_min(int i, int j) const { return U_min()(i, j); }
285 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
286 return coefficients().U_max;
287 }
288 double U_max(int i, int j) const { return U_max()(i, j); }
289
290 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
291 double X(int i, int j) const { return X()(i, j); }
292 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
293 double Y(int i, int j) const { return Y()(i, j); }
294
295 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
296 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
297 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
298 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
299
300 const StateFeedbackHybridPlantCoefficients<number_of_states, number_of_inputs,
301 number_of_outputs>
302 &coefficients(int index) const {
303 return *coefficients_[index];
304 }
305
306 const StateFeedbackHybridPlantCoefficients<number_of_states, number_of_inputs,
307 number_of_outputs>
308 &coefficients() const {
309 return *coefficients_[index_];
310 }
311
312 int index() const { return index_; }
313 void set_index(int index) {
314 assert(index >= 0);
315 assert(index < static_cast<int>(coefficients_.size()));
316 index_ = index;
317 }
318
319 void Reset() {
320 X_.setZero();
321 Y_.setZero();
322 A_.setZero();
323 B_.setZero();
324 UpdateAB(::aos::controls::kLoopFrequency);
325 }
326
327 // Assert that U is within the hardware range.
328 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
329 for (int i = 0; i < kNumInputs; ++i) {
330 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
331 LOG(FATAL, "U out of range\n");
332 }
333 }
334 }
335
336 // Computes the new X and Y given the control input.
337 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U,
338 ::std::chrono::nanoseconds dt) {
339 // Powers outside of the range are more likely controller bugs than things
340 // that the plant should deal with.
341 CheckU(U);
342 X_ = Update(X(), U, dt);
343 Y_ = C() * X() + D() * U;
344 }
345
346 Eigen::Matrix<double, number_of_states, 1> Update(
347 const Eigen::Matrix<double, number_of_states, 1> X,
348 const Eigen::Matrix<double, number_of_inputs, 1> &U,
349 ::std::chrono::nanoseconds dt) {
350 UpdateAB(dt);
351 return A() * X + B() * U;
352 }
353
354 protected:
355 // these are accessible from non-templated subclasses
356 static const int kNumStates = number_of_states;
357 static const int kNumOutputs = number_of_outputs;
358 static const int kNumInputs = number_of_inputs;
359
360 private:
361 void UpdateAB(::std::chrono::nanoseconds dt) {
362 Eigen::Matrix<double, number_of_states + number_of_inputs,
363 number_of_states + number_of_inputs>
364 M_state_continuous;
365 M_state_continuous.setZero();
366 M_state_continuous.template block<number_of_states, number_of_states>(0,
367 0) =
368 coefficients().A_continuous *
369 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
370 .count();
371 M_state_continuous.template block<number_of_states, number_of_inputs>(
372 0, number_of_states) =
373 coefficients().B_continuous *
374 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
375 .count();
376
377 Eigen::Matrix<double, number_of_states + number_of_inputs,
378 number_of_states + number_of_inputs>
379 M_state = M_state_continuous.exp();
380 A_ = M_state.template block<number_of_states, number_of_states>(0, 0);
381 B_ = M_state.template block<number_of_states, number_of_inputs>(
382 0, number_of_states);
383 }
384
385 Eigen::Matrix<double, number_of_states, 1> X_;
386 Eigen::Matrix<double, number_of_outputs, 1> Y_;
387
388 Eigen::Matrix<double, number_of_states, number_of_states> A_;
389 Eigen::Matrix<double, number_of_states, number_of_inputs> B_;
390
391
392 ::std::vector<::std::unique_ptr<StateFeedbackHybridPlantCoefficients<
393 number_of_states, number_of_inputs, number_of_outputs>>>
394 coefficients_;
395
396 int index_;
397
398 DISALLOW_COPY_AND_ASSIGN(StateFeedbackHybridPlant);
399};
400
401template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800402class StateFeedbackController {
403 public:
404 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
405
406 explicit StateFeedbackController(
407 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
408 number_of_states, number_of_inputs, number_of_outputs>>> *controllers)
409 : coefficients_(::std::move(*controllers)) {}
410
411 StateFeedbackController(StateFeedbackController &&other)
412 : index_(other.index_) {
413 ::std::swap(coefficients_, other.coefficients_);
414 }
415
416 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K() const {
417 return coefficients().K;
418 }
419 double K(int i, int j) const { return K()(i, j); }
420 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff() const {
421 return coefficients().Kff;
422 }
423 double Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800424
Austin Schuhe91f14c2017-02-25 19:43:57 -0800425 void Reset() {}
426
Austin Schuh32501832017-02-25 18:32:56 -0800427 // Sets the current controller to be index, clamped to be within range.
428 void set_index(int index) {
429 if (index < 0) {
430 index_ = 0;
431 } else if (index >= static_cast<int>(coefficients_.size())) {
432 index_ = static_cast<int>(coefficients_.size()) - 1;
433 } else {
434 index_ = index;
435 }
436 }
437
438 int index() const { return index_; }
439
440 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
441 number_of_outputs>
442 &coefficients(int index) const {
443 return *coefficients_[index];
444 }
445
446 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
447 number_of_outputs>
448 &coefficients() const {
449 return *coefficients_[index_];
450 }
451
452 private:
453 int index_ = 0;
454 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
455 number_of_states, number_of_inputs, number_of_outputs>>>
456 coefficients_;
457};
458
Austin Schuh32501832017-02-25 18:32:56 -0800459// A container for all the observer coefficients.
460template <int number_of_states, int number_of_inputs, int number_of_outputs>
461struct StateFeedbackObserverCoefficients final {
462 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
463
464 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
465
466 StateFeedbackObserverCoefficients(
467 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L)
468 : L(L) {}
469};
470
471template <int number_of_states, int number_of_inputs, int number_of_outputs>
472class StateFeedbackObserver {
473 public:
474 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
475
476 explicit StateFeedbackObserver(
477 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
478 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
479 : coefficients_(::std::move(*observers)) {}
480
481 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800482 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800483 ::std::swap(coefficients_, other.coefficients_);
484 }
485
486 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
487 return coefficients().L;
488 }
489 double L(int i, int j) const { return L()(i, j); }
490
Austin Schuhe91f14c2017-02-25 19:43:57 -0800491 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
492 return X_hat_;
493 }
494 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
495
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800496 void Reset(
497 StateFeedbackLoop<number_of_states, number_of_inputs, number_of_outputs,
498 StateFeedbackPlant<number_of_states, number_of_inputs,
499 number_of_outputs>,
500 StateFeedbackObserver> * /*loop*/) {
501 X_hat_.setZero();
502 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800503
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800504 void Predict(
505 StateFeedbackLoop<number_of_states, number_of_inputs, number_of_outputs,
506 StateFeedbackPlant<number_of_states, number_of_inputs,
507 number_of_outputs>,
508 StateFeedbackObserver> *loop,
509 const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
510 ::std::chrono::nanoseconds /*dt*/) {
511 mutable_X_hat() = loop->plant().Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800512 }
513
514 void Correct(const StateFeedbackLoop<
515 number_of_states, number_of_inputs, number_of_outputs,
516 StateFeedbackPlant<number_of_states, number_of_inputs,
517 number_of_outputs>,
518 StateFeedbackObserver> &loop,
519 const Eigen::Matrix<double, number_of_inputs, 1> &U,
520 const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
521 mutable_X_hat() += loop.plant().A_inv() * L() *
522 (Y - loop.plant().C() * X_hat() - loop.plant().D() * U);
523 }
524
Austin Schuh32501832017-02-25 18:32:56 -0800525 // Sets the current controller to be index, clamped to be within range.
526 void set_index(int index) {
527 if (index < 0) {
528 index_ = 0;
529 } else if (index >= static_cast<int>(coefficients_.size())) {
530 index_ = static_cast<int>(coefficients_.size()) - 1;
531 } else {
532 index_ = index;
533 }
534 }
535
536 int index() const { return index_; }
537
538 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
539 number_of_outputs>
540 &coefficients(int index) const {
541 return *coefficients_[index];
542 }
543
544 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
545 number_of_outputs>
546 &coefficients() const {
547 return *coefficients_[index_];
548 }
549
550 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800551 // Internal state estimate.
552 Eigen::Matrix<double, number_of_states, 1> X_hat_;
553
Austin Schuh32501832017-02-25 18:32:56 -0800554 int index_ = 0;
555 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
556 number_of_states, number_of_inputs, number_of_outputs>>>
557 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700558};
559
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800560// A container for all the observer coefficients.
561template <int number_of_states, int number_of_inputs, int number_of_outputs>
562struct HybridKalmanCoefficients final {
563 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
564
565 const Eigen::Matrix<double, number_of_states, number_of_states> Q_continuous;
566 const Eigen::Matrix<double, number_of_outputs, number_of_outputs> R_continuous;
567 const Eigen::Matrix<double, number_of_states, number_of_states> P_steady_state;
568
569 HybridKalmanCoefficients(
570 const Eigen::Matrix<double, number_of_states, number_of_states>
571 &Q_continuous,
572 const Eigen::Matrix<double, number_of_outputs, number_of_outputs>
573 &R_continuous,
574 const Eigen::Matrix<double, number_of_states, number_of_states>
575 &P_steady_state)
576 : Q_continuous(Q_continuous),
577 R_continuous(R_continuous),
578 P_steady_state(P_steady_state) {}
579};
580
581template <int number_of_states, int number_of_inputs, int number_of_outputs>
582class HybridKalman {
583 public:
584 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
585
586 explicit HybridKalman(
587 ::std::vector<::std::unique_ptr<HybridKalmanCoefficients<
588 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
589 : coefficients_(::std::move(*observers)) {}
590
591 HybridKalman(HybridKalman &&other)
592 : X_hat_(other.X_hat_), index_(other.index_) {
593 ::std::swap(coefficients_, other.coefficients_);
594 }
595
596 // Getters for Q
597 const Eigen::Matrix<double, number_of_states, number_of_states> &Q() const {
598 return Q_;
599 }
600 double Q(int i, int j) const { return Q()(i, j); }
601 // Getters for R
602 const Eigen::Matrix<double, number_of_outputs, number_of_outputs> &R() const {
603 return R_;
604 }
605 double R(int i, int j) const { return R()(i, j); }
606
607 // Getters for P
608 const Eigen::Matrix<double, number_of_states, number_of_states> &P() const {
609 return P_;
610 }
611 double P(int i, int j) const { return P()(i, j); }
612
613 // Getters for X_hat
614 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
615 return X_hat_;
616 }
617 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
618
619 void Reset(StateFeedbackLoop<
620 number_of_states, number_of_inputs, number_of_outputs,
621 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
622 number_of_outputs>,
623 HybridKalman> *loop) {
624 X_hat_.setZero();
625 P_ = coefficients().P_steady_state;
626 UpdateQR(loop, ::aos::controls::kLoopFrequency);
627 }
628
629 void Predict(StateFeedbackLoop<
630 number_of_states, number_of_inputs, number_of_outputs,
631 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
632 number_of_outputs>,
633 HybridKalman> *loop,
634 const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
635 ::std::chrono::nanoseconds dt) {
636 // Trigger the predict step. This will update A() and B() in the plant.
637 mutable_X_hat() = loop->mutable_plant()->Update(X_hat(), new_u, dt);
638
639 UpdateQR(loop, dt);
640 P_ = loop->plant().A() * P_ * loop->plant().A().transpose() + Q_;
641 }
642
643 void Correct(const StateFeedbackLoop<
644 number_of_states, number_of_inputs, number_of_outputs,
645 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
646 number_of_outputs>,
647 HybridKalman> &loop,
648 const Eigen::Matrix<double, number_of_inputs, 1> &U,
649 const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
650 Eigen::Matrix<double, number_of_outputs, 1> Y_bar =
651 Y - (loop.plant().C() * X_hat_ + loop.plant().D() * U);
652 Eigen::Matrix<double, number_of_outputs, number_of_outputs> S =
653 loop.plant().C() * P_ * loop.plant().C().transpose() + R_;
654 Eigen::Matrix<double, number_of_states, number_of_outputs> KalmanGain;
655 KalmanGain = (S.transpose().ldlt().solve(
656 (P() * loop.plant().C().transpose()).transpose()))
657 .transpose();
658 X_hat_ = X_hat_ + KalmanGain * Y_bar;
659 P_ = (loop.plant().coefficients().A_continuous.Identity() -
660 KalmanGain * loop.plant().C()) *
661 P();
662 }
663
664 // Sets the current controller to be index, clamped to be within range.
665 void set_index(int index) {
666 if (index < 0) {
667 index_ = 0;
668 } else if (index >= static_cast<int>(coefficients_.size())) {
669 index_ = static_cast<int>(coefficients_.size()) - 1;
670 } else {
671 index_ = index;
672 }
673 }
674
675 int index() const { return index_; }
676
677 const HybridKalmanCoefficients<number_of_states, number_of_inputs,
678 number_of_outputs>
679 &coefficients(int index) const {
680 return *coefficients_[index];
681 }
682
683 const HybridKalmanCoefficients<number_of_states, number_of_inputs,
684 number_of_outputs>
685 &coefficients() const {
686 return *coefficients_[index_];
687 }
688
689 private:
690 void UpdateQR(StateFeedbackLoop<
691 number_of_states, number_of_inputs, number_of_outputs,
692 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
693 number_of_outputs>,
694 HybridKalman> *loop,
695 ::std::chrono::nanoseconds dt) {
696 // Now, compute the discrete time Q and R coefficients.
697 Eigen::Matrix<double, number_of_states, number_of_states> Qtemp =
698 (coefficients().Q_continuous +
699 coefficients().Q_continuous.transpose()) /
700 2.0;
701 Eigen::Matrix<double, number_of_outputs, number_of_outputs> Rtemp =
702 (coefficients().R_continuous +
703 coefficients().R_continuous.transpose()) /
704 2.0;
705
706 Eigen::Matrix<double, 2 * number_of_states, 2 * number_of_states> M_gain;
707 M_gain.setZero();
708 // Set up the matrix M = [[-A, Q], [0, A.T]]
709 M_gain.template block<number_of_states, number_of_states>(0, 0) =
710 -loop->plant().coefficients().A_continuous;
711 M_gain.template block<number_of_states, number_of_states>(
712 0, number_of_states) = Qtemp;
713 M_gain.template block<number_of_states, number_of_states>(
714 number_of_states, number_of_states) =
715 loop->plant().coefficients().A_continuous.transpose();
716
717 Eigen::Matrix<double, 2 * number_of_states, 2 *number_of_states> phi =
718 (M_gain *
719 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
720 .count())
721 .exp();
722
723 // Phi12 = phi[0:number_of_states, number_of_states:2*number_of_states]
724 // Phi22 = phi[number_of_states:2*number_of_states,
725 // number_of_states:2*number_of_states]
726 Eigen::Matrix<double, number_of_states, number_of_states> phi12 =
727 phi.block(0, number_of_states, number_of_states, number_of_states);
728 Eigen::Matrix<double, number_of_states, number_of_states> phi22 = phi.block(
729 number_of_states, number_of_states, number_of_states, number_of_states);
730
731 Q_ = phi22.transpose() * phi12;
732 Q_ = (Q_ + Q_.transpose()) / 2.0;
733 R_ = Rtemp /
734 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
735 .count();
736 }
737
738 // Internal state estimate.
739 Eigen::Matrix<double, number_of_states, 1> X_hat_;
740 // Internal covariance estimate.
741 Eigen::Matrix<double, number_of_states, number_of_states> P_;
742
743 // Discretized Q and R for the kalman filter.
744 Eigen::Matrix<double, number_of_states, number_of_states> Q_;
745 Eigen::Matrix<double, number_of_outputs, number_of_outputs> R_;
746
747 int index_ = 0;
748 ::std::vector<::std::unique_ptr<HybridKalmanCoefficients<
749 number_of_states, number_of_inputs, number_of_outputs>>>
750 coefficients_;
751};
752
Austin Schuhe91f14c2017-02-25 19:43:57 -0800753template <int number_of_states, int number_of_inputs, int number_of_outputs,
754 typename PlantType = StateFeedbackPlant<
755 number_of_states, number_of_inputs, number_of_outputs>,
756 typename ObserverType = StateFeedbackObserver<
757 number_of_states, number_of_inputs, number_of_outputs>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800758class StateFeedbackLoop {
759 public:
760 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
761
Austin Schuh32501832017-02-25 18:32:56 -0800762 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800763 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800764 StateFeedbackController<number_of_states, number_of_inputs,
765 number_of_outputs> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800766 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800767 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800768 controller_(::std::move(controller)),
769 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700770 Reset();
771 }
772
Austin Schuhc5fceb82017-02-25 16:24:12 -0800773 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800774 : plant_(::std::move(other.plant_)),
775 controller_(::std::move(other.controller_)),
776 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700777 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800778 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700779 U_.swap(other.U_);
780 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800781 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700782 }
783
Austin Schuh1a387962015-01-31 16:36:20 -0800784 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700785
Brian Silverman273d8a32014-05-10 22:19:09 -0700786 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800787 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700788 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700789 double X_hat(int i, int j) const { return X_hat()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700790 const Eigen::Matrix<double, number_of_states, 1> &R() const { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700791 double R(int i, int j) const { return R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800792 const Eigen::Matrix<double, number_of_states, 1> &next_R() const {
793 return next_R_;
794 }
795 double next_R(int i, int j) const { return next_R()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700796 const Eigen::Matrix<double, number_of_inputs, 1> &U() const { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700797 double U(int i, int j) const { return U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700798 const Eigen::Matrix<double, number_of_inputs, 1> &U_uncapped() const {
799 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700800 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700801 double U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800802 const Eigen::Matrix<double, number_of_inputs, 1> &ff_U() const {
803 return ff_U_;
804 }
805 double ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700806
Austin Schuhe91f14c2017-02-25 19:43:57 -0800807 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() {
808 return observer_.mutable_X_hat();
809 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700810 double &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700811 Eigen::Matrix<double, number_of_states, 1> &mutable_R() { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700812 double &mutable_R(int i, int j) { return mutable_R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800813 Eigen::Matrix<double, number_of_states, 1> &mutable_next_R() {
814 return next_R_;
815 }
816 double &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700817 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U() { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700818 double &mutable_U(int i, int j) { return mutable_U()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700819 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700820 return U_uncapped_;
821 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700822 double &mutable_U_uncapped(int i, int j) {
823 return mutable_U_uncapped()(i, j);
824 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800825
Austin Schuhe91f14c2017-02-25 19:43:57 -0800826 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800827 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800828
Austin Schuh32501832017-02-25 18:32:56 -0800829 const StateFeedbackController<number_of_states, number_of_inputs,
830 number_of_outputs>
Austin Schuh66c19882017-02-25 13:36:28 -0800831 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800832 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700833 }
834
Austin Schuhe91f14c2017-02-25 19:43:57 -0800835 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700836
Austin Schuh9644e1c2013-03-12 00:40:36 -0700837 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700838 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800839 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700840 U_.setZero();
841 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800842 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800843
844 plant_.Reset();
845 controller_.Reset();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800846 observer_.Reset(this);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800847 }
848
849 // If U is outside the hardware range, limit it before the plant tries to use
850 // it.
851 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400852 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800853 if (U(i, 0) > plant().U_max(i, 0)) {
854 U_(i, 0) = plant().U_max(i, 0);
855 } else if (U(i, 0) < plant().U_min(i, 0)) {
856 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800857 }
858 }
859 }
860
Austin Schuhf9286cd2014-02-11 00:51:09 -0800861 // Corrects X_hat given the observation in Y.
862 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800863 observer_.Correct(*this, U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800864 }
865
Austin Schuh3f862bb2016-02-27 14:48:05 -0800866 const Eigen::Matrix<double, number_of_states, 1> error() const {
867 return R() - X_hat();
868 }
869
Austin Schuhb6a6d822016-02-08 00:20:40 -0800870 // Returns the calculated controller power.
871 virtual const Eigen::Matrix<double, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800872 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800873 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800874 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800875 }
876
877 // Calculates the feed forwards power.
878 virtual const Eigen::Matrix<double, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800879 // TODO(austin): Should this live in StateSpaceController?
880 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800881 }
882
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800883 // stop_motors is whether or not to output all 0s.
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800884 void Update(bool stop_motors,
885 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(5)) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800886 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700887 U_.setZero();
888 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800889 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800890 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800891 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800892 CapU();
893 }
894
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800895 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800896
897 UpdateFFReference();
898 }
899
900 // Updates R() after any CapU operations happen on U().
901 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800902 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800903 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800904 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800905 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000906 }
907
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800908 void UpdateObserver(const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
909 ::std::chrono::nanoseconds dt) {
910 observer_.Predict(this, new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800911 }
912
Austin Schuh32501832017-02-25 18:32:56 -0800913 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800914 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800915 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800916 controller_.set_index(index);
917 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700918 }
919
Austin Schuh32501832017-02-25 18:32:56 -0800920 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700921
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800922 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800923 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800924
Austin Schuh32501832017-02-25 18:32:56 -0800925 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs>
926 controller_;
927
Austin Schuhe91f14c2017-02-25 19:43:57 -0800928 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700929
Brian Silverman273d8a32014-05-10 22:19:09 -0700930 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800931 static constexpr int kNumStates = number_of_states;
932 static constexpr int kNumOutputs = number_of_outputs;
933 static constexpr int kNumInputs = number_of_inputs;
934
935 // Portion of U which is based on the feed-forwards.
936 Eigen::Matrix<double, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700937
Brian Silverman273d8a32014-05-10 22:19:09 -0700938 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800939 // Current goal (Used by the feed-back controller).
Brian Silverman273d8a32014-05-10 22:19:09 -0700940 Eigen::Matrix<double, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800941 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
942 Eigen::Matrix<double, number_of_states, 1> next_R_;
943 // Computed output after being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700944 Eigen::Matrix<double, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800945 // Computed output before being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700946 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped_;
947
Brian Silverman0a151c92014-05-02 15:28:44 -0700948 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800949};
950
Brian Silverman273d8a32014-05-10 22:19:09 -0700951#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_