diff --git a/src/controller.rs b/src/controller.rs new file mode 100644 index 0000000..b26f42f --- /dev/null +++ b/src/controller.rs @@ -0,0 +1,342 @@ +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex, MutexGuard}; + +pub trait Updatable { + fn update(&self, dt: f64); +} + +pub type UpdatableRef = Arc; + +pub struct NullUpdatable; + +impl Updatable for NullUpdatable { + fn update(&self, _: f64) {} +} + +impl Updatable for Fn(f64) -> () { + fn update(&self, dt: f64) { + self(dt) + } +} + +impl Updatable for [UpdatableRef] { + fn update(&self, dt: f64) { + for updatable in self { + updatable.update(dt); + } + } +} + +use std::time::{Duration, Instant}; + +const DEFAULT_PERIOD: Duration = Duration::from_nanos(1e9 as u64 / 60); + +pub struct Updater { + updatable: UpdatableRef, + period: Duration, +} + +impl Default for Updater { + fn default() -> Self { + Self { + updatable: Arc::new(NullUpdatable), + period: DEFAULT_PERIOD, + } + } +} + +impl Updater { + pub fn new(updatable: UpdatableRef, period: Duration) -> Self { + Self { updatable, period } + } + + pub fn run(self) { + let mut now = Instant::now(); + let mut last_update = now; + let zero_duration = Duration::new(0, 0); + while true { + let ellapsed = now - last_update; + let sleep_dur = self.period - ellapsed; + if sleep_dur < zero_duration { + warn!( + "Updater period exceeded ({}ms > {}ms)", + ellapsed.as_millis(), + self.period.as_millis() + ); + } else { + std::thread::sleep(sleep_dur); + } + now = Instant::now(); + let dt = (now - last_update).as_float_secs(); + last_update = now; + self.updatable.update(dt); + now = Instant::now(); + } + } +} + +pub trait GenericUpdate { + type State: Default; + + fn enable(&mut self, &mut Self::State); + fn disable(&mut self, &mut Self::State); + fn update(&mut self, &mut Self::State, dt: f64); +} + +pub struct GenericUpdatable { + enabled: AtomicBool, + update_impl: Mutex, + state: Mutex, +} + +impl GenericUpdatable { + pub fn new(update_impl: T) -> Self { + Self { + enabled: AtomicBool::new(false), + update_impl: Mutex::new(update_impl), + state: Mutex::new(T::State::default()), + } + } + + pub fn new_ref(update_impl: T) -> UpdatableRef { + Arc::new(Self::new(update_impl)) + } +} + +impl Updatable for GenericUpdatable { + fn update(&self, dt: f64) { + if self.enabled.load(Ordering::SeqCst) { + let (mut imp, mut state) = match (self.update_impl.lock(), self.state.lock()) { + (Ok(a), Ok(b)) => (a, b), + _ => return, + }; + + imp.update(&mut *state, dt); + } + } +} + +pub trait ControllerInput { + fn controller_input(&self) -> f64; +} + +pub trait ControllerOutput { + fn controller_output(&self, output: f64); +} + +pub struct NullInputOutput; + +impl ControllerInput for NullInputOutput { + fn controller_input(&self) -> f64 { + 0.0 + } +} + +impl ControllerOutput for NullInputOutput { + fn controller_output(&self, output: f64) {} +} + +impl ControllerInput for T +where + T: Fn() -> f64, +{ + fn controller_input(&self) -> f64 { + self() + } +} + +impl ControllerOutput for T +where + T: Fn(f64) -> (), +{ + fn controller_output(&self, output: f64) { + self(output); + } +} + +use crate::motor_controller::{MotorController, MotorControllerRef}; + +impl ControllerOutput for MotorController { + fn controller_output(&self, output: f64) { + self.set(output); + } +} + +impl ControllerOutput for MotorControllerRef { + fn controller_output(&self, output: f64) { + self.set(output); + } +} + +pub trait SISO_Compute { + type State: Default; + + fn compute(&mut self, &mut SISO_State, dt: f64) -> f64; +} + +impl Default for Box { + fn default() -> Self { + Box::new(NullInputOutput) + } +} + +impl Default for Box { + fn default() -> Self { + Box::new(NullInputOutput) + } +} + +pub struct SISO_Controller { + pub input: Box, + pub output: Box, + + pub setpoint_min: f64, + pub setpoint_max: f64, + pub output_min: f64, + pub output_max: f64, + pub output_offset: f64, + + pub inner: TInner, +} + +impl std::ops::Deref for SISO_Controller +where + TInner: SISO_Compute, +{ + type Target = TInner; + fn deref(&self) -> &TInner { + &self.inner + } +} + +impl std::ops::DerefMut for SISO_Controller +where + TInner: SISO_Compute, +{ + fn deref_mut(&mut self) -> &mut TInner { + &mut self.inner + } +} + +impl Default for SISO_Controller +where + TInner: SISO_Compute + Default, +{ + fn default() -> Self { + Self { + input: Default::default(), + output: Default::default(), + setpoint_min: std::f64::NEG_INFINITY, + setpoint_max: std::f64::INFINITY, + output_min: std::f64::NEG_INFINITY, + output_max: std::f64::INFINITY, + output_offset: 0.0, + inner: Default::default(), + } + } +} + +pub struct SISO_State { + setpoint: f64, + input: f64, + + inner: TInner, +} + +impl std::ops::Deref for SISO_State { + type Target = TInner; + fn deref(&self) -> &TInner { + &self.inner + } +} + +impl std::ops::DerefMut for SISO_State { + fn deref_mut(&mut self) -> &mut TInner { + &mut self.inner + } +} + +impl Default for SISO_State +where + TInner: Default, +{ + fn default() -> Self { + Self { + setpoint: 0.0, + input: 0.0, + inner: Default::default(), + } + } +} + +impl SISO_State { + pub fn error(&self) -> f64 { + self.input - self.setpoint + } +} + +impl GenericUpdate for SISO_Controller +where + TInner: SISO_Compute + Default, +{ + type State = SISO_State; + + fn enable(&mut self, state: &mut Self::State) {} + fn disable(&mut self, state: &mut Self::State) {} + fn update(&mut self, state: &mut Self::State, dt: f64) { + state.input = self.input.controller_input(); + let output = self.inner.compute(state, dt); + self.output.controller_output(output); + } +} + +pub struct PID_State { + integral: f64, + last_error: f64, +} + +impl Default for PID_State { + fn default() -> Self { + Self { + integral: 0.0, + last_error: std::f64::NAN, + } + } +} + +pub struct PID_Computer { + k_p: f64, + k_i: f64, + k_d: f64, + k_f: f64, +} + +impl Default for PID_Computer { + fn default() -> Self { + Self { + k_p: 0.0, + k_i: 0.0, + k_d: 0.0, + k_f: 0.0, + } + } +} + +impl SISO_Compute for PID_Computer { + type State = PID_State; + + fn compute(&mut self, state: &mut SISO_State, dt: f64) -> f64 { + let err = state.input - state.setpoint; + let mut output = err * self.k_p; + state.integral += err * dt; + output += self.k_i * state.integral; + if !state.last_error.is_nan() { + output += self.k_d * dt * (err - state.last_error); + } + state.last_error = err; + output += self.k_f * state.setpoint; + output + } +} + +pub type PID_Controller = SISO_Controller; diff --git a/src/drive.rs b/src/drive.rs index 6331831..6df7a1c 100644 --- a/src/drive.rs +++ b/src/drive.rs @@ -1,41 +1,64 @@ use std::cell::RefCell; use std::rc::Rc; -use motor_controller::MockMotorController; -use motor_controller::MotorControllerBox; -use motor_controller::MotorControllerBoxed; +use controller::PID_Controller; +use motor_controller::{MockMotorController, MotorControllerNewRef, MotorControllerRef}; pub struct Drive { - left_motors: Vec, - right_motors: Vec, + left_motors: Vec, + right_motors: Vec, + left_controller: PID_Controller, + right_controller: PID_Controller, } pub type DriveRef = Rc>; -fn create_motor_controllers>(ids: T) -> Vec { - ids.into_iter().map(MockMotorController::new_box).collect() +fn create_motor_controllers>(ids: T) -> Vec { + ids.into_iter().map(MockMotorController::new_ref).collect() } impl Drive { - pub fn new() -> Self { + pub fn new_ref() -> Rc> { let left_motors = create_motor_controllers(0u16..4); let right_motors = create_motor_controllers(4u16..8); - Drive { + let mut left_controller = PID_Controller::default(); + left_controller.input = Box::new(|| 0.5); + let mut right_controller = PID_Controller::default(); + right_controller.input = Box::new(|| 0.5); + right_controller.output = Box::new(left_motors[0].clone()); + let drive = Drive { left_motors, right_motors, - } - } + left_controller, + right_controller, + }; + let drive = Rc::new(RefCell::new(drive)); + + drive.borrow_mut().left_controller.output = { + let drive = drive.clone(); + Box::new(move |out| drive.borrow().set_left_power(out)) + }; + drive.borrow_mut().right_controller.output = { + let drive = drive.clone(); + Box::new(move |out| drive.borrow().set_right_power(out)) + }; - pub fn new_ref() -> DriveRef { - Rc::new(RefCell::new(Drive::new())) + drive } - pub fn drive_powers(&mut self, left_power: f64, right_power: f64) { - for motor in &mut self.left_motors { + pub fn set_left_power(&self, left_power: f64) { + for motor in &self.left_motors { motor.set(left_power); } - for motor in &mut self.right_motors { + } + pub fn set_right_power(&self, right_power: f64) { + for motor in &self.right_motors { motor.set(right_power); } } + + pub fn drive_powers(&self, left_power: f64, right_power: f64) { + self.set_left_power(left_power); + self.set_right_power(right_power); + } } diff --git a/src/main.rs b/src/main.rs index 9ea85ef..5d85708 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ #![feature(drain_filter)] +#![feature(integer_atomics)] +#![feature(duration_float)] #[macro_use] extern crate log; @@ -9,6 +11,7 @@ mod command; mod drive; mod motor_controller; mod robot; +mod controller; use robot::Robot; diff --git a/src/motor_controller.rs b/src/motor_controller.rs index 0b73185..be2ba6f 100644 --- a/src/motor_controller.rs +++ b/src/motor_controller.rs @@ -1,6 +1,9 @@ +use std::sync::Arc; +use std::cell::UnsafeCell; + pub trait MotorController { fn id(&self) -> u16; - fn set(&mut self, value: f64); + fn set(&self, value: f64); fn get(&self) -> f64; } @@ -8,26 +11,26 @@ pub trait MotorControllerId: MotorController { fn new(id: u16) -> Self; } -pub type MotorControllerBox = Box; +pub type MotorControllerRef = Arc; -pub trait MotorControllerBoxed { - fn new_box(id: u16) -> MotorControllerBox; +pub trait MotorControllerNewRef { + fn new_ref(id: u16) -> MotorControllerRef; } -impl MotorControllerBoxed for T { - fn new_box(id: u16) -> MotorControllerBox { - Box::new(T::new(id)) +impl MotorControllerNewRef for T { + fn new_ref(id: u16) -> MotorControllerRef { + Arc::new(T::new(id)) } } pub struct MockMotorController { id: u16, - value: f64, + value: UnsafeCell, // meh } impl MotorControllerId for MockMotorController { fn new(id: u16) -> Self { - MockMotorController { id, value: 0.0 } + MockMotorController { id, value: UnsafeCell::new(0.0) } } } @@ -36,12 +39,12 @@ impl MotorController for MockMotorController { self.id } - fn set(&mut self, value: f64) { - self.value = value; - debug!("MotorController id {} value={}", self.id, self.value); + fn set(&self, value: f64) { + unsafe { *self.value.get() = value; } + debug!("MotorController id {} value={}", self.id, value); } fn get(&self) -> f64 { - self.value + unsafe { *self.value.get() } } }