use crate::enums::{AntiWindupMode, DerivativeMode};
use crate::error::PidError;
#[derive(Debug, Clone)]
pub struct ControllerConfigBuilder {
kp: f64,
ki: f64,
kd: f64,
min_output: f64,
max_output: f64,
anti_windup_mode: AntiWindupMode,
setpoint: f64,
deadband: f64,
derivative_mode: DerivativeMode,
derivative_filter_coeff: f64,
}
impl Default for ControllerConfigBuilder {
fn default() -> Self {
ControllerConfigBuilder {
kp: 1.0,
ki: 0.0,
kd: 0.0,
min_output: -f64::INFINITY,
max_output: f64::INFINITY,
anti_windup_mode: AntiWindupMode::Conditional,
setpoint: 0.0,
deadband: 0.0,
derivative_mode: DerivativeMode::OnMeasurement,
derivative_filter_coeff: 10.0,
}
}
}
impl ControllerConfigBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_kp(mut self, kp: f64) -> Self {
self.kp = kp;
self
}
pub fn with_ki(mut self, ki: f64) -> Self {
self.ki = ki;
self
}
pub fn with_kd(mut self, kd: f64) -> Self {
self.kd = kd;
self
}
pub fn with_output_limits(mut self, min: f64, max: f64) -> Self {
self.min_output = min;
self.max_output = max;
self
}
pub fn with_anti_windup(mut self, enable: bool) -> Self {
self.anti_windup_mode = if enable {
AntiWindupMode::Conditional
} else {
AntiWindupMode::None
};
self
}
pub fn with_anti_windup_mode(mut self, mode: AntiWindupMode) -> Self {
self.anti_windup_mode = mode;
self
}
pub fn with_setpoint(mut self, setpoint: f64) -> Self {
self.setpoint = setpoint;
self
}
pub fn with_deadband(mut self, deadband: f64) -> Self {
self.deadband = deadband.abs();
self
}
pub fn with_derivative_mode(mut self, mode: DerivativeMode) -> Self {
self.derivative_mode = mode;
self
}
pub fn with_derivative_filter_coeff(mut self, n: f64) -> Self {
self.derivative_filter_coeff = n;
self
}
pub fn build(self) -> Result<ControllerConfig, PidError> {
if !self.kp.is_finite() {
return Err(PidError::InvalidParameter("kp must be a finite number"));
}
if !self.ki.is_finite() {
return Err(PidError::InvalidParameter("ki must be a finite number"));
}
if !self.kd.is_finite() {
return Err(PidError::InvalidParameter("kd must be a finite number"));
}
if !self.setpoint.is_finite() {
return Err(PidError::InvalidParameter(
"setpoint must be a finite number",
));
}
if !self.deadband.is_finite() || self.deadband < 0.0 {
return Err(PidError::InvalidParameter(
"deadband must be a finite non-negative number",
));
}
if !self.min_output.is_finite() || !self.max_output.is_finite() {
return Err(PidError::InvalidParameter(
"output limits must be finite numbers",
));
}
if self.min_output >= self.max_output {
return Err(PidError::InvalidParameter(
"min_output must be less than max_output",
));
}
if !self.derivative_filter_coeff.is_finite() || self.derivative_filter_coeff <= 0.0 {
return Err(PidError::InvalidParameter(
"derivative_filter_coeff must be a finite positive number",
));
}
if let AntiWindupMode::BackCalculation { tracking_time } = self.anti_windup_mode {
if !tracking_time.is_finite() || tracking_time <= 0.0 {
return Err(PidError::InvalidParameter(
"back-calculation tracking_time must be a finite positive number",
));
}
}
Ok(ControllerConfig {
kp: self.kp,
ki: self.ki,
kd: self.kd,
min_output: self.min_output,
max_output: self.max_output,
anti_windup_mode: self.anti_windup_mode,
setpoint: self.setpoint,
deadband: self.deadband,
derivative_mode: self.derivative_mode,
derivative_filter_coeff: self.derivative_filter_coeff,
})
}
}
#[derive(Debug, Clone)]
pub struct ControllerConfig {
pub(crate) kp: f64,
pub(crate) ki: f64,
pub(crate) kd: f64,
pub(crate) min_output: f64,
pub(crate) max_output: f64,
pub(crate) anti_windup_mode: AntiWindupMode,
pub(crate) setpoint: f64,
pub(crate) deadband: f64,
pub(crate) derivative_mode: DerivativeMode,
pub(crate) derivative_filter_coeff: f64,
}
impl ControllerConfig {
pub fn builder() -> ControllerConfigBuilder {
ControllerConfigBuilder::new()
}
pub fn kp(&self) -> f64 {
self.kp
}
pub fn ki(&self) -> f64 {
self.ki
}
pub fn kd(&self) -> f64 {
self.kd
}
pub fn min_output(&self) -> f64 {
self.min_output
}
pub fn max_output(&self) -> f64 {
self.max_output
}
pub fn anti_windup_mode(&self) -> AntiWindupMode {
self.anti_windup_mode
}
pub fn setpoint(&self) -> f64 {
self.setpoint
}
pub fn deadband(&self) -> f64 {
self.deadband
}
pub fn derivative_mode(&self) -> DerivativeMode {
self.derivative_mode
}
pub fn derivative_filter_coeff(&self) -> f64 {
self.derivative_filter_coeff
}
}