embedded_stepper/stepper.rs
1//! High-level **blocking** stepper controller ported directly from the Arduino stepper library.
2//!
3//! This struct delegates coil energizing to a [`StepperMotor`]
4//! implementation and uses an [`DelayNs`] for timing.
5
6use embedded_hal::delay::DelayNs;
7use crate::driver::StepperMotor;
8
9/// High-level stepper controller parameterized by a motor coil driver `M` and a delay `D`.
10pub struct Stepper<M: StepperMotor, D: DelayNs> {
11 pub(crate) motor: M,
12 pub(crate) delay: D,
13 step_number: u32,
14 direction: u32,
15 step_delay: u32,
16 number_of_steps: u32,
17}
18
19impl<M: StepperMotor, D: DelayNs> Stepper<M, D> {
20 /// Create a new controller.
21 ///
22 /// - `number_of_steps`: steps per mechanical revolution (as in Arduino stepper constructor)
23 /// - `motor`: coil driver implementing [`StepperMotor`]
24 /// - `delay`: timing provider implementing [`DelayNs`]
25 pub fn new(number_of_steps: u32, motor: M, delay: D) -> Self {
26 Self {
27 motor,
28 delay,
29 step_number: 0,
30 direction: 0,
31 step_delay: 0,
32 number_of_steps,
33 }
34 }
35
36 /// Set speed in **RPM**.
37 ///
38 /// Equivalent to the Arduino stepper function with the same name except the division by 0 check.
39 ///
40 /// If `speed` or `number_of_steps` are 0, the speed is set to 0
41 pub fn set_speed(&mut self, speed: u32) {
42 if speed != 0 && self.number_of_steps != 0 {
43 self.step_delay = 60 * 1_000_000 / self.number_of_steps / speed;
44 } else {
45 self.step_delay = 0;
46 }
47 }
48
49 /// De-energize all coils by delegating to [clear](`StepperMotor::clear`).
50 pub fn deenergise(&mut self) -> Result<(), M::Error> {
51 self.motor.clear()
52 }
53
54 /// Perform a **blocking** move of `steps_to_move` steps.
55 ///
56 /// Positive values step forward; negative values step backward.
57 ///
58 /// Ported from Arduino stepper `step` function
59 pub fn step(&mut self, steps_to_move: i32) -> Result<(), M::Error> {
60 let mut steps_left = if steps_to_move < 0 {
61 self.direction = 0;
62 -steps_to_move as u32
63 } else {
64 self.direction = 1;
65 steps_to_move as u32
66 };
67
68 while steps_left > 0 {
69 self.delay.delay_us(self.step_delay);
70
71 if self.direction == 1 {
72 self.step_number += 1;
73 if self.step_number == self.number_of_steps {
74 self.step_number = 0;
75 }
76 } else {
77 if self.step_number == 0 {
78 self.step_number = self.number_of_steps;
79 }
80 self.step_number -= 1;
81 }
82
83 steps_left -= 1;
84
85 self.motor.step(self.step_number)?;
86 }
87
88 Ok(())
89 }
90}