StepperMotors
Python stepper motor library with customizable acceleration strategies and responsive, interruptible motor operations.
Install / Use
/learn @juanmf/StepperMotorsREADME
Intro
Although Python and PC in general (RPI in particular) are not optimal for accurate timing of stepper motor pulses (OS scheduler + Python sleep inaccuracies and, ATM, Global Interpreter Lock [GIL]), this library aims at providing a versatile tool for managing a set of stepper motors (through their drivers) in several ways that might fit specific scenarios.
A few distinct concepts have been implemented:
Driver(or Controller, used interchangeably), each instantiated driver will behave as a dedicated single thread worker (seeBlockingQueueWorker) which receives steps jobs through a shared queue, in an attempt decouple steps timing from the rest of the system, (here the GIL imposes some challenged in theory).StepperMotor, encapsulates the motor characteristics, like min and max PPS (pulses per second), and instantaneous
torque. A Generic motor is implemented that can be constructed with specifics in case of lacking implementation of
your motor (you are welcome to add it).Navigation, The driver can navigate from A to B, setting direction & sending pulses to the motor, statically (as in a 3D printer scenario where planning is made up front), dynamically (for interactive or event based systems that need to quickly respond to unplanned speed and direction changes), or centrally synchronized for several motors ran in choir (this is also dynamic).AccelerationStrategiesor profiles, handle how to reach max speeds for the motor. Linear, Exponential & Custom (which takes motor's instantaneous torque or a list of transformations as input to max out your motor capabilities). Custom acceleration strategy has a pre-requisite that you use the Benchmark module (see bellow) to find optimal
transformations for your motor, in a production setup (proper load applied). All changes are effected as a function of current motor' speed in PPS. (other systems use curves as function of time. I found that impractical)DelayPlanners(in tandem with Navigation modes) enable Drivers to handle inertia gracefully either in a static or dynamic context. DelayPlanner implementations determine if it's time to start breaking, speeding up or stay steady. Acceleration strategies effect proper changes to speed.
Benchmark, a stress test module to find your motor's (under current load), min & max speeds, and instantaneous torque characteristics, all in terms of PPS. For instantaneous torque characteristics the output (with format[(minPPS, incrementPPS_1), (minPPS + incrementPPS_1, incrementPPS_2), ..., (maxPPS, 0)]) can be used asYourStepperMotorSubClass.TORQUE_CURVEor as an input toCustomAccelerationPerPpsacceleration strategy'stransformationsconstructor argument. This enables your motor to reach max speed in the least amount of steps possible while keeping synch (useful when speed matters).- Currently tested on (see https://www.reddit.com/r/robotics/comments/18ukw4p/benchmarking_stepper_motor/):
- Raspberry Pi 4B with,
- DRV8825 driver board
- PG35S_D48_HHC2 stepper motor
- Currently tested on (see https://www.reddit.com/r/robotics/comments/18ukw4p/benchmarking_stepper_motor/):
EventDispatchercentralized events broker Drivers use to notify any subscriber if steppingComplete events, finalStep
or in advance (10 steps in advance by default). your app can also use it to publish and subscribe to app level events.
It's a neat way to allow for extension points without modifying working classes. In multiprocess scenarioEventDispatcherusesMultiprocessObserverto gain awareness of, and proxy events from, child dedicated process running motor drivers, so in effect, driver events are (re)published in MainProcess where your app resides.
Implemented Drivers
The following table shows what driers have specific implementations, and vaguely their signaling specs, headers marker with * are concepts the MotorDriver base class knows about, Explicitly implemented Driver names are marked with *Bolded. Driers that should work with implemented classes in Italic
| Driver | Step* (Pulse 20-50μs) | Direction* | Enable* | Sleep* | Microstepping* (Number of Pins) | Fault | Implemented | |-------------------------------------------------------------------------------|-----------------------|------------|------------|------------|---------------------------------|-------|-------------| | DRV8825 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | ACTIVE LOW | 3 (2^3 = 8 modes) | YES | Yes | | TMC2209 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | NA | 4 (2^4 = 16 modes) | YES | Yes | | A4988 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | ACTIVE LOW | 3 (2^3 = 8 modes) | NO | Eq(DRV8825) | | TB6600 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | ACTIVE LOW | 3 (2^3 = 8 modes) | YES | | | TB6560 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | ACTIVE LOW | 3 (2^3 = 8 modes) | YES | | | TMC2208 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | NA | 4 (2^4 = 16 modes) | YES | Eq(TMC2208) | | TMC2226 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | NA | 4 (2^4 = 16 modes) | YES | Eq(TMC2208) | | Adafruit Motor HAT Adapter | - | - | - | - | 4 (2^4 = 16 modes) | - | Yes | | LV8729 | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | ACTIVE LOW | 3 (2^3 = 8 modes) | NO | Eq(DRV8825) | | L298N Not supported | 1-2μs (min) | HIGH/LOW | ACTIVE LOW | ACTIVE LOW | 3 (2^3 = 8 modes) | NO | | | ULN2003 (Unipolar) | Full cycle on/off | Sequence | - | - | - Full & Half step | NO | Yes |
Also implements an adapter to Adafruit stepper motor driver.
- Tested on (latest as of this writing) adafruit-circuitpython-motorkit (1.6.14)* See demo files:
- AdafruitStepperAllCombinationsDemo
- AdafruitStepperMotorDemo
Demo
All motors driven by dedicated DRV8825.
Demo with 2 steppers at 400PPS (0.2 Deg/step)
2 Steppers * 3 pins each (dir, step, sleep)
Demo with 4 steppers at 400PPS 2 (0.2 Deg/step) + 4 Nema17 1.8 Deg/step
2 Steppers * 3 GPIO pins (dir, step, sleep) 2 Steppers * 2 GPIO pins (dir, step)
Demo TMC2209(Nema17-17hs4401) + DRV8825(PG35S)
Install
Happy path
If everything works fine (on my RPI this method gets stuck.)
pip install -i https://pypi.org/simple/ stepper-motors-juanmf1
Manually
Manually (find latest link at https://pypi.org/project/stepper-motors-juanmf1/#files copy link for stepper_motors_juanmf1-<latest version>-py3-none-any.whl). Example with stepper_motors_juanmf1-0.0.2-py3-none-any.whl:
juanmf@raspberrypi:~/project/project $ wget https://test-files.pythonhosted.org/packages/8b/7d/289fdee8b0a01e3c0927b9407e14803341daa0d50e65cb592de9a41581b7/stepper_motors_juanmf1-0.0.2-py3-none-any.whl
--2024-01-08 14:23:42-- https://test-files.pythonhosted.org/packages/8b/7d/289fdee8b0a01e3c0927b9407e14803341daa0d50e65cb592de9a41581b7/stepper_motors_juanmf1-0.0.2-py3-none-any.whl
...
Saving to: ‘stepper_motors_juanmf1-0.0.2-py3-none-any.whl’
stepper_motors_juanmf1-0.0.2-py3-none-any.whl 100%[================================================================================================================>] 21.98K --.-KB/s in 0.007s
2024-01-08 14:23:43 (3.01 MB/s) - ‘stepper_motors_juanmf1-0.0.2-py3-none-any.whl’ saved [22507/22507]
juanmf@raspberrypi:~/project/project $ pip install ../
stepper_motors_juanmf1-0.0.2-py3-none-any.whl project/
juanmf@raspberrypi:~/project/project $ pip install ../stepper_motors_juanmf1-0.0.2-py3-none-any.whl
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Processing /home/juanmf/project/stepper_motors_juanmf1-0.0.2-py3-none-any.whl
Installing collected packages: stepper-motors-juanmf1
Successfully installed stepper-motors-juanmf1-0.0.2
To upgrade to a newer release manually, find latest whl file as explained above, then:
now installing stepper_motors_juanmf1-0.0.4-py3-none-any.whl, overriding 0.0.3
juanmf@raspberrypi:~/project $ pip install --upgrade stepper_motors_juanmf1-0.0.4-py3-none-any.whl
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Processing ./stepper_motors_juanmf1-0.0.4-py3-none-any.whl
Installing collected packages: stepper-motors-juanmf1
Attempting uninstall: stepper-motors-juanmf1
Found existing installation: stepper-motors-juanmf1 0.0.3
Uninstalling stepper-motors-juanmf1-0


