blob: 420a0e7123798ca51cc274bda394fb50ce48ea6c [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>
7
Austin Schuhdc1c84a2013-02-23 16:33:10 -08008#include "Eigen/Dense"
9
10template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuhe3490622013-03-13 01:24:30 -070011class StateFeedbackPlantCoefficients {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080012 public:
13 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
14
15 const Eigen::Matrix<double, number_of_states, number_of_states> A;
16 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
17 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
18 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
19 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
20 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
21
Austin Schuhe3490622013-03-13 01:24:30 -070022 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuhdc1c84a2013-02-23 16:33:10 -080023 : A(other.A),
24 B(other.B),
25 C(other.C),
26 D(other.D),
27 U_min(other.U_min),
28 U_max(other.U_max) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080029 }
30
Austin Schuhe3490622013-03-13 01:24:30 -070031 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080032 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
33 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
34 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
35 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
36 const Eigen::Matrix<double, number_of_outputs, 1> &U_max,
37 const Eigen::Matrix<double, number_of_outputs, 1> &U_min)
38 : A(A),
39 B(B),
40 C(C),
41 D(D),
42 U_min(U_min),
43 U_max(U_max) {
Austin Schuhe3490622013-03-13 01:24:30 -070044 }
45
46 protected:
47 // these are accessible from non-templated subclasses
48 static const int kNumStates = number_of_states;
49 static const int kNumOutputs = number_of_outputs;
50 static const int kNumInputs = number_of_inputs;
51};
52
53template <int number_of_states, int number_of_inputs, int number_of_outputs>
54class StateFeedbackPlant {
55 public:
56 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
57 ::std::vector<StateFeedbackPlantCoefficients<
58 number_of_states, number_of_inputs, number_of_outputs> *> coefficients_;
59
60 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
61 return coefficients().A;
62 }
63 double A(int i, int j) const { return A()(i, j); }
64 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
65 return coefficients().B;
66 }
67 double B(int i, int j) const { return B()(i, j); }
68 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
69 return coefficients().C;
70 }
71 double C(int i, int j) const { return C()(i, j); }
72 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
73 return coefficients().D;
74 }
75 double D(int i, int j) const { return D()(i, j); }
76 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
77 return coefficients().U_min;
78 }
79 double U_min(int i, int j) const { return U_min()(i, j); }
80 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
81 return coefficients().U_max;
82 }
83 double U_max(int i, int j) const { return U_max()(i, j); }
84
85 const StateFeedbackPlantCoefficients<
86 number_of_states, number_of_inputs, number_of_outputs>
87 &coefficients() const {
88 return *coefficients_[plant_index_];
89 }
90
91 int plant_index() const { return plant_index_; }
92 void set_plant_index(int plant_index) {
93 if (plant_index < 0) {
94 plant_index_ = 0;
95 } else if (plant_index >= static_cast<int>(coefficients_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -070096 plant_index_ = static_cast<int>(coefficients_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -070097 } else {
98 plant_index_ = plant_index;
99 }
100 }
101
102 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800103 X.setZero();
104 Y.setZero();
105 U.setZero();
106 }
107
Austin Schuhe3490622013-03-13 01:24:30 -0700108 Eigen::Matrix<double, number_of_states, 1> X;
109 Eigen::Matrix<double, number_of_outputs, 1> Y;
110 Eigen::Matrix<double, number_of_inputs, 1> U;
111
112 StateFeedbackPlant(
113 const ::std::vector<StateFeedbackPlantCoefficients<
114 number_of_states, number_of_inputs,
115 number_of_outputs> *> &coefficients)
116 : coefficients_(coefficients),
117 plant_index_(0) {
118 Reset();
119 }
120
121 StateFeedbackPlant(StateFeedbackPlant &&other)
122 : plant_index_(0) {
123 Reset();
124 ::std::swap(coefficients_, other.coefficients_);
125 }
126
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800127 virtual ~StateFeedbackPlant() {}
128
Austin Schuh849f0032013-03-03 23:59:53 -0800129 // Assert that U is within the hardware range.
130 virtual void CheckU() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800131 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuhe3490622013-03-13 01:24:30 -0700132 assert(U(i, 0) <= U_max(i, 0));
133 assert(U(i, 0) >= U_min(i, 0));
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800134 }
135 }
Austin Schuh849f0032013-03-03 23:59:53 -0800136
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800137 // Computes the new X and Y given the control input.
138 void Update() {
Austin Schuh849f0032013-03-03 23:59:53 -0800139 // Powers outside of the range are more likely controller bugs than things
140 // that the plant should deal with.
141 CheckU();
Austin Schuhe3490622013-03-13 01:24:30 -0700142 X = A() * X + B() * U;
143 Y = C() * X + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800144 }
145
146 protected:
147 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800148 static const int kNumStates = number_of_states;
149 static const int kNumOutputs = number_of_outputs;
150 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700151
152 private:
153 int plant_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800154};
155
Austin Schuh9644e1c2013-03-12 00:40:36 -0700156// A Controller is a structure which holds a plant and the K and L matrices.
157// This is designed such that multiple controllers can share one set of state to
158// support gain scheduling easily.
159template <int number_of_states, int number_of_inputs, int number_of_outputs>
160struct StateFeedbackController {
161 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
162 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
163 const Eigen::Matrix<double, number_of_outputs, number_of_states> K;
Austin Schuhe3490622013-03-13 01:24:30 -0700164 StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
165 number_of_outputs> plant;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700166
167 StateFeedbackController(
168 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
169 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700170 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
171 number_of_outputs> &plant)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700172 : L(L),
173 K(K),
174 plant(plant) {
175 }
176};
177
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800178template <int number_of_states, int number_of_inputs, int number_of_outputs>
179class StateFeedbackLoop {
180 public:
181 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
182
Austin Schuh9644e1c2013-03-12 00:40:36 -0700183 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
184 return controller().plant.A;
185 }
186 double A(int i, int j) const { return A()(i, j); }
187 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
188 return controller().plant.B;
189 }
190 double B(int i, int j) const { return B()(i, j); }
191 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
192 return controller().plant.C;
193 }
194 double C(int i, int j) const { return C()(i, j); }
195 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
196 return controller().plant.D;
197 }
198 double D(int i, int j) const { return D()(i, j); }
199 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K() const {
200 return controller().K;
201 }
202 double K(int i, int j) const { return K()(i, j); }
203 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
204 return controller().L;
205 }
206 double L(int i, int j) const { return L()(i, j); }
207 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
208 return controller().plant.U_min;
209 }
210 double U_min(int i, int j) const { return U_min()(i, j); }
211 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
212 return controller().plant.U_max;
213 }
214 double U_max(int i, int j) const { return U_max()(i, j); }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800215
216 Eigen::Matrix<double, number_of_states, 1> X_hat;
217 Eigen::Matrix<double, number_of_states, 1> R;
218 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -0800219 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800220 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800221
Brian Silverman2c590c32013-11-04 18:08:54 -0800222 const StateFeedbackController<number_of_states, number_of_inputs,
223 number_of_outputs> &controller() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700224 return *controllers_[controller_index_];
Austin Schuh9644e1c2013-03-12 00:40:36 -0700225 }
226
Brian Silverman2c590c32013-11-04 18:08:54 -0800227 const StateFeedbackController<number_of_states, number_of_inputs,
228 number_of_outputs> &controller(
229 int index) const {
Austin Schuh2054f5f2013-10-27 14:54:10 -0700230 return *controllers_[index];
231 }
232
Austin Schuh9644e1c2013-03-12 00:40:36 -0700233 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800234 X_hat.setZero();
235 R.setZero();
236 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800237 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800238 U_ff.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800239 }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700240
Brian Silverman2c590c32013-11-04 18:08:54 -0800241 StateFeedbackLoop(const StateFeedbackController<
242 number_of_states, number_of_inputs, number_of_outputs> &controller)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700243 : controller_index_(0) {
Brian Silverman2c590c32013-11-04 18:08:54 -0800244 controllers_.push_back(new StateFeedbackController<
245 number_of_states, number_of_inputs, number_of_outputs>(controller));
Austin Schuh9644e1c2013-03-12 00:40:36 -0700246 Reset();
247 }
248
Brian Silverman2c590c32013-11-04 18:08:54 -0800249 StateFeedbackLoop(const ::std::vector<StateFeedbackController<
250 number_of_states, number_of_inputs, number_of_outputs> *> &controllers)
251 : controllers_(controllers), controller_index_(0) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700252 Reset();
253 }
254
255 StateFeedbackLoop(
256 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
257 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700258 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh9644e1c2013-03-12 00:40:36 -0700259 number_of_outputs> &plant)
260 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700261 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700262 new StateFeedbackController<number_of_states, number_of_inputs,
263 number_of_outputs>(L, K, plant));
264
265 Reset();
266 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800267 virtual ~StateFeedbackLoop() {}
268
269 virtual void FeedForward() {
270 for (int i = 0; i < number_of_outputs; ++i) {
271 U_ff[i] = 0.0;
272 }
273 }
274
275 // If U is outside the hardware range, limit it before the plant tries to use
276 // it.
277 virtual void CapU() {
278 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700279 if (U(i, 0) > U_max(i, 0)) {
280 U(i, 0) = U_max(i, 0);
281 } else if (U(i, 0) < U_min(i, 0)) {
282 U(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800283 }
284 }
285 }
286
Austin Schuhf9286cd2014-02-11 00:51:09 -0800287 // Corrects X_hat given the observation in Y.
288 void Correct(const Eigen::Matrix<double, number_of_outputs, 1> &Y) {
289 Y_ = Y;
290 new_y_ = true;
291 }
292
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800293 // stop_motors is whether or not to output all 0s.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800294 void Update(bool stop_motors) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800295 if (stop_motors) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700296 U.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800297 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700298 U = U_uncapped = K() * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800299 CapU();
300 }
301
Austin Schuhf9286cd2014-02-11 00:51:09 -0800302 if (new_y_) {
303 X_hat = (A() - L() * C()) * X_hat + L() * Y_ + B() * U;
304 new_y_ = false;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800305 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700306 X_hat = A() * X_hat + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800307 }
308 }
309
Austin Schuh9644e1c2013-03-12 00:40:36 -0700310 // Sets the current controller to be index and verifies that it isn't out of
311 // range.
312 void set_controller_index(int index) {
Austin Schuhe3490622013-03-13 01:24:30 -0700313 if (index < 0) {
314 controller_index_ = 0;
315 } else if (index >= static_cast<int>(controllers_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -0700316 controller_index_ = static_cast<int>(controllers_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -0700317 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700318 controller_index_ = index;
319 }
320 }
321
322 void controller_index() const { return controller_index_; }
323
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800324 protected:
Austin Schuh2054f5f2013-10-27 14:54:10 -0700325 ::std::vector<StateFeedbackController<number_of_states, number_of_inputs,
326 number_of_outputs> *> controllers_;
327
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800328 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800329 static const int kNumStates = number_of_states;
330 static const int kNumOutputs = number_of_outputs;
331 static const int kNumInputs = number_of_inputs;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700332
Austin Schuhf9286cd2014-02-11 00:51:09 -0800333 // Temporary storage for a measurement until I can figure out why I can't
334 // correct when the measurement is made.
335 Eigen::Matrix<double, number_of_outputs, 1> Y_;
336 bool new_y_ = false;
337
Austin Schuh9644e1c2013-03-12 00:40:36 -0700338 int controller_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800339};
340
341#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_