#![allow(dead_code)]
use crate::QAngle;
use std::time::Instant;
pub struct Pid {
kp: f64,
ki: f64,
kd: f64,
integral: f64,
previous_error: f64,
time: Instant,
last_time: f64,
min: f64,
max: f64,
imin: f64,
imax: f64,
}
impl Pid {
#[inline]
pub fn new() -> Pid {
Pid {
kp: 0.,
ki: 0.,
kd: 0.,
integral: 0.0,
previous_error: 0.0,
time: Instant::now(),
last_time: 0.,
min: f64::NEG_INFINITY,
max: f64::INFINITY,
imin: f64::NEG_INFINITY,
imax: f64::INFINITY,
}
}
pub fn values(&self) -> (f64, f64, f64) {
(self.kp, self.ki, self.kd)
}
pub fn calculate(&mut self, setpoint: f64, actual: f64) -> f64 {
let error = setpoint - actual;
let t = self.time.elapsed().as_secs_f64();
let mut dt = t - self.last_time;
if dt <= 0.0 {
dt = 0.001; }
let de = error - self.previous_error;
self.integral = (self.integral + error * dt).clamp(self.imin, self.imax);
let derivative = if dt > 0. { de / dt } else { 0. };
self.previous_error = error;
self.last_time = t;
((self.kp * error) + (self.ki * self.integral) + (derivative * self.kd))
.clamp(self.min, self.max)
}
pub fn reset(&mut self) {
self.integral = 0.0;
self.previous_error = 0.0;
self.time = Instant::now();
self.last_time = 0.0;
}
pub fn set_gains(self, kp: f64, ki: f64, kd: f64) -> Self {
Self {
kp,
ki,
kd,
integral: self.integral,
previous_error: self.previous_error,
time: self.time,
last_time: self.last_time,
min: self.min,
max: self.max,
imin: self.imin,
imax: self.imax,
}
}
pub fn with_output_limits(mut self, min: f64, max: f64) -> Self {
self.min = min;
self.max = max;
self
}
pub fn with_integral_limits(mut self, min: f64, max: f64) -> Self {
self.imin = min;
self.imax = max;
self
}
}
pub struct AngularPid {
kp: f64,
ki: f64,
kd: f64,
integral: QAngle,
previous_error: QAngle,
time: Instant,
last_time: f64,
min: QAngle,
max: QAngle,
imin: QAngle,
imax: QAngle,
}
impl AngularPid {
#[inline]
pub fn new() -> AngularPid {
AngularPid {
kp: 0.,
ki: 0.,
kd: 0.,
integral: 0.0.into(),
previous_error: 0.0.into(),
time: Instant::now(),
last_time: 0.,
min: QAngle::from_radians(f64::NEG_INFINITY),
max: QAngle::from_radians(f64::INFINITY),
imin: QAngle::from_radians(f64::NEG_INFINITY),
imax: QAngle::from_radians(f64::INFINITY),
}
}
pub fn values(&self) -> (f64, f64, f64) {
(self.kp, self.ki, self.kd)
}
pub fn calculate(&mut self, setpoint: QAngle, actual: QAngle) -> QAngle {
let error = (setpoint - actual).remainder(QAngle::TAU);
let t = self.time.elapsed().as_secs_f64();
let mut dt = t - self.last_time;
if dt <= 0.0 {
dt = 0.001; }
let de = error - self.previous_error;
self.integral = (self.integral + error * dt).clamp(self.imin, self.imax);
let derivative = if dt > 0. { de / dt } else { 0.0.into() };
self.previous_error = error;
self.last_time = t;
((self.kp * error) + (self.ki * self.integral) + (derivative * self.kd))
.clamp(self.min, self.max)
}
pub fn reset(&mut self) {
self.integral = 0.0.into();
self.previous_error = 0.0.into();
self.time = Instant::now();
self.last_time = 0.0;
}
pub fn set_gains(self, kp: f64, ki: f64, kd: f64) -> Self {
Self {
kp,
ki,
kd,
integral: self.integral,
previous_error: self.previous_error,
time: self.time,
last_time: self.last_time,
min: self.min,
max: self.max,
imin: self.imin,
imax: self.imax,
}
}
pub fn with_output_limits(mut self, min: QAngle, max: QAngle) -> Self {
self.min = min;
self.max = max;
self
}
pub fn with_integral_limits(mut self, min: QAngle, max: QAngle) -> Self {
self.imin = min;
self.imax = max;
self
}
}