blob: ed6bc2258df45bea8c58f1bfc74b693a938d5c6e [file] [log] [blame]
Austin Schuhdc1c84a2013-02-23 16:33:10 -08001#ifndef FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_
2#define FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_
3
Austin Schuh849f0032013-03-03 23:59:53 -08004#include <assert.h>
Austin Schuhdc1c84a2013-02-23 16:33:10 -08005
Brian Silvermanc571e052013-03-13 17:58:56 -07006#include <vector>
Austin Schuhcda86af2014-02-16 16:16:39 -08007#include <iostream>
Brian Silvermanc571e052013-03-13 17:58:56 -07008
Austin Schuhdc1c84a2013-02-23 16:33:10 -08009#include "Eigen/Dense"
10
Austin Schuhcda86af2014-02-16 16:16:39 -080011#include "aos/common/logging/logging.h"
12
Austin Schuhdc1c84a2013-02-23 16:33:10 -080013template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuhe3490622013-03-13 01:24:30 -070014class StateFeedbackPlantCoefficients {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080015 public:
16 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
17
18 const Eigen::Matrix<double, number_of_states, number_of_states> A;
19 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
20 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
21 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
22 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
23 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
24
Austin Schuhe3490622013-03-13 01:24:30 -070025 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuhdc1c84a2013-02-23 16:33:10 -080026 : A(other.A),
27 B(other.B),
28 C(other.C),
29 D(other.D),
30 U_min(other.U_min),
31 U_max(other.U_max) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080032 }
33
Austin Schuhe3490622013-03-13 01:24:30 -070034 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080035 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
36 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
37 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
38 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
39 const Eigen::Matrix<double, number_of_outputs, 1> &U_max,
40 const Eigen::Matrix<double, number_of_outputs, 1> &U_min)
41 : A(A),
42 B(B),
43 C(C),
44 D(D),
45 U_min(U_min),
46 U_max(U_max) {
Austin Schuhe3490622013-03-13 01:24:30 -070047 }
48
49 protected:
50 // these are accessible from non-templated subclasses
51 static const int kNumStates = number_of_states;
52 static const int kNumOutputs = number_of_outputs;
53 static const int kNumInputs = number_of_inputs;
54};
55
56template <int number_of_states, int number_of_inputs, int number_of_outputs>
57class StateFeedbackPlant {
58 public:
59 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
60 ::std::vector<StateFeedbackPlantCoefficients<
61 number_of_states, number_of_inputs, number_of_outputs> *> coefficients_;
62
63 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
64 return coefficients().A;
65 }
66 double A(int i, int j) const { return A()(i, j); }
67 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
68 return coefficients().B;
69 }
70 double B(int i, int j) const { return B()(i, j); }
71 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
72 return coefficients().C;
73 }
74 double C(int i, int j) const { return C()(i, j); }
75 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
76 return coefficients().D;
77 }
78 double D(int i, int j) const { return D()(i, j); }
79 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
80 return coefficients().U_min;
81 }
82 double U_min(int i, int j) const { return U_min()(i, j); }
83 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
84 return coefficients().U_max;
85 }
86 double U_max(int i, int j) const { return U_max()(i, j); }
87
88 const StateFeedbackPlantCoefficients<
89 number_of_states, number_of_inputs, number_of_outputs>
90 &coefficients() const {
91 return *coefficients_[plant_index_];
92 }
93
94 int plant_index() const { return plant_index_; }
95 void set_plant_index(int plant_index) {
96 if (plant_index < 0) {
97 plant_index_ = 0;
98 } else if (plant_index >= static_cast<int>(coefficients_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -070099 plant_index_ = static_cast<int>(coefficients_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -0700100 } else {
101 plant_index_ = plant_index;
102 }
103 }
104
105 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800106 X.setZero();
107 Y.setZero();
108 U.setZero();
109 }
110
Austin Schuhe3490622013-03-13 01:24:30 -0700111 Eigen::Matrix<double, number_of_states, 1> X;
112 Eigen::Matrix<double, number_of_outputs, 1> Y;
113 Eigen::Matrix<double, number_of_inputs, 1> U;
114
115 StateFeedbackPlant(
116 const ::std::vector<StateFeedbackPlantCoefficients<
117 number_of_states, number_of_inputs,
118 number_of_outputs> *> &coefficients)
119 : coefficients_(coefficients),
120 plant_index_(0) {
121 Reset();
122 }
123
124 StateFeedbackPlant(StateFeedbackPlant &&other)
125 : plant_index_(0) {
126 Reset();
127 ::std::swap(coefficients_, other.coefficients_);
128 }
129
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800130 virtual ~StateFeedbackPlant() {}
131
Austin Schuh849f0032013-03-03 23:59:53 -0800132 // Assert that U is within the hardware range.
133 virtual void CheckU() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800134 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800135 assert(U(i, 0) <= U_max(i, 0) + 0.00001);
136 assert(U(i, 0) >= U_min(i, 0) - 0.00001);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800137 }
138 }
Austin Schuh849f0032013-03-03 23:59:53 -0800139
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800140 // Computes the new X and Y given the control input.
141 void Update() {
Austin Schuh849f0032013-03-03 23:59:53 -0800142 // Powers outside of the range are more likely controller bugs than things
143 // that the plant should deal with.
144 CheckU();
Austin Schuhe3490622013-03-13 01:24:30 -0700145 X = A() * X + B() * U;
146 Y = C() * X + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800147 }
148
149 protected:
150 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800151 static const int kNumStates = number_of_states;
152 static const int kNumOutputs = number_of_outputs;
153 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700154
155 private:
156 int plant_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800157};
158
Austin Schuh9644e1c2013-03-12 00:40:36 -0700159// A Controller is a structure which holds a plant and the K and L matrices.
160// This is designed such that multiple controllers can share one set of state to
161// support gain scheduling easily.
162template <int number_of_states, int number_of_inputs, int number_of_outputs>
163struct StateFeedbackController {
164 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
165 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
166 const Eigen::Matrix<double, number_of_outputs, number_of_states> K;
Austin Schuhe3490622013-03-13 01:24:30 -0700167 StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
168 number_of_outputs> plant;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700169
170 StateFeedbackController(
171 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
172 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700173 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
174 number_of_outputs> &plant)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700175 : L(L),
176 K(K),
177 plant(plant) {
178 }
179};
180
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800181template <int number_of_states, int number_of_inputs, int number_of_outputs>
182class StateFeedbackLoop {
183 public:
184 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
185
Austin Schuh9644e1c2013-03-12 00:40:36 -0700186 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
187 return controller().plant.A;
188 }
189 double A(int i, int j) const { return A()(i, j); }
190 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
191 return controller().plant.B;
192 }
193 double B(int i, int j) const { return B()(i, j); }
194 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
195 return controller().plant.C;
196 }
197 double C(int i, int j) const { return C()(i, j); }
198 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
199 return controller().plant.D;
200 }
201 double D(int i, int j) const { return D()(i, j); }
202 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K() const {
203 return controller().K;
204 }
205 double K(int i, int j) const { return K()(i, j); }
206 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
207 return controller().L;
208 }
209 double L(int i, int j) const { return L()(i, j); }
210 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
211 return controller().plant.U_min;
212 }
213 double U_min(int i, int j) const { return U_min()(i, j); }
214 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
215 return controller().plant.U_max;
216 }
217 double U_max(int i, int j) const { return U_max()(i, j); }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800218
219 Eigen::Matrix<double, number_of_states, 1> X_hat;
220 Eigen::Matrix<double, number_of_states, 1> R;
221 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -0800222 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800223 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800224
Brian Silverman2c590c32013-11-04 18:08:54 -0800225 const StateFeedbackController<number_of_states, number_of_inputs,
226 number_of_outputs> &controller() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700227 return *controllers_[controller_index_];
Austin Schuh9644e1c2013-03-12 00:40:36 -0700228 }
229
Brian Silverman2c590c32013-11-04 18:08:54 -0800230 const StateFeedbackController<number_of_states, number_of_inputs,
231 number_of_outputs> &controller(
232 int index) const {
Austin Schuh2054f5f2013-10-27 14:54:10 -0700233 return *controllers_[index];
234 }
235
Austin Schuh9644e1c2013-03-12 00:40:36 -0700236 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800237 X_hat.setZero();
238 R.setZero();
239 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800240 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800241 U_ff.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800242 }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700243
Brian Silverman2c590c32013-11-04 18:08:54 -0800244 StateFeedbackLoop(const StateFeedbackController<
245 number_of_states, number_of_inputs, number_of_outputs> &controller)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700246 : controller_index_(0) {
Brian Silverman2c590c32013-11-04 18:08:54 -0800247 controllers_.push_back(new StateFeedbackController<
248 number_of_states, number_of_inputs, number_of_outputs>(controller));
Austin Schuh9644e1c2013-03-12 00:40:36 -0700249 Reset();
250 }
251
Brian Silverman2c590c32013-11-04 18:08:54 -0800252 StateFeedbackLoop(const ::std::vector<StateFeedbackController<
253 number_of_states, number_of_inputs, number_of_outputs> *> &controllers)
254 : controllers_(controllers), controller_index_(0) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700255 Reset();
256 }
257
258 StateFeedbackLoop(
259 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
260 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700261 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh9644e1c2013-03-12 00:40:36 -0700262 number_of_outputs> &plant)
263 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700264 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700265 new StateFeedbackController<number_of_states, number_of_inputs,
266 number_of_outputs>(L, K, plant));
267
268 Reset();
269 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800270 virtual ~StateFeedbackLoop() {}
271
272 virtual void FeedForward() {
273 for (int i = 0; i < number_of_outputs; ++i) {
274 U_ff[i] = 0.0;
275 }
276 }
277
278 // If U is outside the hardware range, limit it before the plant tries to use
279 // it.
280 virtual void CapU() {
281 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700282 if (U(i, 0) > U_max(i, 0)) {
283 U(i, 0) = U_max(i, 0);
284 } else if (U(i, 0) < U_min(i, 0)) {
285 U(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800286 }
287 }
288 }
289
Austin Schuhf9286cd2014-02-11 00:51:09 -0800290 // Corrects X_hat given the observation in Y.
291 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800292 /*
293 auto eye =
294 Eigen::Matrix<double, number_of_states, number_of_states>::Identity();
295 //LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
296 ::std::cout << "Identity " << eye << ::std::endl;
297 ::std::cout << "X_hat " << X_hat << ::std::endl;
298 ::std::cout << "LC " << L() * C() << ::std::endl;
299 ::std::cout << "L " << L() << ::std::endl;
300 ::std::cout << "C " << C() << ::std::endl;
301 ::std::cout << "y " << Y << ::std::endl;
302 ::std::cout << "z " << (Y - C() * X_hat) << ::std::endl;
303 ::std::cout << "correction " << L() * (Y - C() * X_hat) << ::std::endl;
304 X_hat = (eye - L() * C()) * X_hat + L() * Y;
305 ::std::cout << "X_hat after " << X_hat << ::std::endl;
306 ::std::cout << ::std::endl;
307 */
308 //LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
Austin Schuhf9286cd2014-02-11 00:51:09 -0800309 Y_ = Y;
310 new_y_ = true;
311 }
312
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800313 // stop_motors is whether or not to output all 0s.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800314 void Update(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800315 if (stop_motors) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700316 U.setZero();
Austin Schuh30537882014-02-18 01:07:23 -0800317 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800318 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700319 U = U_uncapped = K() * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800320 CapU();
321 }
322
Austin Schuhcda86af2014-02-16 16:16:39 -0800323 //::std::cout << "Predict xhat before " << X_hat;
324 //::std::cout << "Measurement error is " << Y_ - C() * X_hat;
325 //X_hat = A() * X_hat + B() * U;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800326 if (new_y_) {
327 X_hat = (A() - L() * C()) * X_hat + L() * Y_ + B() * U;
328 new_y_ = false;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800329 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700330 X_hat = A() * X_hat + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800331 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800332 //::std::cout << "Predict xhat after " << X_hat;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800333 }
334
Austin Schuh9644e1c2013-03-12 00:40:36 -0700335 // Sets the current controller to be index and verifies that it isn't out of
336 // range.
337 void set_controller_index(int index) {
Austin Schuhe3490622013-03-13 01:24:30 -0700338 if (index < 0) {
339 controller_index_ = 0;
340 } else if (index >= static_cast<int>(controllers_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -0700341 controller_index_ = static_cast<int>(controllers_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -0700342 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700343 controller_index_ = index;
344 }
345 }
346
Austin Schuhd34569d2014-02-18 20:26:38 -0800347 int controller_index() const { return controller_index_; }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700348
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800349 protected:
Austin Schuh2054f5f2013-10-27 14:54:10 -0700350 ::std::vector<StateFeedbackController<number_of_states, number_of_inputs,
351 number_of_outputs> *> controllers_;
352
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800353 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800354 static const int kNumStates = number_of_states;
355 static const int kNumOutputs = number_of_outputs;
356 static const int kNumInputs = number_of_inputs;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700357
Austin Schuhf9286cd2014-02-11 00:51:09 -0800358 // Temporary storage for a measurement until I can figure out why I can't
359 // correct when the measurement is made.
360 Eigen::Matrix<double, number_of_outputs, 1> Y_;
361 bool new_y_ = false;
362
Austin Schuh9644e1c2013-03-12 00:40:36 -0700363 int controller_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800364};
365
366#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_