blob: 7465672e1d2209dcddb21bfdf71f3e7c27333b8b [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 Silverman20fdbef2013-03-09 13:42:03 -08006// Stupid vxworks system headers define it which blows up Eigen...
7#undef m_data
8
Austin Schuhdc1c84a2013-02-23 16:33:10 -08009#include "Eigen/Dense"
10
11template <int number_of_states, int number_of_inputs, int number_of_outputs>
Austin Schuhe3490622013-03-13 01:24:30 -070012class StateFeedbackPlantCoefficients {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080013 public:
14 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
15
16 const Eigen::Matrix<double, number_of_states, number_of_states> A;
17 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
18 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
19 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
20 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
21 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
22
Austin Schuhe3490622013-03-13 01:24:30 -070023 StateFeedbackPlantCoefficients(const StateFeedbackPlantCoefficients &other)
Austin Schuhdc1c84a2013-02-23 16:33:10 -080024 : A(other.A),
25 B(other.B),
26 C(other.C),
27 D(other.D),
28 U_min(other.U_min),
29 U_max(other.U_max) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080030 }
31
Austin Schuhe3490622013-03-13 01:24:30 -070032 StateFeedbackPlantCoefficients(
Austin Schuhdc1c84a2013-02-23 16:33:10 -080033 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
34 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
35 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
36 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
37 const Eigen::Matrix<double, number_of_outputs, 1> &U_max,
38 const Eigen::Matrix<double, number_of_outputs, 1> &U_min)
39 : A(A),
40 B(B),
41 C(C),
42 D(D),
43 U_min(U_min),
44 U_max(U_max) {
Austin Schuhe3490622013-03-13 01:24:30 -070045 }
46
47 protected:
48 // these are accessible from non-templated subclasses
49 static const int kNumStates = number_of_states;
50 static const int kNumOutputs = number_of_outputs;
51 static const int kNumInputs = number_of_inputs;
52};
53
54template <int number_of_states, int number_of_inputs, int number_of_outputs>
55class StateFeedbackPlant {
56 public:
57 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
58 ::std::vector<StateFeedbackPlantCoefficients<
59 number_of_states, number_of_inputs, number_of_outputs> *> coefficients_;
60
61 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
62 return coefficients().A;
63 }
64 double A(int i, int j) const { return A()(i, j); }
65 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
66 return coefficients().B;
67 }
68 double B(int i, int j) const { return B()(i, j); }
69 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
70 return coefficients().C;
71 }
72 double C(int i, int j) const { return C()(i, j); }
73 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
74 return coefficients().D;
75 }
76 double D(int i, int j) const { return D()(i, j); }
77 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
78 return coefficients().U_min;
79 }
80 double U_min(int i, int j) const { return U_min()(i, j); }
81 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
82 return coefficients().U_max;
83 }
84 double U_max(int i, int j) const { return U_max()(i, j); }
85
86 const StateFeedbackPlantCoefficients<
87 number_of_states, number_of_inputs, number_of_outputs>
88 &coefficients() const {
89 return *coefficients_[plant_index_];
90 }
91
92 int plant_index() const { return plant_index_; }
93 void set_plant_index(int plant_index) {
94 if (plant_index < 0) {
95 plant_index_ = 0;
96 } else if (plant_index >= static_cast<int>(coefficients_.size())) {
97 plant_index_ = static_cast<int>(coefficients_.size());
98 } else {
99 plant_index_ = plant_index;
100 }
101 }
102
103 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800104 X.setZero();
105 Y.setZero();
106 U.setZero();
107 }
108
Austin Schuhe3490622013-03-13 01:24:30 -0700109 Eigen::Matrix<double, number_of_states, 1> X;
110 Eigen::Matrix<double, number_of_outputs, 1> Y;
111 Eigen::Matrix<double, number_of_inputs, 1> U;
112
113 StateFeedbackPlant(
114 const ::std::vector<StateFeedbackPlantCoefficients<
115 number_of_states, number_of_inputs,
116 number_of_outputs> *> &coefficients)
117 : coefficients_(coefficients),
118 plant_index_(0) {
119 Reset();
120 }
121
122 StateFeedbackPlant(StateFeedbackPlant &&other)
123 : plant_index_(0) {
124 Reset();
125 ::std::swap(coefficients_, other.coefficients_);
126 }
127
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800128 virtual ~StateFeedbackPlant() {}
129
Austin Schuh849f0032013-03-03 23:59:53 -0800130 // Assert that U is within the hardware range.
131 virtual void CheckU() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800132 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuhe3490622013-03-13 01:24:30 -0700133 assert(U(i, 0) <= U_max(i, 0));
134 assert(U(i, 0) >= U_min(i, 0));
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800135 }
136 }
Austin Schuh849f0032013-03-03 23:59:53 -0800137
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800138 // Computes the new X and Y given the control input.
139 void Update() {
Austin Schuh849f0032013-03-03 23:59:53 -0800140 // Powers outside of the range are more likely controller bugs than things
141 // that the plant should deal with.
142 CheckU();
Austin Schuhe3490622013-03-13 01:24:30 -0700143 X = A() * X + B() * U;
144 Y = C() * X + D() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800145 }
146
147 protected:
148 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800149 static const int kNumStates = number_of_states;
150 static const int kNumOutputs = number_of_outputs;
151 static const int kNumInputs = number_of_inputs;
Austin Schuhe3490622013-03-13 01:24:30 -0700152
153 private:
154 int plant_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800155};
156
Austin Schuh9644e1c2013-03-12 00:40:36 -0700157// A Controller is a structure which holds a plant and the K and L matrices.
158// This is designed such that multiple controllers can share one set of state to
159// support gain scheduling easily.
160template <int number_of_states, int number_of_inputs, int number_of_outputs>
161struct StateFeedbackController {
162 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
163 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
164 const Eigen::Matrix<double, number_of_outputs, number_of_states> K;
Austin Schuhe3490622013-03-13 01:24:30 -0700165 StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
166 number_of_outputs> plant;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700167
168 StateFeedbackController(
169 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
170 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700171 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
172 number_of_outputs> &plant)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700173 : L(L),
174 K(K),
175 plant(plant) {
176 }
177};
178
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800179template <int number_of_states, int number_of_inputs, int number_of_outputs>
180class StateFeedbackLoop {
181 public:
182 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
183
Austin Schuh9644e1c2013-03-12 00:40:36 -0700184 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
185 return controller().plant.A;
186 }
187 double A(int i, int j) const { return A()(i, j); }
188 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
189 return controller().plant.B;
190 }
191 double B(int i, int j) const { return B()(i, j); }
192 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
193 return controller().plant.C;
194 }
195 double C(int i, int j) const { return C()(i, j); }
196 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
197 return controller().plant.D;
198 }
199 double D(int i, int j) const { return D()(i, j); }
200 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K() const {
201 return controller().K;
202 }
203 double K(int i, int j) const { return K()(i, j); }
204 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
205 return controller().L;
206 }
207 double L(int i, int j) const { return L()(i, j); }
208 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
209 return controller().plant.U_min;
210 }
211 double U_min(int i, int j) const { return U_min()(i, j); }
212 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
213 return controller().plant.U_max;
214 }
215 double U_max(int i, int j) const { return U_max()(i, j); }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800216
217 Eigen::Matrix<double, number_of_states, 1> X_hat;
218 Eigen::Matrix<double, number_of_states, 1> R;
219 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -0800220 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800221 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
222 Eigen::Matrix<double, number_of_outputs, 1> Y;
223
Austin Schuh9644e1c2013-03-12 00:40:36 -0700224 ::std::vector<StateFeedbackController<number_of_states, number_of_inputs,
Austin Schuhe3490622013-03-13 01:24:30 -0700225 number_of_outputs> *> controllers_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800226
Austin Schuh9644e1c2013-03-12 00:40:36 -0700227 const StateFeedbackController<
228 number_of_states, number_of_inputs, number_of_outputs>
229 &controller() const {
Austin Schuhe3490622013-03-13 01:24:30 -0700230 return *controllers_[controller_index_];
Austin Schuh9644e1c2013-03-12 00:40:36 -0700231 }
232
233 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();
239 Y.setZero();
240 }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700241
Austin Schuhe3490622013-03-13 01:24:30 -0700242 StateFeedbackLoop(
243 const StateFeedbackController<number_of_states, number_of_inputs,
244 number_of_outputs> &controller)
Austin Schuh9644e1c2013-03-12 00:40:36 -0700245 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700246 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700247 new StateFeedbackController<number_of_states, number_of_inputs,
248 number_of_outputs>(controller));
249 Reset();
250 }
251
252 StateFeedbackLoop(
Austin Schuhe3490622013-03-13 01:24:30 -0700253 const ::std::vector<StateFeedbackController<
254 number_of_states, number_of_inputs,
255 number_of_outputs> *> &controllers)
256 : controllers_(controllers),
Austin Schuh9644e1c2013-03-12 00:40:36 -0700257 controller_index_(0) {
258 Reset();
259 }
260
261 StateFeedbackLoop(
262 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
263 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
Austin Schuhe3490622013-03-13 01:24:30 -0700264 const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
Austin Schuh9644e1c2013-03-12 00:40:36 -0700265 number_of_outputs> &plant)
266 : controller_index_(0) {
Austin Schuhe3490622013-03-13 01:24:30 -0700267 controllers_.push_back(
Austin Schuh9644e1c2013-03-12 00:40:36 -0700268 new StateFeedbackController<number_of_states, number_of_inputs,
269 number_of_outputs>(L, K, plant));
270
271 Reset();
272 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800273 virtual ~StateFeedbackLoop() {}
274
275 virtual void FeedForward() {
276 for (int i = 0; i < number_of_outputs; ++i) {
277 U_ff[i] = 0.0;
278 }
279 }
280
281 // If U is outside the hardware range, limit it before the plant tries to use
282 // it.
283 virtual void CapU() {
284 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700285 if (U(i, 0) > U_max(i, 0)) {
286 U(i, 0) = U_max(i, 0);
287 } else if (U(i, 0) < U_min(i, 0)) {
288 U(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800289 }
290 }
291 }
292
293 // update_observer is whether or not to use the values in Y.
294 // stop_motors is whether or not to output all 0s.
295 void Update(bool update_observer, bool stop_motors) {
296 if (stop_motors) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700297 U.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800298 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700299 U = U_uncapped = K() * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800300 CapU();
301 }
302
303 if (update_observer) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700304 X_hat = (A() - L() * C()) * X_hat + L() * Y + B() * U;
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())) {
316 controller_index_ = static_cast<int>(controllers_.size());
317 } 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:
325 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800326 static const int kNumStates = number_of_states;
327 static const int kNumOutputs = number_of_outputs;
328 static const int kNumInputs = number_of_inputs;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700329
330 int controller_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800331};
332
333#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_