blob: f95579675a5089cbd159909ad52221a8ca3f142d [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>
12class StateFeedbackPlant {
13 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
23 Eigen::Matrix<double, number_of_states, 1> X;
24 Eigen::Matrix<double, number_of_outputs, 1> Y;
25 Eigen::Matrix<double, number_of_inputs, 1> U;
26
27 StateFeedbackPlant(const StateFeedbackPlant &other)
28 : A(other.A),
29 B(other.B),
30 C(other.C),
31 D(other.D),
32 U_min(other.U_min),
33 U_max(other.U_max) {
34 X.setZero();
35 Y.setZero();
36 U.setZero();
37 }
38
39 StateFeedbackPlant(
40 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
41 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
42 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
43 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
44 const Eigen::Matrix<double, number_of_outputs, 1> &U_max,
45 const Eigen::Matrix<double, number_of_outputs, 1> &U_min)
46 : A(A),
47 B(B),
48 C(C),
49 D(D),
50 U_min(U_min),
51 U_max(U_max) {
52 X.setZero();
53 Y.setZero();
54 U.setZero();
55 }
56
57 virtual ~StateFeedbackPlant() {}
58
Austin Schuh849f0032013-03-03 23:59:53 -080059 // Assert that U is within the hardware range.
60 virtual void CheckU() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -080061 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh849f0032013-03-03 23:59:53 -080062 assert(U[i] <= U_max[i]);
63 assert(U[i] >= U_min[i]);
Austin Schuhdc1c84a2013-02-23 16:33:10 -080064 }
65 }
Austin Schuh849f0032013-03-03 23:59:53 -080066
Austin Schuhdc1c84a2013-02-23 16:33:10 -080067 // Computes the new X and Y given the control input.
68 void Update() {
Austin Schuh849f0032013-03-03 23:59:53 -080069 // Powers outside of the range are more likely controller bugs than things
70 // that the plant should deal with.
71 CheckU();
Austin Schuhdc1c84a2013-02-23 16:33:10 -080072 X = A * X + B * U;
73 Y = C * X + D * U;
74 }
75
76 protected:
77 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -080078 static const int kNumStates = number_of_states;
79 static const int kNumOutputs = number_of_outputs;
80 static const int kNumInputs = number_of_inputs;
Austin Schuhdc1c84a2013-02-23 16:33:10 -080081};
82
Austin Schuh9644e1c2013-03-12 00:40:36 -070083// A Controller is a structure which holds a plant and the K and L matrices.
84// This is designed such that multiple controllers can share one set of state to
85// support gain scheduling easily.
86template <int number_of_states, int number_of_inputs, int number_of_outputs>
87struct StateFeedbackController {
88 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
89 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
90 const Eigen::Matrix<double, number_of_outputs, number_of_states> K;
91 StateFeedbackPlant<number_of_states, number_of_inputs,
92 number_of_outputs> plant;
93
94 StateFeedbackController(
95 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
96 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
97 const StateFeedbackPlant<number_of_states, number_of_inputs,
98 number_of_outputs> &plant)
99 : L(L),
100 K(K),
101 plant(plant) {
102 }
103};
104
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800105template <int number_of_states, int number_of_inputs, int number_of_outputs>
106class StateFeedbackLoop {
107 public:
108 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
109
Austin Schuh9644e1c2013-03-12 00:40:36 -0700110 const Eigen::Matrix<double, number_of_states, number_of_states> &A() const {
111 return controller().plant.A;
112 }
113 double A(int i, int j) const { return A()(i, j); }
114 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B() const {
115 return controller().plant.B;
116 }
117 double B(int i, int j) const { return B()(i, j); }
118 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C() const {
119 return controller().plant.C;
120 }
121 double C(int i, int j) const { return C()(i, j); }
122 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D() const {
123 return controller().plant.D;
124 }
125 double D(int i, int j) const { return D()(i, j); }
126 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K() const {
127 return controller().K;
128 }
129 double K(int i, int j) const { return K()(i, j); }
130 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L() const {
131 return controller().L;
132 }
133 double L(int i, int j) const { return L()(i, j); }
134 const Eigen::Matrix<double, number_of_inputs, 1> &U_min() const {
135 return controller().plant.U_min;
136 }
137 double U_min(int i, int j) const { return U_min()(i, j); }
138 const Eigen::Matrix<double, number_of_inputs, 1> &U_max() const {
139 return controller().plant.U_max;
140 }
141 double U_max(int i, int j) const { return U_max()(i, j); }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800142
143 Eigen::Matrix<double, number_of_states, 1> X_hat;
144 Eigen::Matrix<double, number_of_states, 1> R;
145 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -0800146 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800147 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
148 Eigen::Matrix<double, number_of_outputs, 1> Y;
149
Austin Schuh9644e1c2013-03-12 00:40:36 -0700150 ::std::vector<StateFeedbackController<number_of_states, number_of_inputs,
151 number_of_outputs> *> controllers;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800152
Austin Schuh9644e1c2013-03-12 00:40:36 -0700153 const StateFeedbackController<
154 number_of_states, number_of_inputs, number_of_outputs>
155 &controller() const {
156 return *controllers[controller_index_];
157 }
158
159 void Reset() {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800160 X_hat.setZero();
161 R.setZero();
162 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800163 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800164 U_ff.setZero();
165 Y.setZero();
166 }
Austin Schuh9644e1c2013-03-12 00:40:36 -0700167
168 StateFeedbackLoop(const StateFeedbackPlant<number_of_states, number_of_inputs,
169 number_of_outputs> &controller)
170 : controller_index_(0) {
171 controllers.push_back(
172 new StateFeedbackController<number_of_states, number_of_inputs,
173 number_of_outputs>(controller));
174 Reset();
175 }
176
177 StateFeedbackLoop(
178 const ::std::vector<StateFeedbackPlant<number_of_states, number_of_inputs,
179 number_of_outputs> *> &controllers)
180 : controllers(controllers),
181 controller_index_(0) {
182 Reset();
183 }
184
185 StateFeedbackLoop(
186 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
187 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
188 const StateFeedbackPlant<number_of_states, number_of_inputs,
189 number_of_outputs> &plant)
190 : controller_index_(0) {
191 controllers.push_back(
192 new StateFeedbackController<number_of_states, number_of_inputs,
193 number_of_outputs>(L, K, plant));
194
195 Reset();
196 }
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800197 virtual ~StateFeedbackLoop() {}
198
199 virtual void FeedForward() {
200 for (int i = 0; i < number_of_outputs; ++i) {
201 U_ff[i] = 0.0;
202 }
203 }
204
205 // If U is outside the hardware range, limit it before the plant tries to use
206 // it.
207 virtual void CapU() {
208 for (int i = 0; i < kNumOutputs; ++i) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700209 if (U(i, 0) > U_max(i, 0)) {
210 U(i, 0) = U_max(i, 0);
211 } else if (U(i, 0) < U_min(i, 0)) {
212 U(i, 0) = U_min(i, 0);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800213 }
214 }
215 }
216
217 // update_observer is whether or not to use the values in Y.
218 // stop_motors is whether or not to output all 0s.
219 void Update(bool update_observer, bool stop_motors) {
220 if (stop_motors) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700221 U.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800222 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700223 U = U_uncapped = K() * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800224 CapU();
225 }
226
227 if (update_observer) {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700228 X_hat = (A() - L() * C()) * X_hat + L() * Y + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800229 } else {
Austin Schuh9644e1c2013-03-12 00:40:36 -0700230 X_hat = A() * X_hat + B() * U;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800231 }
232 }
233
Austin Schuh9644e1c2013-03-12 00:40:36 -0700234 // Sets the current controller to be index and verifies that it isn't out of
235 // range.
236 void set_controller_index(int index) {
237 if (index >= 0 && index < controllers.size()) {
238 controller_index_ = index;
239 }
240 }
241
242 void controller_index() const { return controller_index_; }
243
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800244 protected:
245 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800246 static const int kNumStates = number_of_states;
247 static const int kNumOutputs = number_of_outputs;
248 static const int kNumInputs = number_of_inputs;
Austin Schuh9644e1c2013-03-12 00:40:36 -0700249
250 int controller_index_;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800251};
252
253#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_