blob: 41812f23f7f31ca93b3c27750ec78fc1e3277514 [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 Schuh01c7b252017-03-05 00:59:31 -0800163 UpdateY(U);
164 }
165
166 // Computes the new Y given the control input.
167 void UpdateY(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
Austin Schuh66c19882017-02-25 13:36:28 -0800168 Y_ = C() * X() + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800169 }
170
Austin Schuhe91f14c2017-02-25 19:43:57 -0800171 Eigen::Matrix<double, number_of_states, 1> Update(
172 const Eigen::Matrix<double, number_of_states, 1> X,
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800173 const Eigen::Matrix<double, number_of_inputs, 1> &U) const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800174 return A() * X + B() * U;
175 }
176
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800177 protected:
178 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800179 static const int kNumStates = number_of_states;
180 static const int kNumOutputs = number_of_outputs;
181 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700182
183 private:
Brian Silverman273d8a32014-05-10 22:19:09 -0700184 Eigen::Matrix<double, number_of_states, 1> X_;
185 Eigen::Matrix<double, number_of_outputs, 1> Y_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700186
Austin Schuhb6a6d822016-02-08 00:20:40 -0800187 ::std::vector<::std::unique_ptr<StateFeedbackPlantCoefficients<
Austin Schuh64f17a52017-02-25 14:41:58 -0800188 number_of_states, number_of_inputs, number_of_outputs>>>
189 coefficients_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700190
Austin Schuhc5fceb82017-02-25 16:24:12 -0800191 int index_;
Brian Silverman0a151c92014-05-02 15:28:44 -0700192
193 DISALLOW_COPY_AND_ASSIGN(StateFeedbackPlant);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800194};
195
Austin Schuh32501832017-02-25 18:32:56 -0800196// A container for all the controller coefficients.
Austin Schuh9644e1c2013-03-12 00:40:36 -0700197template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800198struct StateFeedbackControllerCoefficients final {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700199 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
Brian Silverman273d8a32014-05-10 22:19:09 -0700200
Brian Silverman5808bcb2014-09-14 21:40:43 -0400201 const Eigen::Matrix<double, number_of_inputs, number_of_states> K;
Austin Schuh86093ad2016-02-06 14:29:34 -0800202 const Eigen::Matrix<double, number_of_inputs, number_of_states> Kff;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700203
Austin Schuh32501832017-02-25 18:32:56 -0800204 StateFeedbackControllerCoefficients(
Brian Silverman5808bcb2014-09-14 21:40:43 -0400205 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K,
Austin Schuhc5fceb82017-02-25 16:24:12 -0800206 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff)
Austin Schuh32501832017-02-25 18:32:56 -0800207 : K(K), Kff(Kff) {}
208};
209
210template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800211struct StateFeedbackHybridPlantCoefficients final {
212 public:
213 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
214
215 StateFeedbackHybridPlantCoefficients(
216 const StateFeedbackHybridPlantCoefficients &other)
217 : A_continuous(other.A_continuous),
218 B_continuous(other.B_continuous),
219 C(other.C),
220 D(other.D),
221 U_min(other.U_min),
222 U_max(other.U_max) {}
223
224 StateFeedbackHybridPlantCoefficients(
225 const Eigen::Matrix<double, number_of_states, number_of_states>
226 &A_continuous,
227 const Eigen::Matrix<double, number_of_states, number_of_inputs>
228 &B_continuous,
229 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
230 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
231 const Eigen::Matrix<double, number_of_inputs, 1> &U_max,
232 const Eigen::Matrix<double, number_of_inputs, 1> &U_min)
233 : A_continuous(A_continuous),
234 B_continuous(B_continuous),
235 C(C),
236 D(D),
237 U_min(U_min),
238 U_max(U_max) {}
239
240 const Eigen::Matrix<double, number_of_states, number_of_states> A_continuous;
241 const Eigen::Matrix<double, number_of_states, number_of_inputs> B_continuous;
242 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
243 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
244 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
245 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
246};
247
248template <int number_of_states, int number_of_inputs, int number_of_outputs>
249class StateFeedbackHybridPlant {
250 public:
251 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
252
253 StateFeedbackHybridPlant(
254 ::std::vector<::std::unique_ptr<StateFeedbackHybridPlantCoefficients<
255 number_of_states, number_of_inputs, number_of_outputs>>>
256 *coefficients)
257 : coefficients_(::std::move(*coefficients)), index_(0) {
258 Reset();
259 }
260
261 StateFeedbackHybridPlant(StateFeedbackHybridPlant &&other)
262 : index_(other.index_) {
263 ::std::swap(coefficients_, other.coefficients_);
264 X_.swap(other.X_);
265 Y_.swap(other.Y_);
266 }
267
268 virtual ~StateFeedbackHybridPlant() {}
269
270 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
271 return A_;
272 }
273 double A(int i, int j) const { return A()(i, j); }
274 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
275 return B_;
276 }
277 double B(int i, int j) const { return B()(i, j); }
278 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
279 return coefficients().C;
280 }
281 double C(int i, int j) const { return C()(i, j); }
282 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
283 return coefficients().D;
284 }
285 double D(int i, int j) const { return D()(i, j); }
286 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
287 return coefficients().U_min;
288 }
289 double U_min(int i, int j) const { return U_min()(i, j); }
290 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
291 return coefficients().U_max;
292 }
293 double U_max(int i, int j) const { return U_max()(i, j); }
294
295 const Eigen::Matrix<double, number_of_states, 1> &X() const { return X_; }
296 double X(int i, int j) const { return X()(i, j); }
297 const Eigen::Matrix<double, number_of_outputs, 1> &Y() const { return Y_; }
298 double Y(int i, int j) const { return Y()(i, j); }
299
300 Eigen::Matrix<double, number_of_states, 1> &mutable_X() { return X_; }
301 double &mutable_X(int i, int j) { return mutable_X()(i, j); }
302 Eigen::Matrix<double, number_of_outputs, 1> &mutable_Y() { return Y_; }
303 double &mutable_Y(int i, int j) { return mutable_Y()(i, j); }
304
305 const StateFeedbackHybridPlantCoefficients<number_of_states, number_of_inputs,
306 number_of_outputs>
307 &coefficients(int index) const {
308 return *coefficients_[index];
309 }
310
311 const StateFeedbackHybridPlantCoefficients<number_of_states, number_of_inputs,
312 number_of_outputs>
313 &coefficients() const {
314 return *coefficients_[index_];
315 }
316
317 int index() const { return index_; }
318 void set_index(int index) {
319 assert(index >= 0);
320 assert(index < static_cast<int>(coefficients_.size()));
321 index_ = index;
322 }
323
324 void Reset() {
325 X_.setZero();
326 Y_.setZero();
327 A_.setZero();
328 B_.setZero();
Austin Schuh09cbf6a2017-04-09 18:20:08 -0700329 DelayedU_.setZero();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800330 UpdateAB(::aos::controls::kLoopFrequency);
331 }
332
333 // Assert that U is within the hardware range.
334 virtual void CheckU(const Eigen::Matrix<double, number_of_inputs, 1> &U) {
335 for (int i = 0; i < kNumInputs; ++i) {
336 if (U(i, 0) > U_max(i, 0) + 0.00001 || U(i, 0) < U_min(i, 0) - 0.00001) {
337 LOG(FATAL, "U out of range\n");
338 }
339 }
340 }
341
342 // Computes the new X and Y given the control input.
343 void Update(const Eigen::Matrix<double, number_of_inputs, 1> &U,
344 ::std::chrono::nanoseconds dt) {
345 // Powers outside of the range are more likely controller bugs than things
346 // that the plant should deal with.
347 CheckU(U);
Austin Schuh09cbf6a2017-04-09 18:20:08 -0700348 ::aos::robot_state.FetchLatest();
349
350 Eigen::Matrix<double, number_of_inputs, 1> current_U =
351 DelayedU_ * (::aos::robot_state.get()
352 ? ::aos::robot_state->voltage_battery / 12.0
353 : 1.0);
354 X_ = Update(X(), current_U);
355 Y_ = C() * X() + D() * current_U;
356 DelayedU_ = U;
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800357 }
358
Austin Schuh09cbf6a2017-04-09 18:20:08 -0700359 Eigen::Matrix<double, number_of_inputs, 1> DelayedU_;
360
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800361 Eigen::Matrix<double, number_of_states, 1> Update(
362 const Eigen::Matrix<double, number_of_states, 1> X,
363 const Eigen::Matrix<double, number_of_inputs, 1> &U,
364 ::std::chrono::nanoseconds dt) {
365 UpdateAB(dt);
366 return A() * X + B() * U;
367 }
368
369 protected:
370 // these are accessible from non-templated subclasses
371 static const int kNumStates = number_of_states;
372 static const int kNumOutputs = number_of_outputs;
373 static const int kNumInputs = number_of_inputs;
374
375 private:
376 void UpdateAB(::std::chrono::nanoseconds dt) {
377 Eigen::Matrix<double, number_of_states + number_of_inputs,
378 number_of_states + number_of_inputs>
379 M_state_continuous;
380 M_state_continuous.setZero();
381 M_state_continuous.template block<number_of_states, number_of_states>(0,
382 0) =
383 coefficients().A_continuous *
384 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
385 .count();
386 M_state_continuous.template block<number_of_states, number_of_inputs>(
387 0, number_of_states) =
388 coefficients().B_continuous *
389 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
390 .count();
391
392 Eigen::Matrix<double, number_of_states + number_of_inputs,
393 number_of_states + number_of_inputs>
394 M_state = M_state_continuous.exp();
395 A_ = M_state.template block<number_of_states, number_of_states>(0, 0);
396 B_ = M_state.template block<number_of_states, number_of_inputs>(
397 0, number_of_states);
398 }
399
400 Eigen::Matrix<double, number_of_states, 1> X_;
401 Eigen::Matrix<double, number_of_outputs, 1> Y_;
402
403 Eigen::Matrix<double, number_of_states, number_of_states> A_;
404 Eigen::Matrix<double, number_of_states, number_of_inputs> B_;
405
406
407 ::std::vector<::std::unique_ptr<StateFeedbackHybridPlantCoefficients<
408 number_of_states, number_of_inputs, number_of_outputs>>>
409 coefficients_;
410
411 int index_;
412
413 DISALLOW_COPY_AND_ASSIGN(StateFeedbackHybridPlant);
414};
415
416template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuh32501832017-02-25 18:32:56 -0800417class StateFeedbackController {
418 public:
419 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
420
421 explicit StateFeedbackController(
422 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
423 number_of_states, number_of_inputs, number_of_outputs>>> *controllers)
424 : coefficients_(::std::move(*controllers)) {}
425
426 StateFeedbackController(StateFeedbackController &&other)
427 : index_(other.index_) {
428 ::std::swap(coefficients_, other.coefficients_);
429 }
430
431 const Eigen::Matrix<double, number_of_inputs, number_of_states> &K() const {
432 return coefficients().K;
433 }
434 double K(int i, int j) const { return K()(i, j); }
435 const Eigen::Matrix<double, number_of_inputs, number_of_states> &Kff() const {
436 return coefficients().Kff;
437 }
438 double Kff(int i, int j) const { return Kff()(i, j); }
Austin Schuh32501832017-02-25 18:32:56 -0800439
Austin Schuhe91f14c2017-02-25 19:43:57 -0800440 void Reset() {}
441
Austin Schuh32501832017-02-25 18:32:56 -0800442 // Sets the current controller to be index, clamped to be within range.
443 void set_index(int index) {
444 if (index < 0) {
445 index_ = 0;
446 } else if (index >= static_cast<int>(coefficients_.size())) {
447 index_ = static_cast<int>(coefficients_.size()) - 1;
448 } else {
449 index_ = index;
450 }
451 }
452
453 int index() const { return index_; }
454
455 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
456 number_of_outputs>
457 &coefficients(int index) const {
458 return *coefficients_[index];
459 }
460
461 const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
462 number_of_outputs>
463 &coefficients() const {
464 return *coefficients_[index_];
465 }
466
467 private:
468 int index_ = 0;
469 ::std::vector<::std::unique_ptr<StateFeedbackControllerCoefficients<
470 number_of_states, number_of_inputs, number_of_outputs>>>
471 coefficients_;
472};
473
Austin Schuh32501832017-02-25 18:32:56 -0800474// A container for all the observer coefficients.
475template <int number_of_states, int number_of_inputs, int number_of_outputs>
476struct StateFeedbackObserverCoefficients final {
477 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
478
479 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
480
481 StateFeedbackObserverCoefficients(
482 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L)
483 : L(L) {}
484};
485
486template <int number_of_states, int number_of_inputs, int number_of_outputs>
487class StateFeedbackObserver {
488 public:
489 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
490
491 explicit StateFeedbackObserver(
492 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
493 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
494 : coefficients_(::std::move(*observers)) {}
495
496 StateFeedbackObserver(StateFeedbackObserver &&other)
Austin Schuhe91f14c2017-02-25 19:43:57 -0800497 : X_hat_(other.X_hat_), index_(other.index_) {
Austin Schuh32501832017-02-25 18:32:56 -0800498 ::std::swap(coefficients_, other.coefficients_);
499 }
500
501 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
502 return coefficients().L;
503 }
504 double L(int i, int j) const { return L()(i, j); }
505
Austin Schuhe91f14c2017-02-25 19:43:57 -0800506 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
507 return X_hat_;
508 }
509 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
510
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800511 void Reset(
512 StateFeedbackLoop<number_of_states, number_of_inputs, number_of_outputs,
513 StateFeedbackPlant<number_of_states, number_of_inputs,
514 number_of_outputs>,
515 StateFeedbackObserver> * /*loop*/) {
516 X_hat_.setZero();
517 }
Austin Schuhe91f14c2017-02-25 19:43:57 -0800518
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800519 void Predict(
520 StateFeedbackLoop<number_of_states, number_of_inputs, number_of_outputs,
521 StateFeedbackPlant<number_of_states, number_of_inputs,
522 number_of_outputs>,
523 StateFeedbackObserver> *loop,
524 const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
525 ::std::chrono::nanoseconds /*dt*/) {
526 mutable_X_hat() = loop->plant().Update(X_hat(), new_u);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800527 }
528
529 void Correct(const StateFeedbackLoop<
530 number_of_states, number_of_inputs, number_of_outputs,
531 StateFeedbackPlant<number_of_states, number_of_inputs,
532 number_of_outputs>,
533 StateFeedbackObserver> &loop,
534 const Eigen::Matrix<double, number_of_inputs, 1> &U,
535 const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
536 mutable_X_hat() += loop.plant().A_inv() * L() *
537 (Y - loop.plant().C() * X_hat() - loop.plant().D() * U);
538 }
539
Austin Schuh32501832017-02-25 18:32:56 -0800540 // Sets the current controller to be index, clamped to be within range.
541 void set_index(int index) {
542 if (index < 0) {
543 index_ = 0;
544 } else if (index >= static_cast<int>(coefficients_.size())) {
545 index_ = static_cast<int>(coefficients_.size()) - 1;
546 } else {
547 index_ = index;
548 }
549 }
550
551 int index() const { return index_; }
552
553 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
554 number_of_outputs>
555 &coefficients(int index) const {
556 return *coefficients_[index];
557 }
558
559 const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
560 number_of_outputs>
561 &coefficients() const {
562 return *coefficients_[index_];
563 }
564
565 private:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800566 // Internal state estimate.
567 Eigen::Matrix<double, number_of_states, 1> X_hat_;
568
Austin Schuh32501832017-02-25 18:32:56 -0800569 int index_ = 0;
570 ::std::vector<::std::unique_ptr<StateFeedbackObserverCoefficients<
571 number_of_states, number_of_inputs, number_of_outputs>>>
572 coefficients_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700573};
574
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800575// A container for all the observer coefficients.
576template <int number_of_states, int number_of_inputs, int number_of_outputs>
577struct HybridKalmanCoefficients final {
578 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
579
580 const Eigen::Matrix<double, number_of_states, number_of_states> Q_continuous;
581 const Eigen::Matrix<double, number_of_outputs, number_of_outputs> R_continuous;
582 const Eigen::Matrix<double, number_of_states, number_of_states> P_steady_state;
583
584 HybridKalmanCoefficients(
585 const Eigen::Matrix<double, number_of_states, number_of_states>
586 &Q_continuous,
587 const Eigen::Matrix<double, number_of_outputs, number_of_outputs>
588 &R_continuous,
589 const Eigen::Matrix<double, number_of_states, number_of_states>
590 &P_steady_state)
591 : Q_continuous(Q_continuous),
592 R_continuous(R_continuous),
593 P_steady_state(P_steady_state) {}
594};
595
596template <int number_of_states, int number_of_inputs, int number_of_outputs>
597class HybridKalman {
598 public:
599 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
600
601 explicit HybridKalman(
602 ::std::vector<::std::unique_ptr<HybridKalmanCoefficients<
603 number_of_states, number_of_inputs, number_of_outputs>>> *observers)
604 : coefficients_(::std::move(*observers)) {}
605
606 HybridKalman(HybridKalman &&other)
607 : X_hat_(other.X_hat_), index_(other.index_) {
608 ::std::swap(coefficients_, other.coefficients_);
609 }
610
611 // Getters for Q
612 const Eigen::Matrix<double, number_of_states, number_of_states> &Q() const {
613 return Q_;
614 }
615 double Q(int i, int j) const { return Q()(i, j); }
616 // Getters for R
617 const Eigen::Matrix<double, number_of_outputs, number_of_outputs> &R() const {
618 return R_;
619 }
620 double R(int i, int j) const { return R()(i, j); }
621
622 // Getters for P
623 const Eigen::Matrix<double, number_of_states, number_of_states> &P() const {
624 return P_;
625 }
626 double P(int i, int j) const { return P()(i, j); }
627
628 // Getters for X_hat
629 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
630 return X_hat_;
631 }
632 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() { return X_hat_; }
633
634 void Reset(StateFeedbackLoop<
635 number_of_states, number_of_inputs, number_of_outputs,
636 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
637 number_of_outputs>,
638 HybridKalman> *loop) {
639 X_hat_.setZero();
640 P_ = coefficients().P_steady_state;
641 UpdateQR(loop, ::aos::controls::kLoopFrequency);
642 }
643
644 void Predict(StateFeedbackLoop<
645 number_of_states, number_of_inputs, number_of_outputs,
646 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
647 number_of_outputs>,
648 HybridKalman> *loop,
649 const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
650 ::std::chrono::nanoseconds dt) {
651 // Trigger the predict step. This will update A() and B() in the plant.
652 mutable_X_hat() = loop->mutable_plant()->Update(X_hat(), new_u, dt);
653
654 UpdateQR(loop, dt);
655 P_ = loop->plant().A() * P_ * loop->plant().A().transpose() + Q_;
656 }
657
658 void Correct(const StateFeedbackLoop<
659 number_of_states, number_of_inputs, number_of_outputs,
660 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
661 number_of_outputs>,
662 HybridKalman> &loop,
663 const Eigen::Matrix<double, number_of_inputs, 1> &U,
664 const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
665 Eigen::Matrix<double, number_of_outputs, 1> Y_bar =
666 Y - (loop.plant().C() * X_hat_ + loop.plant().D() * U);
667 Eigen::Matrix<double, number_of_outputs, number_of_outputs> S =
668 loop.plant().C() * P_ * loop.plant().C().transpose() + R_;
669 Eigen::Matrix<double, number_of_states, number_of_outputs> KalmanGain;
670 KalmanGain = (S.transpose().ldlt().solve(
671 (P() * loop.plant().C().transpose()).transpose()))
672 .transpose();
673 X_hat_ = X_hat_ + KalmanGain * Y_bar;
674 P_ = (loop.plant().coefficients().A_continuous.Identity() -
675 KalmanGain * loop.plant().C()) *
676 P();
677 }
678
679 // Sets the current controller to be index, clamped to be within range.
680 void set_index(int index) {
681 if (index < 0) {
682 index_ = 0;
683 } else if (index >= static_cast<int>(coefficients_.size())) {
684 index_ = static_cast<int>(coefficients_.size()) - 1;
685 } else {
686 index_ = index;
687 }
688 }
689
690 int index() const { return index_; }
691
692 const HybridKalmanCoefficients<number_of_states, number_of_inputs,
693 number_of_outputs>
694 &coefficients(int index) const {
695 return *coefficients_[index];
696 }
697
698 const HybridKalmanCoefficients<number_of_states, number_of_inputs,
699 number_of_outputs>
700 &coefficients() const {
701 return *coefficients_[index_];
702 }
703
704 private:
705 void UpdateQR(StateFeedbackLoop<
706 number_of_states, number_of_inputs, number_of_outputs,
707 StateFeedbackHybridPlant<number_of_states, number_of_inputs,
708 number_of_outputs>,
709 HybridKalman> *loop,
710 ::std::chrono::nanoseconds dt) {
711 // Now, compute the discrete time Q and R coefficients.
712 Eigen::Matrix<double, number_of_states, number_of_states> Qtemp =
713 (coefficients().Q_continuous +
714 coefficients().Q_continuous.transpose()) /
715 2.0;
716 Eigen::Matrix<double, number_of_outputs, number_of_outputs> Rtemp =
717 (coefficients().R_continuous +
718 coefficients().R_continuous.transpose()) /
719 2.0;
720
721 Eigen::Matrix<double, 2 * number_of_states, 2 * number_of_states> M_gain;
722 M_gain.setZero();
723 // Set up the matrix M = [[-A, Q], [0, A.T]]
724 M_gain.template block<number_of_states, number_of_states>(0, 0) =
725 -loop->plant().coefficients().A_continuous;
726 M_gain.template block<number_of_states, number_of_states>(
727 0, number_of_states) = Qtemp;
728 M_gain.template block<number_of_states, number_of_states>(
729 number_of_states, number_of_states) =
730 loop->plant().coefficients().A_continuous.transpose();
731
732 Eigen::Matrix<double, 2 * number_of_states, 2 *number_of_states> phi =
733 (M_gain *
734 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
735 .count())
736 .exp();
737
738 // Phi12 = phi[0:number_of_states, number_of_states:2*number_of_states]
739 // Phi22 = phi[number_of_states:2*number_of_states,
740 // number_of_states:2*number_of_states]
741 Eigen::Matrix<double, number_of_states, number_of_states> phi12 =
742 phi.block(0, number_of_states, number_of_states, number_of_states);
743 Eigen::Matrix<double, number_of_states, number_of_states> phi22 = phi.block(
744 number_of_states, number_of_states, number_of_states, number_of_states);
745
746 Q_ = phi22.transpose() * phi12;
747 Q_ = (Q_ + Q_.transpose()) / 2.0;
748 R_ = Rtemp /
749 ::std::chrono::duration_cast<::std::chrono::duration<double>>(dt)
750 .count();
751 }
752
753 // Internal state estimate.
754 Eigen::Matrix<double, number_of_states, 1> X_hat_;
755 // Internal covariance estimate.
756 Eigen::Matrix<double, number_of_states, number_of_states> P_;
757
758 // Discretized Q and R for the kalman filter.
759 Eigen::Matrix<double, number_of_states, number_of_states> Q_;
760 Eigen::Matrix<double, number_of_outputs, number_of_outputs> R_;
761
762 int index_ = 0;
763 ::std::vector<::std::unique_ptr<HybridKalmanCoefficients<
764 number_of_states, number_of_inputs, number_of_outputs>>>
765 coefficients_;
766};
767
Austin Schuhe91f14c2017-02-25 19:43:57 -0800768template <int number_of_states, int number_of_inputs, int number_of_outputs,
769 typename PlantType = StateFeedbackPlant<
770 number_of_states, number_of_inputs, number_of_outputs>,
771 typename ObserverType = StateFeedbackObserver<
772 number_of_states, number_of_inputs, number_of_outputs>>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800773class StateFeedbackLoop {
774 public:
775 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
776
Austin Schuh32501832017-02-25 18:32:56 -0800777 explicit StateFeedbackLoop(
Austin Schuhe91f14c2017-02-25 19:43:57 -0800778 PlantType &&plant,
Austin Schuh32501832017-02-25 18:32:56 -0800779 StateFeedbackController<number_of_states, number_of_inputs,
780 number_of_outputs> &&controller,
Austin Schuhe91f14c2017-02-25 19:43:57 -0800781 ObserverType &&observer)
Austin Schuhc5fceb82017-02-25 16:24:12 -0800782 : plant_(::std::move(plant)),
Austin Schuh32501832017-02-25 18:32:56 -0800783 controller_(::std::move(controller)),
784 observer_(::std::move(observer)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700785 Reset();
786 }
787
Austin Schuhc5fceb82017-02-25 16:24:12 -0800788 StateFeedbackLoop(StateFeedbackLoop &&other)
Austin Schuh32501832017-02-25 18:32:56 -0800789 : plant_(::std::move(other.plant_)),
790 controller_(::std::move(other.controller_)),
791 observer_(::std::move(other.observer_)) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700792 R_.swap(other.R_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800793 next_R_.swap(other.next_R_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700794 U_.swap(other.U_);
795 U_uncapped_.swap(other.U_uncapped_);
Austin Schuhb6a6d822016-02-08 00:20:40 -0800796 ff_U_.swap(other.ff_U_);
Brian Silverman273d8a32014-05-10 22:19:09 -0700797 }
798
Austin Schuh1a387962015-01-31 16:36:20 -0800799 virtual ~StateFeedbackLoop() {}
Brian Silverman0a151c92014-05-02 15:28:44 -0700800
Brian Silverman273d8a32014-05-10 22:19:09 -0700801 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800802 return observer().X_hat();
Austin Schuh9644e1c2013-03-12 00:40:36 -0700803 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700804 double X_hat(int i, int j) const { return X_hat()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700805 const Eigen::Matrix<double, number_of_states, 1> &R() const { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700806 double R(int i, int j) const { return R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800807 const Eigen::Matrix<double, number_of_states, 1> &next_R() const {
808 return next_R_;
809 }
810 double next_R(int i, int j) const { return next_R()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700811 const Eigen::Matrix<double, number_of_inputs, 1> &U() const { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700812 double U(int i, int j) const { return U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700813 const Eigen::Matrix<double, number_of_inputs, 1> &U_uncapped() const {
814 return U_uncapped_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700815 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700816 double U_uncapped(int i, int j) const { return U_uncapped()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800817 const Eigen::Matrix<double, number_of_inputs, 1> &ff_U() const {
818 return ff_U_;
819 }
820 double ff_U(int i, int j) const { return ff_U()(i, j); }
Brian Silverman273d8a32014-05-10 22:19:09 -0700821
Austin Schuhe91f14c2017-02-25 19:43:57 -0800822 Eigen::Matrix<double, number_of_states, 1> &mutable_X_hat() {
823 return observer_.mutable_X_hat();
824 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700825 double &mutable_X_hat(int i, int j) { return mutable_X_hat()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700826 Eigen::Matrix<double, number_of_states, 1> &mutable_R() { return R_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700827 double &mutable_R(int i, int j) { return mutable_R()(i, j); }
Austin Schuhb6a6d822016-02-08 00:20:40 -0800828 Eigen::Matrix<double, number_of_states, 1> &mutable_next_R() {
829 return next_R_;
830 }
831 double &mutable_next_R(int i, int j) { return mutable_next_R()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700832 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U() { return U_; }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700833 double &mutable_U(int i, int j) { return mutable_U()(i, j); }
Brian Silverman0ca790b2014-06-12 21:33:08 -0700834 Eigen::Matrix<double, number_of_inputs, 1> &mutable_U_uncapped() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700835 return U_uncapped_;
836 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700837 double &mutable_U_uncapped(int i, int j) {
838 return mutable_U_uncapped()(i, j);
839 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800840
Austin Schuhe91f14c2017-02-25 19:43:57 -0800841 const PlantType &plant() const { return plant_; }
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800842 PlantType *mutable_plant() { return &plant_; }
Austin Schuhc5fceb82017-02-25 16:24:12 -0800843
Austin Schuh32501832017-02-25 18:32:56 -0800844 const StateFeedbackController<number_of_states, number_of_inputs,
845 number_of_outputs>
Austin Schuh66c19882017-02-25 13:36:28 -0800846 &controller() const {
Austin Schuh32501832017-02-25 18:32:56 -0800847 return controller_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700848 }
849
Austin Schuhe91f14c2017-02-25 19:43:57 -0800850 const ObserverType &observer() const { return observer_; }
Austin Schuh2054f5f2013-10-27 14:54:10 -0700851
Austin Schuh9644e1c2013-03-12 00:40:36 -0700852 void Reset() {
Brian Silverman273d8a32014-05-10 22:19:09 -0700853 R_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800854 next_R_.setZero();
Brian Silverman273d8a32014-05-10 22:19:09 -0700855 U_.setZero();
856 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800857 ff_U_.setZero();
Austin Schuhe91f14c2017-02-25 19:43:57 -0800858
859 plant_.Reset();
860 controller_.Reset();
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800861 observer_.Reset(this);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800862 }
863
864 // If U is outside the hardware range, limit it before the plant tries to use
865 // it.
866 virtual void CapU() {
Brian Silverman5808bcb2014-09-14 21:40:43 -0400867 for (int i = 0; i < kNumInputs; ++i) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800868 if (U(i, 0) > plant().U_max(i, 0)) {
869 U_(i, 0) = plant().U_max(i, 0);
870 } else if (U(i, 0) < plant().U_min(i, 0)) {
871 U_(i, 0) = plant().U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800872 }
873 }
874 }
875
Austin Schuhf9286cd2014-02-11 00:51:09 -0800876 // Corrects X_hat given the observation in Y.
877 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuhe91f14c2017-02-25 19:43:57 -0800878 observer_.Correct(*this, U(), Y);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800879 }
880
Austin Schuh3f862bb2016-02-27 14:48:05 -0800881 const Eigen::Matrix<double, number_of_states, 1> error() const {
882 return R() - X_hat();
883 }
884
Austin Schuhb6a6d822016-02-08 00:20:40 -0800885 // Returns the calculated controller power.
886 virtual const Eigen::Matrix<double, number_of_inputs, 1> ControllerOutput() {
Austin Schuh32501832017-02-25 18:32:56 -0800887 // TODO(austin): Should this live in StateSpaceController?
Austin Schuhb6a6d822016-02-08 00:20:40 -0800888 ff_U_ = FeedForward();
Austin Schuh32501832017-02-25 18:32:56 -0800889 return controller().K() * error() + ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800890 }
891
892 // Calculates the feed forwards power.
893 virtual const Eigen::Matrix<double, number_of_inputs, 1> FeedForward() {
Austin Schuh32501832017-02-25 18:32:56 -0800894 // TODO(austin): Should this live in StateSpaceController?
895 return controller().Kff() * (next_R() - plant().A() * R());
Austin Schuhb6a6d822016-02-08 00:20:40 -0800896 }
897
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800898 // stop_motors is whether or not to output all 0s.
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800899 void Update(bool stop_motors,
900 ::std::chrono::nanoseconds dt = ::std::chrono::milliseconds(5)) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800901 if (stop_motors) {
Brian Silverman273d8a32014-05-10 22:19:09 -0700902 U_.setZero();
903 U_uncapped_.setZero();
Austin Schuhb6a6d822016-02-08 00:20:40 -0800904 ff_U_.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800905 } else {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800906 U_ = U_uncapped_ = ControllerOutput();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800907 CapU();
908 }
909
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800910 UpdateObserver(U_, dt);
Austin Schuh093535c2016-03-05 23:21:00 -0800911
912 UpdateFFReference();
913 }
914
915 // Updates R() after any CapU operations happen on U().
916 void UpdateFFReference() {
Austin Schuhb6a6d822016-02-08 00:20:40 -0800917 ff_U_ -= U_uncapped() - U();
Austin Schuh32501832017-02-25 18:32:56 -0800918 if (!controller().Kff().isZero(0)) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800919 R_ = plant().A() * R() + plant().B() * ff_U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800920 }
Ben Fredrickson890c3fe2014-03-02 00:15:16 +0000921 }
922
Austin Schuh3ad5ed82017-02-25 21:36:19 -0800923 void UpdateObserver(const Eigen::Matrix<double, number_of_inputs, 1> &new_u,
924 ::std::chrono::nanoseconds dt) {
925 observer_.Predict(this, new_u, dt);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800926 }
927
Austin Schuh32501832017-02-25 18:32:56 -0800928 // Sets the current controller to be index.
Austin Schuhc5fceb82017-02-25 16:24:12 -0800929 void set_index(int index) {
Austin Schuhc5fceb82017-02-25 16:24:12 -0800930 plant_.set_index(index);
Austin Schuhe91f14c2017-02-25 19:43:57 -0800931 controller_.set_index(index);
932 observer_.set_index(index);
Austin Schuh9644e1c2013-03-12 00:40:36 -0700933 }
934
Austin Schuh32501832017-02-25 18:32:56 -0800935 int index() const { return plant_.index(); }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700936
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800937 protected:
Austin Schuhe91f14c2017-02-25 19:43:57 -0800938 PlantType plant_;
Austin Schuhc5fceb82017-02-25 16:24:12 -0800939
Austin Schuh32501832017-02-25 18:32:56 -0800940 StateFeedbackController<number_of_states, number_of_inputs, number_of_outputs>
941 controller_;
942
Austin Schuhe91f14c2017-02-25 19:43:57 -0800943 ObserverType observer_;
Austin Schuh2054f5f2013-10-27 14:54:10 -0700944
Brian Silverman273d8a32014-05-10 22:19:09 -0700945 // These are accessible from non-templated subclasses.
Austin Schuhf59b6bc2016-03-11 21:26:19 -0800946 static constexpr int kNumStates = number_of_states;
947 static constexpr int kNumOutputs = number_of_outputs;
948 static constexpr int kNumInputs = number_of_inputs;
949
950 // Portion of U which is based on the feed-forwards.
951 Eigen::Matrix<double, number_of_inputs, 1> ff_U_;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700952
Brian Silverman273d8a32014-05-10 22:19:09 -0700953 private:
Austin Schuhb6a6d822016-02-08 00:20:40 -0800954 // Current goal (Used by the feed-back controller).
Brian Silverman273d8a32014-05-10 22:19:09 -0700955 Eigen::Matrix<double, number_of_states, 1> R_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800956 // Goal to go to in the next cycle (Used by Feed-Forward controller.)
957 Eigen::Matrix<double, number_of_states, 1> next_R_;
958 // Computed output after being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700959 Eigen::Matrix<double, number_of_inputs, 1> U_;
Austin Schuhb6a6d822016-02-08 00:20:40 -0800960 // Computed output before being capped.
Brian Silverman273d8a32014-05-10 22:19:09 -0700961 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped_;
962
Brian Silverman0a151c92014-05-02 15:28:44 -0700963 DISALLOW_COPY_AND_ASSIGN(StateFeedbackLoop);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800964};
965
Brian Silverman273d8a32014-05-10 22:19:09 -0700966#endif // FRC971_CONTROL_LOOPS_STATE_FEEDBACK_LOOP_H_