extern crate core;
pub mod util;
use std::f64;
pub trait Controller {
fn update(&mut self, value: f64, delta_t: f64) -> f64;
fn set_target(&mut self, target: f64);
fn target(&self) -> f64;
fn reset(&mut self);
}
#[derive(Debug, Clone, Copy)]
pub enum DerivativeMode {
OnError,
OnMeasurement,
}
#[derive(Debug, Clone)]
pub struct PIDController {
pub p_gain: f64,
pub i_gain: f64,
pub d_gain: f64,
target: f64,
pub i_min: f64,
pub i_max: f64,
pub out_min: f64,
pub out_max: f64,
pub d_mode: DerivativeMode,
err_sum: f64,
prev_value: f64,
prev_error: f64,
}
impl PIDController {
pub fn new(p_gain: f64, i_gain: f64, d_gain: f64) -> PIDController {
PIDController{
p_gain: p_gain,
i_gain: i_gain,
d_gain: d_gain,
target: 0.0,
err_sum: 0.0,
prev_value: f64::NAN,
prev_error: f64::NAN,
i_min: -f64::INFINITY,
i_max: f64::INFINITY,
out_min: -f64::INFINITY,
out_max: f64::INFINITY,
d_mode: DerivativeMode::OnMeasurement,
}
}
pub fn set_limits(&mut self, min: f64, max: f64) {
self.i_min = min;
self.i_max = max;
self.out_min = min;
self.out_max = max;
}
}
impl Controller for PIDController {
fn set_target(&mut self, target: f64) {
self.target = target;
}
fn target(&self) -> f64 {
self.target
}
fn update(&mut self, value: f64, delta_t: f64) -> f64 {
let error = self.target - value;
let p_term = self.p_gain * error;
self.err_sum = util::limit_range(
self.i_min, self.i_max,
self.err_sum + self.i_gain * error * delta_t
);
let i_term = self.err_sum;
let d_term = if self.prev_value.is_nan() || self.prev_error.is_nan() {
0.0
} else {
match self.d_mode {
DerivativeMode::OnMeasurement => {
self.d_gain * (self.prev_value - value) / delta_t
},
DerivativeMode::OnError => {
self.d_gain * (error - self.prev_error) / delta_t
}
}
};
self.prev_value = value;
self.prev_error = error;
util::limit_range(
self.out_min, self.out_max,
p_term + d_term + i_term
)
}
fn reset(&mut self) {
self.prev_value = f64::NAN;
self.prev_error = f64::NAN;
self.err_sum = 0.0;
}
}