Add saturation for current loops
Signed-off-by: Ravago Jones <ravagojones@gmail.com>
Change-Id: If80e6b964453f748ab8846c9c5f46bc94c2058ac
diff --git a/frc971/control_loops/state_feedback_loop.h b/frc971/control_loops/state_feedback_loop.h
index 65e0ba1..295beca 100644
--- a/frc971/control_loops/state_feedback_loop.h
+++ b/frc971/control_loops/state_feedback_loop.h
@@ -42,6 +42,8 @@
D(other.D),
U_min(other.U_min),
U_max(other.U_max),
+ U_limit_coefficient(other.U_limit_coefficient),
+ U_limit_constant(other.U_limit_constant),
dt(other.dt),
delayed_u(other.delayed_u) {}
@@ -52,6 +54,9 @@
const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> &D,
const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_max,
const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_min,
+ const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
+ &U_limit_coefficient,
+ const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant,
const std::chrono::nanoseconds dt, size_t delayed_u)
: A(A),
B(B),
@@ -59,6 +64,8 @@
D(D),
U_min(U_min),
U_max(U_max),
+ U_limit_coefficient(U_limit_coefficient),
+ U_limit_constant(U_limit_constant),
dt(dt),
delayed_u(delayed_u) {}
@@ -68,6 +75,9 @@
const Eigen::Matrix<Scalar, number_of_outputs, number_of_inputs> D;
const Eigen::Matrix<Scalar, number_of_inputs, 1> U_min;
const Eigen::Matrix<Scalar, number_of_inputs, 1> U_max;
+ const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
+ U_limit_coefficient;
+ const Eigen::Matrix<Scalar, number_of_inputs, 1> U_limit_constant;
const std::chrono::nanoseconds dt;
// If true, this adds a single cycle output delay model to the plant. This is
@@ -134,6 +144,19 @@
return coefficients().U_max;
}
Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
+ const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
+ &U_limit_coefficient() const {
+ return coefficients().U_limit_coefficient;
+ }
+ Scalar U_limit_coefficient(int i, int j) const {
+ return U_limit_coefficient()(i, j);
+ }
+ const Eigen::Matrix<Scalar, number_of_inputs, 1> &U_limit_constant() const {
+ return coefficients().U_limit_constant;
+ }
+ Scalar U_limit_constant(int i, int j = 0) const {
+ return U_limit_constant()(i, j);
+ }
const std::chrono::nanoseconds dt() const { return coefficients().dt; }
@@ -549,11 +572,24 @@
// If U is outside the hardware range, limit it before the plant tries to use
// it.
virtual void CapU() {
+ // TODO(Ravago): this runs before the state update step, so it's limiting
+ // the future control based on the old state. This gets even worse when we
+ // have delayed_u.
+ Eigen::Matrix<Scalar, number_of_inputs, 1> U_max_computed =
+ plant().U_limit_coefficient() * plant().X() +
+ plant().U_limit_constant();
+ Eigen::Matrix<Scalar, number_of_inputs, 1> U_min_computed =
+ plant().U_limit_coefficient() * plant().X() -
+ plant().U_limit_constant();
+
+ U_max_computed = U_max_computed.cwiseMin(plant().U_max());
+ U_min_computed = U_min_computed.cwiseMax(plant().U_min());
+
for (int i = 0; i < kNumInputs; ++i) {
- if (U(i, 0) > plant().U_max(i, 0)) {
- U_(i, 0) = plant().U_max(i, 0);
- } else if (U(i, 0) < plant().U_min(i, 0)) {
- U_(i, 0) = plant().U_min(i, 0);
+ if (U(i, 0) > U_max_computed(i, 0)) {
+ U_(i, 0) = U_max_computed(i, 0);
+ } else if (U(i, 0) < U_min_computed(i, 0)) {
+ U_(i, 0) = U_min_computed(i, 0);
}
}
}