blob: 4c354197f5ddb2043d99c854ec14d61e17f64783 [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
Brian Silverman20fdbef2013-03-09 13:42:03 -08008// Stupid vxworks system headers define it which blows up Eigen...
9#undef m_data
10
Austin Schuhdc1c84a2013-02-23 16:33:10 -080011#include "Eigen/Dense"
12
13template <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 Schuhe3490622013-03-13 01:24:30 -0700135 assert(U(i, 0) <= U_max(i, 0));
136 assert(U(i, 0) >= U_min(i, 0));
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;
224 Eigen::Matrix<double, number_of_outputs, 1> Y;
225
Austin Schuh9644e1c2013-03-12 00:40:36 -0700226 const StateFeedbackController<
227 number_of_states, number_of_inputs, number_of_outputs>
228 &controller() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700229 return *controllers_[controller_index_];
Austin Schuh9644e1c2013-03-12 00:40:36 -0700230 }
231
Austin Schuh2054f5f2013-10-27 14:54:10 -0700232 const StateFeedbackController<
233 number_of_states, number_of_inputs, number_of_outputs>
234 &controller(int index) const {
235 return *controllers_[index];
236 }
237
Austin Schuh9644e1c2013-03-12 00:40:36 -0700238 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800239 X_hat.setZero();
240 R.setZero();
241 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800242 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800243 U_ff.setZero();
244 Y.setZero();
245 }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700246
Austin Schuhe3490622013-03-13 01:24:30 -0700247 StateFeedbackLoop(
248 const StateFeedbackController<number_of_states, number_of_inputs,
249 number_of_outputs> &controller)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700250 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700251 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700252 new StateFeedbackController<number_of_states, number_of_inputs,
253 number_of_outputs>(controller));
254 Reset();
255 }
256
257 StateFeedbackLoop(
Austin Schuhe3490622013-03-13 01:24:30 -0700258 const ::std::vector<StateFeedbackController<
259 number_of_states, number_of_inputs,
260 number_of_outputs> *> &controllers)
261 : controllers_(controllers),
Austin Schuh9644e1c2013-03-12 00:40:36 -0700262 controller_index_(0) {
263 Reset();
264 }
265
266 StateFeedbackLoop(
267 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
268 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700269 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh9644e1c2013-03-12 00:40:36 -0700270 number_of_outputs> &plant)
271 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700272 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700273 new StateFeedbackController<number_of_states, number_of_inputs,
274 number_of_outputs>(L, K, plant));
275
276 Reset();
277 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800278 virtual ~StateFeedbackLoop() {}
279
280 virtual void FeedForward() {
281 for (int i = 0; i < number_of_outputs; ++i) {
282 U_ff[i] = 0.0;
283 }
284 }
285
286 // If U is outside the hardware range, limit it before the plant tries to use
287 // it.
288 virtual void CapU() {
289 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700290 if (U(i, 0) > U_max(i, 0)) {
291 U(i, 0) = U_max(i, 0);
292 } else if (U(i, 0) < U_min(i, 0)) {
293 U(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800294 }
295 }
296 }
297
298 // update_observer is whether or not to use the values in Y.
299 // stop_motors is whether or not to output all 0s.
300 void Update(bool update_observer, bool stop_motors) {
301 if (stop_motors) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700302 U.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800303 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700304 U = U_uncapped = K() * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800305 CapU();
306 }
307
308 if (update_observer) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700309 X_hat = (A() - L() * C()) * X_hat + L() * Y + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800310 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700311 X_hat = A() * X_hat + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800312 }
313 }
314
Austin Schuh9644e1c2013-03-12 00:40:36 -0700315 // Sets the current controller to be index and verifies that it isn't out of
316 // range.
317 void set_controller_index(int index) {
Austin Schuhe3490622013-03-13 01:24:30 -0700318 if (index < 0) {
319 controller_index_ = 0;
320 } else if (index >= static_cast<int>(controllers_.size())) {
Brian Silvermanb8cd6892013-03-17 23:36:24 -0700321 controller_index_ = static_cast<int>(controllers_.size()) - 1;
Austin Schuhe3490622013-03-13 01:24:30 -0700322 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700323 controller_index_ = index;
324 }
325 }
326
327 void controller_index() const { return controller_index_; }
328
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800329 protected:
Austin Schuh2054f5f2013-10-27 14:54:10 -0700330 ::std::vector<StateFeedbackController<number_of_states, number_of_inputs,
331 number_of_outputs> *> controllers_;
332
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800333 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800334 static const int kNumStates = number_of_states;
335 static const int kNumOutputs = number_of_outputs;
336 static const int kNumInputs = number_of_inputs;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700337
338 int controller_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800339};
340
341#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_