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}