blob: 38ca89c08feb420990c74b44280053a3aadbb05d [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;
221 Eigen::Matrix<double, number_of_outputs, 1> Y;
222
Brian Silverman2c590c32013-11-04 18:08:54 -0800223 const StateFeedbackController<number_of_states, number_of_inputs,
224 number_of_outputs> &controller() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700225 return *controllers_[controller_index_];
Austin Schuh9644e1c2013-03-12 00:40:36 -0700226 }
227
Brian Silverman2c590c32013-11-04 18:08:54 -0800228 const StateFeedbackController<number_of_states, number_of_inputs,
229 number_of_outputs> &controller(
230 int index) const {
Austin Schuh2054f5f2013-10-27 14:54:10 -0700231 return *controllers_[index];
232 }
233
Austin Schuh9644e1c2013-03-12 00:40:36 -0700234 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800235 X_hat.setZero();
236 R.setZero();
237 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800238 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800239 U_ff.setZero();
240 Y.setZero();
241 }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700242
Brian Silverman2c590c32013-11-04 18:08:54 -0800243 StateFeedbackLoop(const StateFeedbackController<
244 number_of_states, number_of_inputs, number_of_outputs> &controller)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700245 : controller_index_(0) {
Brian Silverman2c590c32013-11-04 18:08:54 -0800246 controllers_.push_back(new StateFeedbackController<
247 number_of_states, number_of_inputs, number_of_outputs>(controller));
Austin Schuh9644e1c2013-03-12 00:40:36 -0700248 Reset();
249 }
250
Brian Silverman2c590c32013-11-04 18:08:54 -0800251 StateFeedbackLoop(const ::std::vector<StateFeedbackController<
252 number_of_states, number_of_inputs, number_of_outputs> *> &controllers)
253 : controllers_(controllers), controller_index_(0) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700254 Reset();
255 }
256
257 StateFeedbackLoop(
258 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
259 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700260 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh9644e1c2013-03-12 00:40:36 -0700261 number_of_outputs> &plant)
262 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700263 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700264 new StateFeedbackController<number_of_states, number_of_inputs,
265 number_of_outputs>(L, K, plant));
266
267 Reset();
268 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800269 virtual ~StateFeedbackLoop() {}
270
271 virtual void FeedForward() {
272 for (int i = 0; i < number_of_outputs; ++i) {
273 U_ff[i] = 0.0;
274 }
275 }
276
277 // If U is outside the hardware range, limit it before the plant tries to use
278 // it.
279 virtual void CapU() {
280 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700281 if (U(i, 0) > U_max(i, 0)) {
282 U(i, 0) = U_max(i, 0);
283 } else if (U(i, 0) < U_min(i, 0)) {
284 U(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800285 }
286 }
287 }
288
289 // update_observer is whether or not to use the values in Y.
290 // stop_motors is whether or not to output all 0s.
291 void Update(bool update_observer, bool stop_motors) {
292 if (stop_motors) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700293 U.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800294 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700295 U = U_uncapped = K() * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800296 CapU();
297 }
298
299 if (update_observer) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700300 X_hat = (A() - L() * C()) * X_hat + L() * Y + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800301 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700302 X_hat = A() * X_hat + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800303 }
304 }
305
Austin Schuh9644e1c2013-03-12 00:40:36 -0700306 // Sets the current controller to be index and verifies that it isn't out of
307 // range.
308 void set_controller_index(int index) {
Austin Schuhe3490622013-03-13 01:24:30 -0700309 if (index < 0) {
310 controller_index_ = 0;
311 } else if (index >= static_cast<int>(controllers_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -0700312 controller_index_ = static_cast<int>(controllers_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -0700313 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700314 controller_index_ = index;
315 }
316 }
317
318 void controller_index() const { return controller_index_; }
319
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800320 protected:
Austin Schuh2054f5f2013-10-27 14:54:10 -0700321 ::std::vector<StateFeedbackController<number_of_states, number_of_inputs,
322 number_of_outputs> *> controllers_;
323
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800324 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800325 static const int kNumStates = number_of_states;
326 static const int kNumOutputs = number_of_outputs;
327 static const int kNumInputs = number_of_inputs;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700328
329 int controller_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800330};
331
332#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_