#![no_std] #![forbid(unsafe_code)]
#[cfg(feature = "f32")]
pub type Float = f32;
#[cfg(not(feature = "f32"))]
pub type Float = f64;
pub struct PidController {
pub kp: Float,
pub ki: Float,
pub kd: Float,
first_run: bool, setpoint: Float,
integral: Float,
last_measurement: Float,
output_min: Float,
output_max: Float,
}
impl PidController {
pub fn new(kp: Float, ki: Float, kd: Float, setpoint: Float, min: Float, max: Float) -> Self {
Self {
kp,
ki,
kd,
setpoint,
integral: 0.0,
last_measurement: 0.0,
output_min: min,
output_max: max,
first_run: true, }
}
pub fn update(&mut self, measurement: Float, dt: Float) -> Float {
if dt <= 0.0 {
return 0.0;
}
if self.first_run {
self.last_measurement = measurement;
self.first_run = false;
}
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: Float) {
self.setpoint = setpoint;
}
pub fn get_target(&self) -> Float {
self.setpoint
}
pub fn set_kp(&mut self, kp: Float) {
self.kp = kp;
}
pub fn set_ki(&mut self, ki: Float) {
self.ki = ki;
}
pub fn set_kd(&mut self, kd: Float) {
self.kd = kd;
}
}
#[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);
}
#[test]
fn test_dynamic_tuning() {
let mut pid = PidController::new(1.0, 0.0, 0.0, 100.0, -100.0, 100.0);
let out1 = pid.update(50.0, 0.1); assert_eq!(out1, 50.0);
pid.set_kp(2.0); let out2 = pid.update(50.0, 0.1); assert_eq!(out2, 100.0);
}
}