blob: c49ca442c70f7adc2dca1461412d55028aa370df [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
6#include "Eigen/Dense"
7
8template <int number_of_states, int number_of_inputs, int number_of_outputs>
9class StateFeedbackPlant {
10 public:
11 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
12
13 const Eigen::Matrix<double, number_of_states, number_of_states> A;
14 const Eigen::Matrix<double, number_of_states, number_of_inputs> B;
15 const Eigen::Matrix<double, number_of_outputs, number_of_states> C;
16 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> D;
17 const Eigen::Matrix<double, number_of_inputs, 1> U_min;
18 const Eigen::Matrix<double, number_of_inputs, 1> U_max;
19
20 Eigen::Matrix<double, number_of_states, 1> X;
21 Eigen::Matrix<double, number_of_outputs, 1> Y;
22 Eigen::Matrix<double, number_of_inputs, 1> U;
23
24 StateFeedbackPlant(const StateFeedbackPlant &other)
25 : A(other.A),
26 B(other.B),
27 C(other.C),
28 D(other.D),
29 U_min(other.U_min),
30 U_max(other.U_max) {
31 X.setZero();
32 Y.setZero();
33 U.setZero();
34 }
35
36 StateFeedbackPlant(
37 const Eigen::Matrix<double, number_of_states, number_of_states> &A,
38 const Eigen::Matrix<double, number_of_states, number_of_inputs> &B,
39 const Eigen::Matrix<double, number_of_outputs, number_of_states> &C,
40 const Eigen::Matrix<double, number_of_outputs, number_of_inputs> &D,
41 const Eigen::Matrix<double, number_of_outputs, 1> &U_max,
42 const Eigen::Matrix<double, number_of_outputs, 1> &U_min)
43 : A(A),
44 B(B),
45 C(C),
46 D(D),
47 U_min(U_min),
48 U_max(U_max) {
49 X.setZero();
50 Y.setZero();
51 U.setZero();
52 }
53
54 virtual ~StateFeedbackPlant() {}
55
56 // If U is outside the hardware range, limit it before the plant tries to use
57 // it.
58 virtual void CapU() {
59 for (int i = 0; i < kNumOutputs; ++i) {
60 if (U[i] > U_max[i]) {
61 U[i] = U_max[i];
62 } else if (U[i] < U_min[i]) {
63 U[i] = U_min[i];
64 }
65 }
66 }
67 // Computes the new X and Y given the control input.
68 void Update() {
69 CapU();
70 X = A * X + B * U;
71 Y = C * X + D * U;
72 }
73
74 protected:
75 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -080076 static const int kNumStates = number_of_states;
77 static const int kNumOutputs = number_of_outputs;
78 static const int kNumInputs = number_of_inputs;
Austin Schuhdc1c84a2013-02-23 16:33:10 -080079};
80
81template <int number_of_states, int number_of_inputs, int number_of_outputs>
82class StateFeedbackLoop {
83 public:
84 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
85
86 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
87 const Eigen::Matrix<double, number_of_outputs, number_of_states> K;
88
89 Eigen::Matrix<double, number_of_states, 1> X_hat;
90 Eigen::Matrix<double, number_of_states, 1> R;
91 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -080092 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -080093 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
94 Eigen::Matrix<double, number_of_outputs, 1> Y;
95
96 StateFeedbackPlant<number_of_states, number_of_inputs,
97 number_of_outputs> plant;
98
99 StateFeedbackLoop(
100 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
101 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
102 const StateFeedbackPlant<number_of_states, number_of_inputs,
103 number_of_outputs> &plant)
104 : L(L),
105 K(K),
106 plant(plant) {
107 X_hat.setZero();
108 R.setZero();
109 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800110 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800111 U_ff.setZero();
112 Y.setZero();
113 }
114 virtual ~StateFeedbackLoop() {}
115
116 virtual void FeedForward() {
117 for (int i = 0; i < number_of_outputs; ++i) {
118 U_ff[i] = 0.0;
119 }
120 }
121
122 // If U is outside the hardware range, limit it before the plant tries to use
123 // it.
124 virtual void CapU() {
125 for (int i = 0; i < kNumOutputs; ++i) {
126 if (U[i] > plant.U_max[i]) {
127 U[i] = plant.U_max[i];
128 } else if (U[i] < plant.U_min[i]) {
129 U[i] = plant.U_min[i];
130 }
131 }
132 }
133
134 // update_observer is whether or not to use the values in Y.
135 // stop_motors is whether or not to output all 0s.
136 void Update(bool update_observer, bool stop_motors) {
137 if (stop_motors) {
138 for (int i = 0; i < number_of_outputs; ++i) {
139 U[i] = 0.0;
140 }
141 } else {
Austin Schuh06ee48e2013-03-02 01:47:54 -0800142 U = U_uncapped = K * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800143 CapU();
144 }
145
146 if (update_observer) {
147 X_hat = (plant.A - L * plant.C) * X_hat + L * Y + plant.B * U;
148 } else {
149 X_hat = plant.A * X_hat + plant.B * U;
150 }
151 }
152
153 protected:
154 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800155 static const int kNumStates = number_of_states;
156 static const int kNumOutputs = number_of_outputs;
157 static const int kNumInputs = number_of_inputs;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800158};
159
160#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_