use core::f32::consts::PI;
use serde::{Serialize, Deserialize};
use syunit::*;
use crate::ActuatorVars;
use crate::data::MicroSteps;
use crate::math::force::torque_dyn;
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct StepperConfig {
pub voltage : f32,
pub overload_current : Option<f32>
}
impl StepperConfig {
pub const GEN : Self = Self {
voltage: 12.0,
overload_current: None
};
pub const ERROR : Self = Self {
voltage: 0.0,
overload_current: None
};
#[inline(always)]
pub fn new(voltage : f32, overload_current : Option<f32>) -> Self {
Self {
voltage,
overload_current
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StepperConst {
pub default_current : f32,
pub inductance : f32,
pub resistance : f32,
pub number_steps : u64,
pub torque_stall : Force,
pub inertia_motor : Inertia
}
impl StepperConst {
pub const ERROR : Self = Self {
default_current: 0.0,
inductance: 0.0,
resistance: 0.0,
number_steps: 0,
torque_stall: Force::ZERO,
inertia_motor: Inertia::ZERO
};
pub const GEN : Self = Self::MOT_17HE15_1504S;
pub const MOT_17HE15_1504S : Self = Self {
default_current: 1.5,
inductance: 0.004,
resistance: 2.3,
number_steps: 200,
torque_stall: Force(0.42),
inertia_motor: Inertia(0.000_005_7)
};
pub fn torque_overload_max(&self, voltage : f32) -> Force {
self.torque_stall * voltage / self.resistance / self.default_current
}
pub fn torque_overload(&self, current : Option<f32>) -> Force {
self.torque_stall * current.unwrap_or(self.default_current) / self.default_current
}
pub fn alpha_max_stall(&self, vars : &ActuatorVars, dir : Direction) -> Option<Acceleration> {
vars.force_after_load(self.torque_stall, dir).map(|f| f / vars.inertia_after_load(self.inertia_motor))
}
pub fn alpha_max_for_omega(&self, vars : &ActuatorVars, config : &StepperConfig, omega : Velocity, dir : Direction) -> Option<Acceleration> {
vars.force_after_load(torque_dyn(self, omega, config.voltage, None), dir).map(|f| f / vars.inertia_after_load(self.inertia_motor))
}
#[inline(always)]
pub fn tau(&self) -> Time {
Time(self.inductance / self.resistance)
}
#[inline(always)]
pub fn omega_max(&self, voltage : f32) -> Velocity {
Velocity(2.0 * PI * voltage / self.default_current / self.inductance / self.number_steps as f32)
}
#[inline(always)]
pub fn omega(&self, step_time : Time, microsteps : MicroSteps) -> Velocity {
if (step_time == Time(0.0)) | (step_time == Time(-0.0)) {
panic!("The given step time ({}) is zero!", step_time)
}
self.step_angle(microsteps) / step_time
}
#[inline(always)]
pub fn step_angle(&self, microsteps : MicroSteps) -> Delta {
self.full_step_angle() / microsteps.as_u8() as f32
}
#[inline(always)]
pub fn full_step_angle(&self) -> Delta {
Delta(2.0 * PI / self.number_steps as f32)
}
#[inline]
pub fn step_time(&self, omega : Velocity, microsteps : MicroSteps) -> Time {
self.step_angle(microsteps) / omega
}
#[inline]
pub fn full_step_time(&self, omega : Velocity) -> Time {
if (omega == Velocity(0.0)) | (omega == Velocity(-0.0)) {
panic!("The given omega ({}) is zero!", omega);
}
self.full_step_angle() / omega
}
#[inline(always)]
pub fn steps_from_angle_abs(&self, angle : Delta, microsteps : MicroSteps) -> u64 {
(angle.abs() / self.step_angle(microsteps)).round() as u64
}
#[inline(always)]
pub fn steps_from_angle(&self, angle : Delta, microsteps : MicroSteps) -> i64 {
(angle / self.step_angle(microsteps)).round() as i64
}
#[inline(always)]
pub fn angle_from_steps_abs(&self, steps : u64, microsteps : MicroSteps) -> Delta {
steps as f32 * self.step_angle(microsteps)
}
#[inline(always)]
pub fn angle_from_steps(&self, steps : i64, microsteps : MicroSteps) -> Delta {
steps as f32 * self.step_angle(microsteps)
}
pub fn round_angle_to_steps(&self, angle : Delta, microsteps : MicroSteps) -> Delta {
self.angle_from_steps(self.steps_from_angle(angle, microsteps), microsteps)
}
#[inline(always)]
pub fn is_in_step_range(&self, steps : i64, angle : Delta, microsteps : MicroSteps) -> bool {
self.steps_from_angle(angle, microsteps) == steps
}
}