stepgen/
lib.rs

1#![no_std]
2#![warn(missing_docs)]
3#![deny(warnings)]
4
5//! Stepper motor speed ramp generator.
6//!
7//! Given acceleration, target speed and target step to stop
8//! at, generates acceleration or deceleration profile for the stepper motor, in the form of delays
9//! between steps.
10//!
11//! Uses algorithm from "[Generate stepper-motor speed pro les in real time][1]" paper by David Austin.
12//!
13//! # Examples
14//! ```
15//! use stepgen::Stepgen;
16//!
17//! let mut stepper = Stepgen::new(1_000_000);
18//!
19//! stepper.set_acceleration(1000 << 8).unwrap(); // 1000 steps per second per second
20//! stepper.set_target_speed(800 << 8).unwrap(); // 800 steps per second (4 turns per second)
21//! stepper.set_target_step(1000).unwrap(); // stop at step 1000
22//!
23//! // Take 99 steps
24//! for _ in 0..99 {
25//!     println!("{}", stepper.next().unwrap());
26//! }
27//!
28//! assert_eq!(99, stepper.current_step());
29//! assert_eq!(113621, stepper.current_speed());
30//! assert_eq!(2242, (stepper.next().unwrap() + 128) >> 8); // delay for 100th step, rounded to the nearest integer
31//! ```
32//! ## Note on numbers
33//!
34//! In few APIs, stepgen keeps numbers as fixed-point numbers, using least significant 8 bits
35//! for the fractional part and the remaining bits for the integral part.
36//!
37//! [1]: http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time
38
39
40/// Error code for some of the stepgen operations.
41#[derive(Clone, Copy, PartialEq, Debug)]
42pub enum Error {
43    /// Requested parameter (acceleration or speed) is too slow -- delay is too long and does not
44    /// fit in 16.8 format.
45    TooSlow,
46
47    /// Requested speed is too fast -- delay is to short for the MCU to process it timely.
48    TooFast,
49
50    /// Speed or acceleration was not configured when step is set.
51    SpeedAccelerationNotSet
52}
53
54/// Result type for some of the stepgen operations.
55pub type Result = core::result::Result<(), Error>;
56
57// Smallest delay we can handle without significant rounding errors
58const FASTEST_DELAY: u32 = 30;
59
60/// State of the stepgen.
61#[derive(Debug)]
62pub struct Stepgen {
63    // Current step
64    current_step: u32,
65
66    // Amount of acceleration steps we've taken so far
67    speed: u32,
68    // Previously calculated delay, in 16.16 format
69    delay: u32,
70
71    // If slewing, this will be the slewing delay. Switched to this mode once
72    // we overshoot target speed. 16.16 format.
73    slewing_delay: u32,
74
75    // Timer frequency
76    ticks_per_second: u32,
77    // First step delay, in 16.16 format
78    first_delay: u32,
79    // Target step
80    target_step: u32,
81    // Target speed delay, in 16.16 format
82    target_delay: u32,
83}
84
85/// This function computes square root of an `u64` number.
86fn u64sqrt(x0: u64) -> u64 {
87    let mut x = x0;
88    let mut xr = 0; // result register
89    let mut q2 = 0x4000_0000_0000_0000u64; // scan-bit register, set to highest possible result bit
90    while q2 != 0 {
91        if (xr + q2) <= x {
92            x -= xr + q2;
93            xr >>= 1;
94            xr += q2; // test flag
95        } else {
96            xr >>= 1;
97        }
98        q2 >>= 2; // shift twice
99    }
100
101    // add for rounding, if necessary
102    if xr < x { xr + 1 } else { xr }
103}
104
105impl Stepgen {
106    /// Create new copy of stepgen. `ticks_per_second` defines size of each tick stepgen operates.
107    /// All settings (acceleration, speed) and current parameters (speed) are defined in terms of
108    /// these ticks.
109    pub const fn new(ticks_per_second: u32) -> Stepgen {
110        Stepgen {
111            current_step: 0,
112            speed: 0,
113            delay: 0,
114            slewing_delay: 0,
115            ticks_per_second,
116            first_delay: 0,
117            target_step: 0,
118            target_delay: 0,
119        }
120    }
121
122
123    // Configuration methods. Should not be called while motor is running.
124
125    /// Set stepper motor acceleration, in steps per second per second (in 16.8 format).
126    /// Note that this method is computation intensive, so it's best to set acceleration
127    /// once and never change it.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use stepgen::Stepgen;
133    /// let mut stepgen = Stepgen::new(1_000_000);
134    ///
135    /// stepgen.set_acceleration(1200 << 8).unwrap();
136    /// ```
137    ///
138    /// # Errors
139    ///
140    /// Returns an error if acceleration is too slow (first delay does not fit into 16.8).
141    ///
142    /// Too slow:
143    ///
144    /// ```
145    /// use stepgen::{Stepgen, Error};
146    ///
147    /// let mut stepper = Stepgen::new(1_000_000);
148    ///
149    /// // 1 step per second per second -- too slow!
150    /// assert_eq!(Error::TooSlow, stepper.set_acceleration(1 << 8).unwrap_err());
151    /// ```
152    pub fn set_acceleration(&mut self, acceleration: u32) -> Result {
153        // c0 = F*sqrt(2/a)*.676 = F*sqrt(2/a)*676/1000 =
154        //      F*sqrt(2*676*676/a)/1000 =
155        //      F*sqrt(2*676*676*1^16)/(1000*1^8)
156        // We bring as much as we can under square root, to increase accuracy of division
157        // sqrt(1 << 16) is (1 << 8), which is to convert to 24.8
158        // We shift 24 bits to the left to adjust for acceleration in 24.8 format plus to convert
159        // result into 24.8 format, so the resulting shift is 40 bits.
160        // 676 is used to correct for the first step (see the linked paper)
161        let c0long: u64 = ((2u64 * 676 * 676) << 40) / u64::from(acceleration);
162        let c0: u64 = (u64::from(self.ticks_per_second) * u64sqrt(c0long) / 1000) >> 8;
163        if (c0 >> 24) != 0 {
164            // Doesn't fit in 16.8 format, our timer is only 16 bit.
165            return Err(Error::TooSlow);
166        }
167        // Convert to 16.16 format. We only need this precision during intermediate calculations.
168        self.first_delay = (c0 as u32) << 8;
169        Ok(())
170    }
171
172    /// Set destination step for the stepper motor pulse generator. This is one of the two methods
173    /// to control the step generation (target step and target speed). If current step > target
174    /// step, stepper motor would slow down until stop if running or stay stopped if not running.
175    ///
176    /// # Errors
177    /// If speed or acceleration are not set, returns an error `Error::SpeedAccelerationNotSet`.
178    ///
179    /// # Notes
180    /// 1. Steps could only go in positive direction. Therefore, setting target step to 0 wil
181    /// always force step generation to decelerate and stop.
182    pub fn set_target_step(&mut self, target_step: u32) -> Result {
183        if self.target_delay == 0 || self.first_delay == 0 {
184            return Err(Error::SpeedAccelerationNotSet);
185        }
186        self.target_step = target_step;
187        Ok(())
188    }
189
190    /// Set slew speed (maximum speed stepper motor would run), in steps per second. Note that
191    /// stepper motor would only reach this speed if target step is far enough, so there is
192    /// enough space for acceleration/deceleration.
193    ///
194    /// # Errors
195    ///
196    /// Returns an error if target speed is either too slow (first delay does not fit into 16.8) or
197    /// too fast (first delay is shorter than `TICKS_PER_UPDATE`).
198    ///
199    /// Too slow:
200    ///
201    /// ```
202    /// use stepgen::{Stepgen, Error};
203    ///
204    /// let mut stepper = Stepgen::new(1_000_000);
205    ///
206    /// // 1 step per second -- too slow!
207    /// assert_eq!(Error::TooSlow, stepper.set_target_speed(1 << 8).unwrap_err());
208    /// ```
209    ///
210    /// Too fast:
211    ///
212    /// ```
213    /// use stepgen::{Stepgen, Error};
214    ///
215    /// let mut stepper = Stepgen::new(1_000_000);
216    ///
217    /// // 1_000_000 step per second per second -- too fast!
218    /// assert_eq!(Error::TooFast, stepper.set_target_speed(1_000_000 << 8).unwrap_err());
219    /// ```
220    pub fn set_target_speed(&mut self, target_speed: u32) -> Result {
221        if target_speed == 0 {
222            // Too slow, speed is zero
223            return Err(Error::TooSlow);
224        }
225        let delay = (u64::from(self.ticks_per_second) << 16) / u64::from(target_speed);
226        if (delay >> 24) != 0 {
227            // Too slow, doesn't fit in in 16.8 format, our timer is only 16 bit.
228            return Err(Error::TooSlow);
229        }
230        if delay <= u64::from(FASTEST_DELAY) * (1 << 8) {
231            // Too fast, less than 10 ticks of a timer. 10 is an arbitrary number,
232            // just to make sure we have enough time to calculate next delay.
233            return Err(Error::TooFast);
234        }
235        // Convert to 16.16 format. We only need this precision during intermediate calculations.
236        self.target_delay = (delay as u32) << 8;
237        Ok(())
238    }
239
240    /// Current step stepgen is at.
241    pub fn current_step(&self) -> u32 {
242        self.current_step
243    }
244
245    /// Target step stepgen should stop at. Note that if stepper is running too fast, it might not
246    /// be able to stop exactly at this step. This could happen when target step is updated after
247    /// stepper motor accelerated to certain speed.
248    pub fn target_step(&self) -> u32 {
249        self.target_step
250    }
251
252    /// Get estimated current speed, in 24.8 format
253    pub fn current_speed(&self) -> u32 {
254        let delay = if self.slewing_delay != 0 { self.slewing_delay } else { self.delay };
255        let delay = delay >> 8; // Convert to 16.8 format
256        if delay != 0 {
257            let speed = (u64::from(self.ticks_per_second) << 16) / u64::from(delay);
258            speed as u32
259        } else {
260            0
261        }
262    }
263
264    /// If we are running at target speed
265    pub fn is_at_speed(&self) -> bool {
266        self.slewing_delay != 0
267    }
268
269    /// Returns '0' if should stop. Otherwise, returns timer delay in 24.8 format
270    fn next_delay(&mut self) -> u32 {
271        let target_step = self.target_step;
272        let target_delay = self.target_delay;
273        let st = self.current_step;
274
275        // We are at the stop point and speed is zero -- return "stopped" (delay of 0)
276        if st >= target_step && self.speed <= 1 {
277            self.speed = 0;
278            return 0;
279        }
280
281        // Stop slewing if target delay was changed
282        if self.slewing_delay != 0 && self.slewing_delay != target_delay {
283            self.slewing_delay = 0;
284        }
285
286        // Steps made so far
287        self.current_step += 1;
288
289        if self.speed == 0 {
290            let d = if target_delay > self.first_delay {
291                // No acceleration is necessary -- just return the target delay
292                target_delay
293            } else {
294                // First step: load first delay, count as one acceleration step
295                self.delay = self.first_delay;
296                self.speed = 1;
297                self.delay
298            };
299            return d >> 8; // Convert to 16.8 format
300        }
301
302        // Calculate the projected step we would stop at if we start decelerating right now
303        let est_stop = st + self.speed;
304        if est_stop == target_step {
305            // We would stop one step earlier than we want, so let's just
306            // return the same delay as the current one and start deceleration
307            // on the next step.
308        } else if est_stop > target_step {
309            // We need to stop at target step, slow down
310            self.slowdown();
311
312            // We are not slewing even though we could have slowed down below the slewing speed
313            self.slewing_delay = 0;
314        } else if self.slewing_delay == 0 && self.delay < target_delay {
315            // Not slewing and running too fast, slow down
316            self.slowdown();
317
318            // Switch to slewing if we slowed down enough
319            if self.delay >= target_delay {
320                self.slewing_delay = target_delay;
321            }
322        } else if self.slewing_delay == 0 && self.delay > target_delay {
323            // Not slewing and running too slow, speed up
324            self.speedup();
325
326            // Switch to slewing if we have accelerated enough
327            if self.delay <= target_delay {
328                self.slewing_delay = target_delay;
329            }
330        }
331
332        // If slewing, return slew delay. delay should be close enough, but could
333        // be different due to the accumulated rounding errors
334        let d = if self.slewing_delay != 0 { self.slewing_delay } else { self.delay };
335        d >> 8 // Convert to 16.8 format
336    }
337
338
339    fn speedup(&mut self) {
340        let denom = 4 * self.speed + 1;
341        self.delay -= (2 * self.delay + denom / 2) / denom;
342        self.speed += 1;
343    }
344
345    fn slowdown(&mut self) {
346        self.speed -= 1;
347        let denom = 4 * self.speed - 1;
348        self.delay += (2 * self.delay + denom / 2) / denom;
349    }
350}
351
352impl Iterator for Stepgen {
353    type Item = u32;
354
355    fn next(&mut self) -> Option<Self::Item> {
356        match Stepgen::next_delay(self) {
357            0 => None,
358            v => Some(v)
359        }
360    }
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366
367    const FREQUENCY: u32 = 1_000_000; // Tests assume timer ticking at 1us (1Mhz)
368
369    fn round(delay: u32) -> u32 {
370        (delay + 128) >> 8
371    }
372
373    #[test]
374    fn sqrt_works() {
375        assert_eq!(0, u64sqrt(0));
376        assert_eq!(1, u64sqrt(1));
377        assert_eq!(2, u64sqrt(4));
378        assert_eq!(3, u64sqrt(10));
379        assert_eq!(4, u64sqrt(15));
380        assert_eq!(0x80_00_00_00u64, u64sqrt(0x4000_0000_0000_0000u64));
381        assert_eq!(0x1_00_00_00_00u64, u64sqrt(0xffff_ffff_ffff_ffffu64));
382    }
383
384    #[test]
385    fn acceleration_too_slow() {
386        let mut stepgen = Stepgen::new(FREQUENCY);
387        assert_eq!(Err(Error::TooSlow), stepgen.set_acceleration(1 << 8));
388    }
389
390    #[test]
391    fn too_slow() {
392        let mut stepgen = Stepgen::new(FREQUENCY);
393        assert_eq!(Err(Error::TooSlow), stepgen.set_target_speed(1 << 8));
394    }
395
396    #[test]
397    fn too_slow_2() {
398        let mut stepgen = Stepgen::new(FREQUENCY);
399        stepgen.set_target_speed(3907).unwrap();
400        assert_eq!(Err(Error::TooSlow), stepgen.set_target_speed(3906));
401    }
402
403    #[test]
404    fn too_slow_zero() {
405        let mut stepgen = Stepgen::new(FREQUENCY);
406        assert_eq!(Err(Error::TooSlow), stepgen.set_target_speed(0));
407    }
408
409    #[test]
410    fn slower_than_first_step_after_accel() {
411        // Setting very slow speed after acceleration is OK
412        let mut stepgen = Stepgen::new(FREQUENCY);
413        stepgen.set_acceleration(1000 << 8).unwrap();
414        stepgen.set_target_speed(5120).unwrap(); // 20 pulses per second = 50_000 delay
415        stepgen.set_target_step(3).unwrap();
416        assert!(stepgen.first_delay < stepgen.target_delay);
417
418        // Walk three steps
419        assert_eq!(50_000 << 8, stepgen.next().unwrap());
420        assert_eq!(0, stepgen.speed);
421        assert_eq!(50_000 << 8, stepgen.next().unwrap());
422        assert_eq!(0, stepgen.speed);
423        assert_eq!(50_000 << 8, stepgen.next().unwrap());
424        assert_eq!(0, stepgen.speed);
425        assert!(stepgen.next().is_none());
426    }
427
428    #[test]
429    fn slower_than_first_step_before_accel() {
430        // Setting acceleration after setting slow speed is also OK
431        let mut stepgen = Stepgen::new(FREQUENCY);
432        stepgen.set_target_speed(5120).unwrap();
433        stepgen.set_acceleration(1000 << 8).unwrap();
434        stepgen.set_target_step(3).unwrap();
435        assert!(stepgen.first_delay < stepgen.target_delay);
436
437        // Walk three steps
438        assert_eq!(50_000 << 8, stepgen.next().unwrap());
439        assert_eq!(0, stepgen.speed);
440        assert_eq!(50_000 << 8, stepgen.next().unwrap());
441        assert_eq!(0, stepgen.speed);
442        assert_eq!(50_000 << 8, stepgen.next().unwrap());
443        assert_eq!(0, stepgen.speed);
444        assert!(stepgen.next().is_none());
445    }
446
447    #[test]
448    fn too_fast() {
449        let mut stepgen = Stepgen::new(FREQUENCY);
450        assert_eq!(Err(Error::TooFast), stepgen.set_target_speed(1_000_000 << 8));
451    }
452
453    #[test]
454    fn slow_during_acceleration() {
455        let mut stepgen = Stepgen::new(FREQUENCY);
456        stepgen.set_target_speed(800 << 8).unwrap();
457        stepgen.set_acceleration(1000 << 8).unwrap();
458        stepgen.set_target_step(core::u32::MAX).unwrap();
459
460        assert_eq!(0, stepgen.current_speed());
461
462        assert_eq!(30232, round(stepgen.next().unwrap()));
463        assert_eq!(18139, round(stepgen.next().unwrap()));
464        assert_eq!(14108, round(stepgen.next().unwrap()));
465        assert_eq!(11938, round(stepgen.next().unwrap()));
466
467        // Update target speed, want to run slower
468        stepgen.set_target_speed(50 << 8).unwrap();
469        assert_eq!(14108, round(stepgen.next().unwrap()));
470        assert_eq!(18139, round(stepgen.next().unwrap()));
471        assert_eq!(20000, round(stepgen.next().unwrap())); // 20000 = 1_000_000 / 50
472        assert_eq!(50 << 8, stepgen.current_speed());
473
474        // Slow a little bit more
475        stepgen.set_target_speed(40 << 8).unwrap();
476        assert_eq!(25000, round(stepgen.next().unwrap())); // 25000 = 1_000_000 / 40
477        assert_eq!(40 << 8, stepgen.current_speed());
478    }
479
480    #[test]
481    fn no_speed_set() {
482        let mut stepgen = Stepgen::new(FREQUENCY);
483        stepgen.set_acceleration(1000 << 8).unwrap();
484        assert_eq!(Err(Error::SpeedAccelerationNotSet), stepgen.set_target_step(1_000_000_000));
485    }
486
487    #[test]
488    fn no_acceleration_set() {
489        let mut stepgen = Stepgen::new(FREQUENCY);
490        stepgen.set_target_speed(800 << 8).unwrap();
491        assert_eq!(Err(Error::SpeedAccelerationNotSet), stepgen.set_target_step(1_000_000_000));
492    }
493}