use libm::F32Ext; use board; use pid; const FBI_PID_PARAMETERS: pid::Parameters = pid::Parameters { kp: 200.0, ki: 20.0, kd: 10.0, output_min: 0.5, output_max: 10.0, integral_min: -0.1, integral_max: 0.1 }; const FV_PID_PARAMETERS: pid::Parameters = pid::Parameters { kp: 20.0, ki: 1.5, kd: 0.0, output_min: 0.0, output_max: 150.0, integral_min: -50.0, integral_max: 50.0 }; pub struct Controller { fbi_target: f32, fbi_range: board::EmissionRange, fbi_buffer: [f32; 16], fbi_buffer_count: usize, last_fbi: Option, fbi_pid: pid::Controller, last_fv_target: Option, fv_pid: pid::Controller, last_fv: Option, fbv_target: f32, last_fbv: Option } #[derive(Clone, Copy)] pub struct ControllerStatus { pub ready: bool, pub fbi: Option, pub fv_target: Option, pub fv: Option, pub fbv: Option } impl Controller { pub const fn new() -> Controller { Controller { fbi_target: 0.0, fbi_range: board::EmissionRange::Med, fbi_buffer: [0.0; 16], fbi_buffer_count: 0, last_fbi: None, fbi_pid: pid::Controller::new(FBI_PID_PARAMETERS), last_fv_target: None, fv_pid: pid::Controller::new(FV_PID_PARAMETERS), last_fv: None, fbv_target: 0.0, last_fbv: None, } } pub fn adc_input(&mut self, fbi_sample: u16, fd_sample: u16, fv_sample: u16, fbv_sample: u16) { let fbi_voltage = ((fbi_sample as f32) - board::FBI_ADC_OFFSET)/board::FBI_ADC_GAIN; let fbi_r225 = fbi_voltage/board::FBI_R225; let fbi = match self.fbi_range { board::EmissionRange::Low => fbi_r225, board::EmissionRange::Med => { let fd_voltage = ((fd_sample as f32) - board::FD_ADC_OFFSET)/board::FD_ADC_GAIN; fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R223 }, board::EmissionRange::High => { let fd_voltage = 0.9; fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R224 } }; self.fbi_buffer[self.fbi_buffer_count] = fbi; self.fbi_buffer_count += 1; if self.fbi_buffer_count == self.fbi_buffer.len() { let mut fbi_avg: f32 = 0.0; for fbi in self.fbi_buffer.iter() { fbi_avg += *fbi; } self.last_fbi = Some(fbi_avg/(self.fbi_buffer.len() as f32)); self.fbi_buffer_count = 0; } let fv_target = self.fbi_pid.update(fbi); self.last_fv_target = Some(fv_target); self.fv_pid.set_target(fv_target); let fv = fv_sample as f32/board::FV_ADC_GAIN; let fv_pwm_duty = self.fv_pid.update(fv); board::set_fv_pwm(120); self.last_fv = Some(fv); self.last_fbv = Some(fbv_sample as f32/board::FBV_ADC_GAIN); } pub fn set_emission_target(&mut self, amperes: f32) { self.fbi_target = amperes; self.fbi_pid.set_target(amperes); self.fbi_range = board::EmissionRange::Low; if amperes > 120e-6 { self.fbi_range = board::EmissionRange::Med; } if amperes > 8e-3 { self.fbi_range = board::EmissionRange::High; } board::set_emission_range(self.fbi_range); } pub fn set_bias_target(&mut self, volts: f32) { self.fbv_target = volts; board::set_fbv_pwm((volts/board::FBV_PWM_GAIN) as u16); } fn emission_ready(&self) -> bool { match self.last_fbi { None => false, Some(last_fbi) => (self.fbi_target - last_fbi).abs()/self.fbi_target < 0.05 } } fn bias_ready(&self) -> bool { match self.last_fbv { None => false, Some(last_fbv) => (self.fbv_target - last_fbv).abs() < 1.0 } } pub fn reset(&mut self) { self.fbi_pid.reset(); self.fv_pid.reset(); self.last_fv_target = None; self.fbi_buffer_count = 0; self.last_fbi = None; self.last_fv = None; self.last_fbv = None; } pub fn get_status(&self) -> ControllerStatus { ControllerStatus { ready: self.emission_ready() & self.bias_ready(), fbi: self.last_fbi, fv_target: self.last_fv_target, fv: self.last_fv, fbv: self.last_fbv } } }