Expand description

Stepper - Universal Stepper Motor Interface

Stepper aims to provide an interface that abstracts over stepper drivers and motion control chips, exposing high-level hardware features directly where available, or providing software fallbacks where hardware support is lacking.

Right now, Stepper supports the following ICs:

Please check out the documentation of Stepper, which is the main entry point to this API.

Example

use stepper::{
    fugit::NanosDurationU32 as Nanoseconds,
    motion_control, ramp_maker,
    Direction, Stepper,
};

// We need some `embedded_hal::digital::OutputPin` implementations connected
// to the STEP and DIR signals of our driver chip. How you acquire those
// depends on the platform you run on. Here, we'll use a mock implementation
// for the sake of demonstration.
let step = Pin;
let dir = Pin;

// We also need a timer (that implements `embedded_hal::timer::CountDown`),
// since there are time-critical aspects to communicating with the driver
// chip. Again, how you acquire one depends on your target platform, and
// again, we'll use a mock here for the sake of demonstration.
let mut timer = Timer::<1_000_000>::new();

// Define the numeric type we're going to use. We'll use a fixed-point type
// here, as that's the most widely supported. If your target hardware has
// support for floating point, it might be more convenient (and possibly
// efficient) to use that instead.
type Num = fixed::FixedI64<typenum::U32>;

// Define the target acceleration and maximum speed using timer ticks as the
// unit of time. We could also use seconds or any other unit of time
// (Stepper doesn't care), but then we'd need to provide a conversion from
// seconds to timer ticks. This way, we save that conversion.
//
// These values assume a 1 MHz timer, but that depends on the timer you're
// using, of course.
let target_accel = Num::from_num(0.001); // steps / tick^2; 1000 steps / s^2
let max_speed = Num::from_num(0.001); // steps / tick; 1000 steps / s

// We want to use the high-level motion control API (see below), but let's
// assume the driver we use for this example doesn't provide hardware
// support for that. Let's instantiate a motion profile from the RampMaker
// library to provide a software fallback.
let profile = ramp_maker::Trapezoidal::new(target_accel);

// Now we need to initialize the stepper API. We do this by initializing a
// driver (`MyDriver`), then wrapping that into the generic API (`Stepper`).
// `MyDriver` is a placeholder. In a real use-case, you'd typically use one
// of the drivers from the `stepper::drivers` module, but any driver that
// implements the traits from `stepper::traits` will do.
//
// By default, drivers can't do anything after being initialized. This means
// they also don't require any hardware resources, which makes them easier
// to use when you don't need all features.
let mut stepper = Stepper::from_driver(MyDriver::new())
    // Enable direction control
    .enable_direction_control(dir, Direction::Forward, &mut timer)?
    // Enable step control
    .enable_step_control(step)
    // Enable motion control using the software fallback
    .enable_motion_control((timer, profile, DelayToTicks));

// Tell the motor to move 2000 steps (10 revolutions on a typical stepper
// motor), while respecting the maximum speed. Since we selected a
// trapezoidal motion profile above, this will result in a controlled
// acceleration to the maximum speed, and a controlled deceleration after.
let target_step = 2000;
stepper
    .move_to_position(max_speed, target_step)
    .wait()?;

// Here's the converter that Stepper is going to use internally, to convert
// from the computed delay value to timer ticks. Since we chose to use timer
// ticks as the unit of time for velocity and acceleration, this conversion
// is pretty simple (and cheap).
use num_traits::cast::ToPrimitive;
pub struct DelayToTicks;
impl<const TIMER_HZ: u32> motion_control::DelayToTicks<Num, TIMER_HZ> for DelayToTicks {
    type Error = core::convert::Infallible;

    fn delay_to_ticks(&self, delay: Num)
        -> Result<fugit::TimerDurationU32<TIMER_HZ>, Self::Error>
    {
        Ok(fugit::TimerDurationU32::<TIMER_HZ>::from_ticks(Num::to_u32(&delay).expect("the delay to convert")))
    }
}

Re-exports

pub extern crate embedded_hal;
pub extern crate fugit;
pub extern crate ramp_maker;

Modules

Compatibility code to help use Stepper on more platforms

Parent module for all driver implementations

Software implementation of motion control capability

Types related to working with a driver’s microstepping mode

Traits that can be implemented by Stepper drivers

Utility module for miscellaneous stuff that the rest of the crate needs

Structs

The “future” returned by Stepper::move_to_position

The “future” returned by Stepper::set_direction

The “future” returned by Stepper::set_step_mode

The “future” returned by Stepper::step

Unified stepper motor interface

Enums

Defines the direction in which to rotate the motor

Unified error type

An error that can occur while using this API