blob: 8fe18f892c69b46e1fe6257cd85b8adf99ce32c0 [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
4// wikipedia article is <http://en.wikipedia.org/wiki/State_observer>
5
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
59 // If U is outside the hardware range, limit it before the plant tries to use
60 // it.
61 virtual void CapU() {
62 for (int i = 0; i < kNumOutputs; ++i) {
63 if (U[i] > U_max[i]) {
64 U[i] = U_max[i];
65 } else if (U[i] < U_min[i]) {
66 U[i] = U_min[i];
67 }
68 }
69 }
70 // Computes the new X and Y given the control input.
71 void Update() {
72 CapU();
73 X = A * X + B * U;
74 Y = C * X + D * U;
75 }
76
77 protected:
78 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -080079 static const int kNumStates = number_of_states;
80 static const int kNumOutputs = number_of_outputs;
81 static const int kNumInputs = number_of_inputs;
Austin Schuhdc1c84a2013-02-23 16:33:10 -080082};
83
84template <int number_of_states, int number_of_inputs, int number_of_outputs>
85class StateFeedbackLoop {
86 public:
87 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
88
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
92 Eigen::Matrix<double, number_of_states, 1> X_hat;
93 Eigen::Matrix<double, number_of_states, 1> R;
94 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -080095 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -080096 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
97 Eigen::Matrix<double, number_of_outputs, 1> Y;
98
99 StateFeedbackPlant<number_of_states, number_of_inputs,
100 number_of_outputs> plant;
101
102 StateFeedbackLoop(
103 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
104 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
105 const StateFeedbackPlant<number_of_states, number_of_inputs,
106 number_of_outputs> &plant)
107 : L(L),
108 K(K),
109 plant(plant) {
110 X_hat.setZero();
111 R.setZero();
112 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800113 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800114 U_ff.setZero();
115 Y.setZero();
116 }
117 virtual ~StateFeedbackLoop() {}
118
119 virtual void FeedForward() {
120 for (int i = 0; i < number_of_outputs; ++i) {
121 U_ff[i] = 0.0;
122 }
123 }
124
125 // If U is outside the hardware range, limit it before the plant tries to use
126 // it.
127 virtual void CapU() {
128 for (int i = 0; i < kNumOutputs; ++i) {
129 if (U[i] > plant.U_max[i]) {
130 U[i] = plant.U_max[i];
131 } else if (U[i] < plant.U_min[i]) {
132 U[i] = plant.U_min[i];
133 }
134 }
135 }
136
137 // update_observer is whether or not to use the values in Y.
138 // stop_motors is whether or not to output all 0s.
139 void Update(bool update_observer, bool stop_motors) {
140 if (stop_motors) {
141 for (int i = 0; i < number_of_outputs; ++i) {
142 U[i] = 0.0;
143 }
144 } else {
Austin Schuh06ee48e2013-03-02 01:47:54 -0800145 U = U_uncapped = K * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800146 CapU();
147 }
148
149 if (update_observer) {
150 X_hat = (plant.A - L * plant.C) * X_hat + L * Y + plant.B * U;
151 } else {
152 X_hat = plant.A * X_hat + plant.B * U;
153 }
154 }
155
156 protected:
157 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800158 static const int kNumStates = number_of_states;
159 static const int kNumOutputs = number_of_outputs;
160 static const int kNumInputs = number_of_inputs;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800161};
162
163#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_