stepper_motion/config/
mechanical.rs1use super::limits::StepLimits;
4use super::motor::MotorConfig;
5use super::units::{DegreesPerSec, DegreesPerSecSquared};
6
7#[derive(Debug, Clone)]
11pub struct MechanicalConstraints {
12 pub steps_per_revolution: u32,
14
15 pub steps_per_degree: f32,
17
18 pub max_velocity_steps_per_sec: f32,
20
21 pub max_acceleration_steps_per_sec2: f32,
23
24 pub min_step_interval_ns: u32,
26
27 pub limits: Option<StepLimits>,
29
30 pub max_velocity: DegreesPerSec,
32
33 pub max_acceleration: DegreesPerSecSquared,
35}
36
37impl MechanicalConstraints {
38 pub fn from_config(config: &MotorConfig) -> Self {
40 let steps_per_revolution = (config.steps_per_revolution as f32
42 * config.microsteps.value() as f32
43 * config.gear_ratio) as u32;
44
45 let steps_per_degree = steps_per_revolution as f32 / 360.0;
47
48 let max_velocity_steps_per_sec = config.max_velocity.0 * steps_per_degree;
50
51 let max_acceleration_steps_per_sec2 = config.max_acceleration.0 * steps_per_degree;
53
54 let min_step_interval_ns = if max_velocity_steps_per_sec > 0.0 {
56 (1_000_000_000.0 / max_velocity_steps_per_sec) as u32
57 } else {
58 u32::MAX
59 };
60
61 let limits = config
63 .limits
64 .as_ref()
65 .map(|l| StepLimits::from_soft_limits(l, steps_per_degree));
66
67 Self {
68 steps_per_revolution,
69 steps_per_degree,
70 max_velocity_steps_per_sec,
71 max_acceleration_steps_per_sec2,
72 min_step_interval_ns,
73 limits,
74 max_velocity: config.max_velocity,
75 max_acceleration: config.max_acceleration,
76 }
77 }
78
79 #[inline]
81 pub fn degrees_to_steps(&self, degrees: f32) -> i64 {
82 (degrees * self.steps_per_degree) as i64
83 }
84
85 #[inline]
87 pub fn steps_to_degrees(&self, steps: i64) -> f32 {
88 steps as f32 / self.steps_per_degree
89 }
90
91 #[inline]
93 pub fn velocity_to_steps(&self, deg_per_sec: f32) -> f32 {
94 deg_per_sec * self.steps_per_degree
95 }
96
97 #[inline]
99 pub fn acceleration_to_steps(&self, deg_per_sec2: f32) -> f32 {
100 deg_per_sec2 * self.steps_per_degree
101 }
102
103 #[inline]
105 pub fn velocity_to_interval_ns(&self, velocity_steps_per_sec: f32) -> u32 {
106 if velocity_steps_per_sec > 0.0 {
107 (1_000_000_000.0 / velocity_steps_per_sec) as u32
108 } else {
109 u32::MAX
110 }
111 }
112
113 pub fn check_limits(&self, steps: i64) -> Option<i64> {
115 match &self.limits {
116 Some(limits) => limits.apply(steps),
117 None => Some(steps), }
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use crate::config::units::Microsteps;
126
127 fn make_test_config() -> MotorConfig {
128 MotorConfig {
129 name: heapless::String::try_from("test").unwrap(),
130 steps_per_revolution: 200,
131 microsteps: Microsteps::SIXTEENTH,
132 gear_ratio: 1.0,
133 max_velocity: DegreesPerSec(360.0),
134 max_acceleration: DegreesPerSecSquared(720.0),
135 invert_direction: false,
136 limits: None,
137 backlash_compensation: None,
138 }
139 }
140
141 #[test]
142 fn test_steps_per_revolution() {
143 let config = make_test_config();
144 let constraints = MechanicalConstraints::from_config(&config);
145
146 assert_eq!(constraints.steps_per_revolution, 3200);
148 }
149
150 #[test]
151 fn test_steps_per_degree() {
152 let config = make_test_config();
153 let constraints = MechanicalConstraints::from_config(&config);
154
155 assert!((constraints.steps_per_degree - 8.889).abs() < 0.01);
157 }
158
159 #[test]
160 fn test_velocity_conversion() {
161 let config = make_test_config();
162 let constraints = MechanicalConstraints::from_config(&config);
163
164 assert!((constraints.max_velocity_steps_per_sec - 3200.0).abs() < 1.0);
166 }
167}