#![no_std]
pub struct PidController {
pub kp: f64,
pub ki: f64,
pub kd: f64,
setpoint: f64,
integral: f64,
last_measurement: f64,
output_min: f64,
output_max: f64,
}
impl PidController {
pub fn new(kp: f64, ki: f64, kd: f64, setpoint: f64, min: f64, max: f64) -> Self {
Self {
kp,
ki,
kd,
setpoint,
integral: 0.0,
last_measurement: 0.0,
output_min: min,
output_max: max,
}
}
pub fn update(&mut self, measurement: f64, dt: f64) -> f64 {
if dt <= 0.0 {
return 0.0;
}
let error = self.setpoint - measurement;
let p = self.kp * error;
self.integral += self.ki * error * dt;
self.integral = self.integral.clamp(self.output_min, self.output_max);
let d = -self.kd * (measurement - self.last_measurement) / dt;
self.last_measurement = measurement;
(p + self.integral + d).clamp(self.output_min, self.output_max)
}
pub fn set_target(&mut self, setpoint: f64) {
self.setpoint = setpoint;
}
pub fn get_target(&self) -> f64 {
self.setpoint
}
}
#[cfg(test)]
mod tests {
extern crate std;
use std::println;
use super::*;
#[test]
fn test_pid_stability() {
let mut pid = PidController::new(2.0, 0.5, 0.1, 50.0, 0.0, 100.0);
let mut system_value = 0.0;
let dt = 0.1;
for _ in 0..100 {
let power = pid.update(system_value, dt);
system_value += (power * 0.1) - (system_value * 0.05);
}
println!("Final system value: {}", system_value);
assert!((50.0 - system_value).abs() < 2.0);
}
#[test]
fn test_zero_dt_safety() {
let mut pid = PidController::new(1.0, 1.0, 1.0, 100.0, -100.0, 100.0);
let output = pid.update(50.0, 0.0);
assert_eq!(output, 0.0);
}
}