pid #12

Merged
zack merged 6 commits from pid into master 2024-06-07 23:41:54 +00:00
4 changed files with 471 additions and 11 deletions
Showing only changes of commit f1f5947f22 - Show all commits

View File

@ -109,18 +109,18 @@ pub struct Pid<T: Number> {
/// Defines the overall output filter limit. /// Defines the overall output filter limit.
pub output_limit: T, pub output_limit: T,
/// Proportional gain. /// Proportional gain.
pub kp: T, pub p_gain: T,
/// Integral gain. /// Integral gain.
pub ki: T, pub i_gain: T,
/// Derivative gain. /// Derivative gain.
pub kd: T, pub d_gain: T,
/// Limiter for the proportional term: `-p_limit <= P <= p_limit`. /// Limiter for the proportional term: `-p_limit <= P <= p_limit`.
pub p_limit: T, pub p_limit: T,
/// Limiter for the integral term: `-i_limit <= I <= i_limit`. /// Limiter for the integral term: `-i_limit <= I <= i_limit`.
pub i_limit: T, pub i_limit: T,
/// Limiter for the derivative term: `-d_limit <= D <= d_limit`. /// Limiter for the derivative term: `-d_limit <= D <= d_limit`.
pub d_limit: T, pub d_limit: T,
/// Last calculated integral value if [Pid::ki] is used. /// Last calculated integral value if [Pid::i_gain] is used.
integral_term: T, integral_term: T,
/// Previously found measurement whilst using the [Pid::next_control_output] method. /// Previously found measurement whilst using the [Pid::next_control_output] method.
prev_measurement: Option<T>, prev_measurement: Option<T>,
@ -167,13 +167,13 @@ impl<T> Pid<T>
/// - [Self::p()]: Proportional term setting /// - [Self::p()]: Proportional term setting
/// - [Self::i()]: Integral term setting /// - [Self::i()]: Integral term setting
/// - [Self::d()]: Derivative term setting /// - [Self::d()]: Derivative term setting
pub fn new(setpoint: impl Into<T>, output_limit: impl Into<T>) -> Self { pub fn new(setpoint: T, output_limit: T) -> Self {
Self { Self {
setpoint: setpoint.into(), setpoint,
output_limit: output_limit.into(), output_limit,
kp: T::zero(), p_gain: T::zero(),
ki: T::zero(), i_gain: T::zero(),
kd: T::zero(), d_gain: T::zero(),
p_limit: T::zero(), p_limit: T::zero(),
i_limit: T::zero(), i_limit: T::zero(),
d_limit: T::zero(), d_limit: T::zero(),
@ -183,44 +183,40 @@ impl<T> Pid<T>
} }
/// Sets the [Self::p] term for this controller. /// Sets the [Self::p] term for this controller.
pub fn p(&mut self, gain: impl Into<T>, limit: impl Into<T>) -> &mut Self { pub fn p(&mut self, gain: T, limit: T) -> &mut Self {
self.kp = gain.into(); self.p_gain = gain;
self.p_limit = limit.into(); self.p_limit = limit;
self self
} }
/// Sets the [Self::i] term for this controller. /// Sets the [Self::i] term for this controller.
pub fn i(&mut self, gain: impl Into<T>, limit: impl Into<T>) -> &mut Self { pub fn i(&mut self, gain: T, limit: T) -> &mut Self {
self.ki = gain.into(); self.i_gain = gain;
self.i_limit = limit.into(); self.i_limit = limit;
self self
} }
/// Sets the [Self::d] term for this controller. /// Sets the [Self::d] term for this controller.
pub fn d(&mut self, gain: impl Into<T>, limit: impl Into<T>) -> &mut Self { pub fn d(&mut self, gain: T, limit: T) -> &mut Self {
self.kd = gain.into(); self.d_gain = gain;
self.d_limit = limit.into(); self.d_limit = limit;
self self
} }
/// Sets the [Pid::setpoint] to target for this controller. /// Sets the [Pid::setpoint] to target for this controller.
pub fn setpoint(&mut self, setpoint: impl Into<T>) -> &mut Self { pub fn setpoint(&mut self, setpoint: T) -> &mut Self {
self.setpoint = setpoint.into(); self.setpoint = setpoint;
self self
} }
/// Given a new measurement, calculates the next [control output](ControlOutput). /// Given a new measurement, calculates the next [control output](ControlOutput).
///
/// # Panics
///
/// - If a setpoint has not been set via `update_setpoint()`.
pub fn next_control_output(&mut self, measurement: T) -> ControlOutput<T> { pub fn next_control_output(&mut self, measurement: T) -> ControlOutput<T> {
// Calculate the error between the ideal setpoint and the current // Calculate the error between the ideal setpoint and the current
// measurement to compare against // measurement to compare against
let error = self.setpoint - measurement; let error = self.setpoint - measurement;
// Calculate the proportional term and limit to it's individual limit // Calculate the proportional term and limit to it's individual limit
let p_unbounded = error * self.kp; let p_unbounded = error * self.p_gain;
let p = apply_limit(self.p_limit, p_unbounded); let p = apply_limit(self.p_limit, p_unbounded);
// Mitigate output jumps when ki(t) != ki(t-1). // Mitigate output jumps when ki(t) != ki(t-1).
@ -228,7 +224,7 @@ impl<T> Pid<T>
// just the error (no ki), because we support ki changing dynamically, // just the error (no ki), because we support ki changing dynamically,
// we store the entire term so that we don't need to remember previous // we store the entire term so that we don't need to remember previous
// ki values. // ki values.
self.integral_term = self.integral_term + error * self.ki; self.integral_term = self.integral_term + error * self.i_gain;
// Mitigate integral windup: Don't want to keep building up error // Mitigate integral windup: Don't want to keep building up error
// beyond what i_limit will allow. // beyond what i_limit will allow.
@ -239,7 +235,7 @@ impl<T> Pid<T>
let d_unbounded = -match self.prev_measurement.as_ref() { let d_unbounded = -match self.prev_measurement.as_ref() {
Some(prev_measurement) => measurement - *prev_measurement, Some(prev_measurement) => measurement - *prev_measurement,
None => T::zero(), None => T::zero(),
} * self.kd; } * self.d_gain;
self.prev_measurement = Some(measurement); self.prev_measurement = Some(measurement);
let d = apply_limit(self.d_limit, d_unbounded); let d = apply_limit(self.d_limit, d_unbounded);
@ -253,7 +249,7 @@ impl<T> Pid<T>
p, p,
i: self.integral_term, i: self.integral_term,
d, d,
output: output, output,
} }
} }