blob: 894487b7bf971283f67af05f6d957059f49b35a7 [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
83template <int number_of_states, int number_of_inputs, int number_of_outputs>
84class StateFeedbackLoop {
85 public:
86 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
87
88 const Eigen::Matrix<double, number_of_states, number_of_outputs> L;
89 const Eigen::Matrix<double, number_of_outputs, number_of_states> K;
90
91 Eigen::Matrix<double, number_of_states, 1> X_hat;
92 Eigen::Matrix<double, number_of_states, 1> R;
93 Eigen::Matrix<double, number_of_inputs, 1> U;
Austin Schuh06ee48e2013-03-02 01:47:54 -080094 Eigen::Matrix<double, number_of_inputs, 1> U_uncapped;
Austin Schuhdc1c84a2013-02-23 16:33:10 -080095 Eigen::Matrix<double, number_of_outputs, 1> U_ff;
96 Eigen::Matrix<double, number_of_outputs, 1> Y;
97
98 StateFeedbackPlant<number_of_states, number_of_inputs,
99 number_of_outputs> plant;
100
101 StateFeedbackLoop(
102 const Eigen::Matrix<double, number_of_states, number_of_outputs> &L,
103 const Eigen::Matrix<double, number_of_outputs, number_of_states> &K,
104 const StateFeedbackPlant<number_of_states, number_of_inputs,
105 number_of_outputs> &plant)
106 : L(L),
107 K(K),
108 plant(plant) {
109 X_hat.setZero();
110 R.setZero();
111 U.setZero();
Austin Schuh06ee48e2013-03-02 01:47:54 -0800112 U_uncapped.setZero();
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800113 U_ff.setZero();
114 Y.setZero();
115 }
116 virtual ~StateFeedbackLoop() {}
117
118 virtual void FeedForward() {
119 for (int i = 0; i < number_of_outputs; ++i) {
120 U_ff[i] = 0.0;
121 }
122 }
123
124 // If U is outside the hardware range, limit it before the plant tries to use
125 // it.
126 virtual void CapU() {
127 for (int i = 0; i < kNumOutputs; ++i) {
128 if (U[i] > plant.U_max[i]) {
129 U[i] = plant.U_max[i];
130 } else if (U[i] < plant.U_min[i]) {
131 U[i] = plant.U_min[i];
132 }
133 }
134 }
135
136 // update_observer is whether or not to use the values in Y.
137 // stop_motors is whether or not to output all 0s.
138 void Update(bool update_observer, bool stop_motors) {
139 if (stop_motors) {
140 for (int i = 0; i < number_of_outputs; ++i) {
141 U[i] = 0.0;
142 }
143 } else {
Austin Schuh06ee48e2013-03-02 01:47:54 -0800144 U = U_uncapped = K * (R - X_hat);
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800145 CapU();
146 }
147
148 if (update_observer) {
149 X_hat = (plant.A - L * plant.C) * X_hat + L * Y + plant.B * U;
150 } else {
151 X_hat = plant.A * X_hat + plant.B * U;
152 }
153 }
154
155 protected:
156 // these are accessible from non-templated subclasses
Austin Schuhb1cdb382013-03-01 22:53:52 -0800157 static const int kNumStates = number_of_states;
158 static const int kNumOutputs = number_of_outputs;
159 static const int kNumInputs = number_of_inputs;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800160};
161
162#endif // FRC971_CONTROL_LOOPS_STATEFEEDBACKLOOP_H_