1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
//! Step/Dir - Universal Stepper Motor Interface //! //! Step/Dir aims to provide an interface that abstracts over stepper motor //! drivers and controllers, exposing high-level hardware features directly //! where available, or providing software fallbacks where hardware support is //! lacking. //! //! Step/Dir is part of the [Flott] motion control toolkit. Please also check //! out [RampMaker], a library for generating stepper acceleration ramps. In a //! future version, both libraries will be integrated, but for now they can be //! used separately to complement each other. //! //! Right now, Step/Dir supports the following drivers: //! //! - [DRV8825](crate::drivers::drv8825::DRV8825) //! - [STSPIN220](crate::drivers::stspin220::STSPIN220) //! //! Please check out the documentation of [`Driver`], which is the main entry //! point to this API. //! //! # Example //! //! ``` rust //! # fn main() //! # -> Result< //! # (), //! # step_dir::Error< //! # core::convert::Infallible, //! # core::convert::Infallible, //! # core::convert::Infallible, //! # > //! # > { //! # //! use step_dir::{ //! embedded_time::duration::Nanoseconds, //! Direction, Driver, //! }; //! //! // This constant defines how much time there is between two steps. Changing //! // this value directly affects the speed at which the motor runs. //! const STEP_DELAY: Nanoseconds = Nanoseconds(500_000); //! //! # // Use a real driver to make things easy, without making the example seem //! # // to specific to one driver. //! # type MyDriver = step_dir::drivers::drv8825::DRV8825< //! # (), (), (), (), (), (), (), (), () //! # >; //! # //! # struct Pin; //! # impl step_dir::embedded_hal::digital::OutputPin for Pin { //! # type Error = core::convert::Infallible; //! # fn try_set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } //! # fn try_set_high(&mut self) -> Result<(), Self::Error> { Ok(()) } //! # } //! # //! # struct Timer; //! # impl step_dir::embedded_hal::timer::CountDown for Timer { //! # type Error = core::convert::Infallible; //! # type Time = Ticks; //! # fn try_start<T>(&mut self, count: T) -> Result<(), Self::Error> //! # where T: Into<Self::Time> //! # { //! # Ok(()) //! # } //! # fn try_wait(&mut self) -> nb::Result<(), Self::Error> { //! # Ok(()) //! # } //! # } //! # //! # struct Ticks; //! # impl From<Nanoseconds> for Ticks { //! # fn from(_: Nanoseconds) -> Self { //! # Self //! # } //! # } //! # //! # fn delay_ns(_: Nanoseconds) {} //! # //! // 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; //! //! // Now we need to initialize the driver API. We do this by creating a //! // driver-specific API (`MyDriver`), then wrapping that into the generic API //! // (`Driver`). `MyDriver` is a placeholder. In a real use-case, you'd //! // typically use one of the drivers from the `step_dir::drivers` module, but //! // any driver that implements the traits from `step_dir::traits` will work. //! // //! // By default, drivers can't do anything directly 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. //! // //! // Here, we enable control over the STEP and DIR pins, as we want to step //! // the motor in a defined direction. //! let mut driver = Driver::from_inner(MyDriver::new()) //! .enable_direction_control(dir, Direction::Forward, &mut timer)? //! .enable_step_control(step); //! //! // Rotate stepper motor by a few steps. //! for _ in 0 .. 5 { //! // The `step` method returns a future. We just use it to block until the //! // operation completes, but you can also use the API in a non-blocking //! // way. //! driver.step(&mut timer).wait()?; //! //! // After telling the driver to make a step, we need to make sure to call //! // the step method again after an appropriate amount of time. Let's just //! // wait for the right time, using this example `delay_ns` function. How //! // you do this in your own code is up to you. //! delay_ns(STEP_DELAY - driver.pulse_length()); //! } //! # //! # Ok(()) //! # } //! ``` //! //! [Flott]: https://flott-motion.org/ //! [RampMaker]: https://crates.io/crates/ramp-maker #![cfg_attr(not(test), no_std)] #![deny(missing_docs, broken_intra_doc_links)] pub extern crate embedded_hal; pub extern crate embedded_time; pub mod drivers; pub mod step_mode; pub mod traits; mod driver; pub use self::driver::*; /// Defines the direction in which to rotate the motor #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Direction { /// Rotate the motor forward /// /// This corresponds to whatever direction the motor rotates in when the /// driver's DIR signal is set HIGH. Forward = 1, /// Rotate the motor backward /// /// This corresponds to whatever direction the motor rotates in when the /// driver's DIR signal set is LOW. Backward = -1, }