diff --git a/src/core/logic/kinematics.rs b/src/core/logic/kinematics.rs index e69de29..8b13789 100644 --- a/src/core/logic/kinematics.rs +++ b/src/core/logic/kinematics.rs @@ -0,0 +1 @@ + diff --git a/src/core/logic/mod.rs b/src/core/logic/mod.rs index e454905..043d6b9 100644 --- a/src/core/logic/mod.rs +++ b/src/core/logic/mod.rs @@ -1,2 +1,3 @@ pub mod kinematics; -pub mod motor; \ No newline at end of file +pub mod motor; +pub mod pid; diff --git a/src/core/logic/motor.rs b/src/core/logic/motor.rs index 4583698..3ddce2a 100644 --- a/src/core/logic/motor.rs +++ b/src/core/logic/motor.rs @@ -1,24 +1,32 @@ -use crate::core::{ - motor, - positional, - units, -}; +use crate::core::motor; +use crate::core::motor::{Direction, Speed}; +use crate::core::logic::pid; -///The Config for the PID system used by the controller -pub struct PIDConfig { - ///The Porportional value for the controller - pub kp: f32, - ///The Integral value for the controller - pub ki: f32, - ///The Derivative value for the controller - pub kd: f32, - ///The Feedforward value for the controller - pub ff: f32, +pub struct Data { + pub max_speed: Speed, + pub pid: pid::PID, + pub current_direction: Direction, +} -} +///Controller trait for motors. Motors with this trait, automatically have controls included +pub trait Controller: motor::Driver + motor::Sensor { + ///Create a Data field using the Data type in your motor struct, and return it here. The rest of the trait is automatic + fn data(&mut self) -> Data; -///Controller trait for motors. Motors with this trait, automatically have a PID included. -pub trait Controller : motor::Driver + motor::Sensor { - const CONFIG: PIDConfig; -} \ No newline at end of file + ///Uses the given set_speed and then will handle the rest of the control logic to accurately* hit the requested speed + fn control(&mut self, set_speed: Speed) { + let data: &mut Data = &mut self.data(); + let max_speed_rads = data.max_speed.rads(); + let set_speed_rads = set_speed.rads().clamp(-max_speed_rads, max_speed_rads); + + data.pid.set_point(set_speed_rads); + let pid_output = data.pid.pid_step(self.get_speed().rads()); + + data.current_direction.dir_from_f32(pid_output); + + let motor_command = (pid_output * 65535.0) as u16; + + self.set_speed_and_direction(motor_command, data.current_direction); + } +} diff --git a/src/core/logic/pid.rs b/src/core/logic/pid.rs new file mode 100644 index 0000000..19fb743 --- /dev/null +++ b/src/core/logic/pid.rs @@ -0,0 +1,92 @@ +///The Config for the PID system used by the controller +pub struct Config { + ///The Proportional value for the controller + pub kp: f32, + ///The Integral value for the controller + pub ki: f32, + ///The Derivative value for the controller + pub kd: f32, + ///The Feedforward value for the controller + pub ff: f32, + ///The delta time Value used for the controller + pub dt: f32, + ///The max accel change from the controller, 0 means no limit + pub accel: f32, +} + +pub struct PID { + pub config: Config, + + integral: f32, + prev_error: f32, + + set_point: f32, + + output: f32, +} + +impl PID { + ///Calculuates a single step of the PID+FF based on the config given to it. + ///Will output a float between -1.0 and 1.0 + ///Current value is the current "position" of the system NOT the goal + /// Use set_point() method to change the "goal position" for the system + pub fn pid_step(&mut self, current_value: f32) -> f32 { + //If the values + let error = self.set_point - current_value; + + //If the error is equal to 0.0, just return the output from before. All of this math will just end up not affecting anything + if error == 0.0 { + return self.output; + } + + //Calculate the integral + self.integral += error * self.config.dt; + + //Calculate the derivative + let derivative = (error - self.prev_error) / self.config.dt; + + //store the original error + self.prev_error = error; + + //Calculate the feedforward + let f = self.set_point * self.config.ff; + //Calculate the proportional factor + let p = error * self.config.kp; + //Calculate the inegral factor + let i = self.integral * self.config.ki; + //Calculate the derivative + let d = derivative * self.config.kd; + + //Calculate and store the output + let output = match self.config.accel { + 0.0 => f + p + i + d, + _ => { + let pre_output = f + p + i + d; + let change = pre_output - self.output; + let change = change.clamp(-self.config.accel, self.config.accel); + + let accel_output = self.output + change; + let excess = pre_output - accel_output; + + self.integral += excess / self.config.ki; + + accel_output + } + }; + + self.output = output.abs().clamp(-1.0, 1.0); + + //Return the output information + return self.output; + } + + pub fn set_point(&mut self, set_point: f32) { + if set_point != self.set_point { + //Update all internal fields + self.integral = 0.0; + self.prev_error = 0.0; + + self.set_point = set_point; + } + } +}