Compare commits

...

10 Commits

Author SHA1 Message Date
melfely 3d2399aaea shorted comment length so no scroll bar 2026-06-28 08:03:24 -05:00
melfely 14fb0899f3 Verison bump to 0.3.0 2026-06-14 14:24:39 -05:00
melfely 3df2334b10 Changed over to async functions
changed over all the classes in these files to use async based methods
rather than non. This SHOULD make the system more reliable with embassy
in the future, and hopefully prevent issues with blocking code and the
way embassy works.
2026-06-14 14:24:08 -05:00
melfely 6ade7615a7 version bump. 2026-06-13 13:54:28 -05:00
melfely 16107036e7 Changed internal PID math
The system new reduces itself by 1000 internally before output,
hopefully making the precision much higher (IE NOT needing to use tiny
ass inputs to make anything reasonable)
2026-06-13 13:53:22 -05:00
melfely 19bbcfd7ab version bump 2026-06-13 12:12:23 -05:00
melfely ff448bf1af Added a retrieve method
This will let you get the speed from the motor directly without the
future communication system being needed
2026-06-13 12:11:31 -05:00
melfely 58eb647507 added docs comments for new method 2026-06-12 19:08:07 -05:00
melfely 8631d9d2a1 Fixed a new() issue
where it took in a PID rather than a pid::PID rather than a pid::PID

Version Bump to 0.2.2
2026-06-12 19:07:37 -05:00
melfely eb7d4ca59a Version bump 2026-06-12 19:01:19 -05:00
6 changed files with 43 additions and 29 deletions
Generated
+1 -1
View File
@@ -22,7 +22,7 @@ dependencies = [
[[package]]
name = "rnavp"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"serde",
]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rnavp"
version = "0.2.0"
version = "0.3.0"
edition = "2024"
publish = ["gitea"]
+15 -6
View File
@@ -25,26 +25,35 @@ where
///Controller Impl for the adding the PID logic for handling the motor compiston
impl<T: motor::Driver + motor::Sensor> Controller<T> {
///Uses the given set_speed and then will handle the rest of the control logic to accurately* hit the requested speed
pub fn control(&mut self, set_speed: Speed) {
pub async fn control(&mut self, set_speed: Speed) {
let max_speed_rads = self.max_speed.rads();
let set_speed_rads = set_speed.rads().clamp(-max_speed_rads, max_speed_rads);
self.pid.set_point(set_speed_rads);
let pid_output = self.pid.pid_step(self.motor.get_speed().rads());
self.pid.set_point(set_speed_rads).await;
let pid_output = self.pid.pid_step(self.motor.get_speed().await.rads()).await;
self.current_direction.dir_from_f32(pid_output);
let motor_command = (pid_output * 65535.0) as u16;
self.motor
.set_speed_and_direction(motor_command, self.current_direction);
.set_speed_and_direction(motor_command, self.current_direction)
.await;
}
pub fn new(motor: T, max_speed: Speed, pid: pid::PID) -> Self {
///Retrieve the speed from the motor inside the controller.
/// This allows you to get a speed value from behind the move.
pub async fn retrieve(&self) -> motor::Speed {
self.motor.get_speed().await
}
///Creates a new Controller with a motor (of type T), a max speed and a pid::Config
/// This then allows for you to use the controller with the provided types
pub fn new(motor: T, max_speed: Speed, config: pid::Config) -> Self {
Controller {
motor: motor,
max_speed: max_speed,
pid: pid,
pid: pid::PID::new(config),
current_direction: Direction::CCW,
}
}
+6 -6
View File
@@ -38,14 +38,14 @@ impl PID {
integral: 0.0,
prev_error: 0.0,
set_point: 0.0,
output: 0.0
output: 0.0,
}
}
}
impl Default for PID {
fn default() -> Self {
PID::new(Config{
PID::new(Config {
kp: 0.0,
ki: 0.0,
kd: 0.0,
@@ -61,7 +61,7 @@ impl PID {
///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 {
pub async fn pid_step(&mut self, current_value: f32) -> f32 {
//If the values
let error = self.set_point - current_value;
@@ -93,9 +93,9 @@ impl PID {
//Calculate and store the output
let output = match self.config.accel {
0.0 => f + p + i + d,
0.0 => (f + p + i + d) * 0.0001,
_ => {
let pre_output = f + p + i + d;
let pre_output = (f + p + i + d) * 0.0001;
let change = pre_output - self.output;
let change = change.clamp(-self.config.accel, self.config.accel);
@@ -117,7 +117,7 @@ impl PID {
return self.output;
}
pub fn set_point(&mut self, set_point: f32) {
pub async fn set_point(&mut self, set_point: f32) {
if set_point != self.set_point {
//Update all internal fields
self.integral = 0.0;
+1
View File
@@ -4,6 +4,7 @@ pub mod communication;
#[cfg(feature = "core_logic")]
pub mod logic;
pub mod error;
pub mod motor;
pub mod positional;
pub mod units;
+19 -15
View File
@@ -111,62 +111,66 @@ impl Display for Speed {
}
}
///This trait is implemented on a motor struct to implement the motor DRIVER (like an ESC) capabalities in how it should control the motor.
/// This will then let other systems use this generic trait and system to control your motor without needing to understand the hardware as much.
/// # Motor Driver
///
/// This trait is implemented on a motor struct to implement the motor DRIVER (like an ESC) capabalities in how it should control the motor.
/// This will then let other systems use this trait and system to control your motor without needing to understand the hardware as much.
#[allow(async_fn_in_trait)]
pub trait Driver {
///Spins in the provided direction
/// Properly map each direction to CounterClockWise and Clockwise when LOOKING AT THE MOTOR SHAFT. This is VITAL for the way the systems within core::logic will work.
///This is best not called manually, use set_speed_and_direction_raw instead
fn spin(&mut self, dir: Direction);
async fn spin(&mut self, dir: Direction);
///Commands the motor to stop
/// This should stop the motor in what ever way you see fit.
/// Some hardware may have a proper "Stop" or "Off" Signal, some will not.
/// If there is no proper hardware stop, verify that 0 speed is actually a stopping command and you can easily just set speed to 0 via set_speed_raw in this method.
/// No default implementation (though this is easily something I could have done) because it SHOULD be something you notice and implement PROPERLY if applicable
fn stop(&mut self);
async fn stop(&mut self);
///This method uses a full u16 to set the motor speed. This does not change spin direction.
/// You need to map 0 to 65535 properly to your specific hardware range, just because PWM is commonly 0 to 65535 do not assume that ALL ways of controlling a motor cleanly takes a value of 0 to 65535,
/// you need to verify and map properly.
/// 65535 should be the max possible speed, while 0 should be stopped.
///This is best to not call manually, use set_speed_and_direction_raw instead
fn set_speed(&mut self, speed: u16);
async fn set_speed(&mut self, speed: u16);
///Commands the motors to use the speed and spin in the same command.
///Uses a number between 0 and 65535
///This should be used in most cases, unless the motor has the core::logic::motor::controller Trait, then the the methods from that should be used instead.
fn set_speed_and_direction(&mut self, speed: u16, dir: Direction) {
async fn set_speed_and_direction(&mut self, speed: u16, dir: Direction) {
//Set direction before speed, so it won't start spinning in one direction, then snap to the other.
//Most MCUs should execute these two lines of code so fast, that it should be neglible regardless.
self.spin(dir);
self.set_speed(speed);
self.spin(dir).await;
self.set_speed(speed).await;
}
}
///This trait is implemented on motors that have some form of sensory feedback. Note that this does not require the motor ITSELF provide feedback, just that the setup the motor is in supports it. IE, a Current draw based ESC
/// # Motor Sensor
/// This trait is implemented on motors that have some form of sensory feedback. Note that this does not require the motor ITSELF provide feedback, just that the setup the motor is in supports it. IE, a Current draw based ESC
/// Speed Feedback is REQUIRED, if your device does not provide speed feedback directly,
/// Implement the other conditions and use them to then implement the speed method.
///
///
/// Some motors/sensors might have a direct "Current Angle" being reported, the option is there in case yours can, so the communication system can sync it to the host for you.
/// Some sensors may also provide current and voltage feedback, if implemented the communication system can sync them to the host you for.
/// Can also be used for other custom logic. They are unused by RNavP, entirely optional.
#[allow(async_fn_in_trait)]
pub trait Sensor {
///Returns the speed struct value from the motors sensor.
/// This should be non-blocking, there should be some form of cached value ready to go as soon as the method is called
///
/// IF properly returned in the correct Enum Data field, all other systems will use the value propely, being unit agnostic later.
fn get_speed(&self) -> Speed;
async fn get_speed(&self) -> Speed;
///Returns the current from the sensor, if it capable.
/// This should be non-blocking. Keep a cached value ready.
fn get_current(&self) -> Option<Current>;
async fn get_current(&self) -> Option<Current>;
///Returns the current voltage from the sensro, if it is capable.
/// This should be non-blocking. Keep a cached value ready.
fn get_voltage(&self) -> Option<Voltage>;
async fn get_voltage(&self) -> Option<Voltage>;
///Returns the current angle from the sensor if it is capable.
/// This should be non-blocking. Keep a cached value ready.
fn get_angle(&self) -> Option<Angle>;
async fn get_angle(&self) -> Option<Angle>;
}