use crate::fb::StateMachine;
use super::axis_view::AxisHandle;
#[derive(Debug, Clone)]
pub struct PressureControlConfig {
pub kp: f64,
pub ki: f64,
pub kd: f64,
pub feed_forward: f64,
pub max_step: f64,
pub max_integral: f64,
pub filter_alpha: f64,
pub invert_direction: bool,
pub tolerance: f64,
pub settling_time: f64,
}
impl Default for PressureControlConfig {
fn default() -> Self {
Self {
kp: 0.0,
ki: 0.0,
kd: 0.0,
feed_forward: 0.0,
max_step: 0.005, max_integral: 100.0,
filter_alpha: 0.5,
invert_direction: false,
tolerance: 1.0,
settling_time: 0.1,
}
}
}
#[derive(Debug, Clone)]
pub struct PressureControl {
pub active: bool,
pub in_tolerance: bool,
pub error: bool,
pub state: StateMachine,
integral: f64,
prev_error: f64,
filtered_load: f64,
commanded_position: f64,
settling_timer: f64,
is_first_run: bool,
}
impl Default for PressureControl {
fn default() -> Self {
Self {
active: false,
in_tolerance: false,
error: false,
state: StateMachine::new(),
integral: 0.0,
prev_error: 0.0,
filtered_load: 0.0,
commanded_position: 0.0,
settling_timer: 0.0,
is_first_run: true,
}
}
}
impl PressureControl {
pub fn new() -> Self {
Self::default()
}
pub fn call(
&mut self,
axis: &mut impl AxisHandle,
execute: bool,
target_load: f64,
current_load: f64,
config: &PressureControlConfig,
dt: f64,
) {
if !execute {
if self.active {
axis.halt();
self.active = false;
self.in_tolerance = false;
self.state.index = 0; }
self.is_first_run = true;
self.integral = 0.0;
self.prev_error = 0.0;
self.settling_timer = 0.0;
self.error = false;
return;
}
if axis.is_error() {
self.error = true;
self.active = false;
self.in_tolerance = false;
self.state.set_error(100, "Axis is in error state");
return;
}
if self.is_first_run {
self.filtered_load = current_load; self.commanded_position = axis.position(); self.is_first_run = false;
self.active = true;
self.error = false;
self.state.index = 10; }
let alpha = config.filter_alpha.clamp(0.0, 1.0);
self.filtered_load = (alpha * current_load) + ((1.0 - alpha) * self.filtered_load);
let error = target_load - self.filtered_load;
self.integral += error * dt;
self.integral = self.integral.clamp(-config.max_integral, config.max_integral);
let derivative = if dt > 0.0 { (error - self.prev_error) / dt } else { 0.0 };
self.prev_error = error;
let mut output = (config.kp * error) + (config.ki * self.integral) + (config.kd * derivative) + config.feed_forward;
if config.invert_direction {
output = -output;
}
let step = output.clamp(-config.max_step, config.max_step);
self.commanded_position += step;
let vel = axis.config().jog_speed;
let acc = axis.config().jog_accel;
let dec = axis.config().jog_decel;
if step.abs() > f64::EPSILON {
axis.move_absolute(self.commanded_position, vel, acc, dec);
}
if error.abs() <= config.tolerance {
self.settling_timer += dt;
if self.settling_timer >= config.settling_time {
self.in_tolerance = true;
}
} else {
self.settling_timer = 0.0;
self.in_tolerance = false;
}
}
}