Releases: juanmf/StepperMotors
v.0.0.20
Release Notes - Version 0.0.20 (Stable)
Overview
This release introduces several new features, enhancements, and bug fixes to improve the overall stability and functionality of the application. As well as several newly tested drivers (see doc/demo & README), and several bug fixes.
Multiprocess implemented for dedicated process driving a set of motors up to 2 child processes should be safely spawned, each driving multiple controllers, max number will depend on max PPS sent, on a RPi 4B 2 controllers can be pulsed at min period of 30uS, if no callables are provided.
New Features (from MVP v0.0.6)
- BlockingQueueWorker:
- Formal Job definition.
- WorkChain (sequenced execution of Jobs). Also available in multiprocess scenario.
- Controller:
- signedSteps() to accept signet in number of steps. Proxy for CW vs CCW rotation (-) is CCW, (+) is CW.
- moveTo() for absolute positioning in steps, from 0 to )SPR.
- Stepping Event prefixes. See demo files MultiProcessPolarCoordinatesSample.
- Support for sleep/disable mode after stepping
useHoldingTorque
constructor param (and inferred too from enableGpioPin & sleepGpioPin parameters). - Uses MultiprocessObserver to sync jobs execution to proxy
BlockingQueueWorker
in MainProcess. (Client code can use Driver proxies transparently and block on proxied jobs as if those were running locally.)
- Logging:
- tprint() function to buffer outputs in a Thread Local fashion.
- flush_streams() function to dump logs from all threads when convenient. (Avoiding using print at critical times!)
- more handy functions, check ThreadOrderedPrint
- Exit handlers to kill lingering threads and processes. see atexit_handlers
- Changed Timing to monotonic_ns
- EventDispatcher
- can now reguster multiple events to same handler in one
register(eventName=[eName1,...,eNameN], callee)
call - Event propagation from child process to MainProcess.
- can now reguster multiple events to same handler in one
- Multiprocess: sets of Controllers can be initiated in dedicated process. see demo MultiProcessPolarCoordinatesSample
- MultiprocessObserver to encapsulate MP Locks and subscriber/notifier functions.
- StepperMotor:
- Added Builder to
GenericStepper
to make it easy to configure custom stepper definitions.
- Added Builder to
New implementations
Added implementations for best seller motors and drivers. see README and demo files.
v0.0.19-Unstable
Major Changes
Published package to https://test.pypi.org/project/stepper-motors-juanmf1/0.0.19/
MultiprocessObserver Leveraged to sync Jobs in multiprocess scenario. Now MainProcess jobs know when they are done. Client code can use Driver proxies transparently and block on proxied jobs as if those were running locally. #3
7ba371e#diff-b6e9e89760eb653174a673ea4af508ea223bfaa459b5af76c558729f877021f0R66-R114
Chained jobs can now be used in multiprocess scenario. #5
Synchronized navigation bug fix. #2
Improved StepperMotor API, adde builder to GenericStepper
. Added dummy implementations of best seller motors, need test.
Added doc on multiprocess classes and demo.py
with client code examples.
To-do list
Pendings from previous release:
- micro-stepping modes (always used full step mode) (No changes)
- Release next Stable release with current set of features. Add to main pypi mirror (Not yet).
Pendings from this release:
- On Exit, zombi thread prevent returning to prompt. Annoying.
- micro-stepping modes (always used full step mode)
- Release next Stable release with current set of features. Add to main pypi mirror (Not yet).
- add unit tests (no promises)
- Evaluate migration to https://pypi.org/project/python-periphery/ (replace RPi GPIO lib)
- JobChain not working on StaticNavigation #6
v0.0.17-Unstable
Major Changes
MultiprocessObserver Simplifies synchronization between processes, enabling the user focus on actual handling of shared data. And keeping publisher connection and observer in one place.
Improved documentation, hopefully UML diagrams now better convey architecture and usage.
Bubbling up some method from BipolarStepperMotorDriver
to MotorDriver
(if the system grows to DC motors there might be some conflicts to look out to)
Added customization of event names on stepping related events, at Driver constriction and step job initiation times.
Improved tprint()
logs dumping to avoid rare race conditions.
To-do list
Pendings from previous release:
- micro-stepping modes (always used full step mode) (No changes)
- EventDispatcher cross-proccess event propagation from child to parent. Needs testing, probably a few tweaks.
- Check that update position on child process' Controller is visible on Parent Process' Proxy Controller:
Pendings from previous release:
- Release next Stable release with current set of features. Add to main pypi mirror (currently in test).
- micro-stepping modes (always used full step mode)
- add unit tests (no promises)
- Evaluate migration to https://pypi.org/project/python-periphery/ (replace RPi GPIO lib)
v0.0.15-Unstable
Multiprocessing fixes for values sync from child to parent process
This release fixes EventDispatcher level Event propagation from child (motor drivers) to parent (your app) process.
Pendings from release v0.0.13:
- micro-stepping modes (always used full step mode) (no change)
- EventDispatcher cross-proccess event propagation from child to parent. Needs testing, probably a few tweaks.
- Check that update position on child process' Controller is visible on Parent Process' Proxy Controller:
Pendings from this release:
- micro-stepping modes (always used full step mode)
- No known major bug. Todo List:
## Todo List
- **EventDispatcher.py**
- Should I add eventId to callee parameters?
- **Navigation.py**
- Find out if -1 works as LOW (normally set to 0) for direction pin.
- GPIO.LOW is not controller specific. Fix with `controller.setDirection(controller.defaultDirection)` or similar.
- This will be called from multiple threads, one per driver. Handle synchronization accordingly. Waits to get all Synchronized controllers to go then coordinates their steps so that all sleep and step at once.
- **Benchmark.py**
- 'u': lambda: self.undoSpeedBoost(controller, speedBoosts)
- Test after library extraction.
- **Controller.py**
- Migrate to [python-periphery](https://pypi.org/project/python-periphery/).
- If `libc.usleep` works, use active wait under 300uS.
- `libc.usleep` fails on my RPI. See `self.usleep()`.
- Check that "-s" still applies. Think it was important for `PWM()`, not used now.
- Client knows targetPosition, would only need currentPosition and realDirection, but not every step. Update sharedMemory.
- **StepperMotor.py**
- Assess removal. (Remove `self.settingsLock = threading.Lock()`.)
- Remove this one.
- **BlockingQueueWorker.py**
- Sync completion. (Return job. Never complete. The child process might end, we don't have visibility. We could use this thread.)
- **AccelerationStrategy.py**
- Find midpoint when steps < 2 * rampSteps.
- PendingSteps == 0 and PPS == minPPS we should be able to stop without rampDown.
v0.0.13-Unstable
Full Changelog: v0.0.11-Unstable...v0.0.13-Unstable
Huge changes to support real parallelism. Drivers can now run on their own dedicated process, with minimal overhead, while preserving object oriented design, Driver threads remain blocked while Synchronized navigation operates GPIO pulses in a coordinated fashion, transparently, being the only active thread it does not get disturbed by client application and avoid Drivers interfering with each other.
Minor improvements to tprint
Pendings from release v0.0.11:
- micro-stepping modes (always used full step mode) (No change)
- How well threads are scheduled with multiple motors running.
- This release adds 2 complementary features:
-
- BasicSynchronizedNavigation
-
- multiprocess (not multiprocessing) (see README); makes the frequency much more stable as you add motors to your RPi.
Pendings from this release:
- micro-stepping modes (always used full step mode)
- EventDispatcher cross-proccess event propagation from child to parent. Needs testing, probably a few tweaks.
- Check that update position on child process' Controller is visible on Parent Process' Proxy Controller:
def setCurrentPosition(self, position):
self.currentPosition = position
if self.sharedPosition is not None:
with self.sharedLock:
self.sharedPosition.value.position = position
self.sharedPosition.value.direction = self.currentDirection
v0.0.11-Unstable
Full Changelog: v0.0.9-Unstable...v0.0.11-Unstable
This release adds:
- Change time usages to time.monotonic_ns()
- Fixes sleep mode logic, tested on HRB8825 Stepper Motor HAT Board for Raspberry Pi Series . Current stable release is only tested with holding torque (never sleeps)
- Event Dispatcher can now reguster multiple events to same handler in one
register(eventName=[eName1,...,eNameN], callee)
call.
Main areas still pending test:
- micro-stepping modes (always used full step mode)
- How well threads are scheduled with multiple motors running.
** tested this one, it sucks. GIL makes thread management horribly, steps frequency splits in half. Will fix it.
v0.0.9-Unstable
Full Changelog: v0.0.6-MVP...v0.0.9-Unstable
This release adds:
- Improvements to
BlockingQueueWorker
. Better encapsulation of Queue, WorkChain (to sequence jobs in a dynamic navigation scenario, where stacking jobs would interrupt ongoing jobs.)
"""
creates a double-linked list of jobs, starts the 1st when the pipe is set. BlockingQueueWorker's
consumer will add the chain links to the jobQueue in order as it finishes jobs.
"""
class SomeWorkerClass(BlockingQueueWorker):
...
def doSomeChainedWork(self):
self.workChain([your handler fn param list], block=False)
.then([your handler fn next param list])
.startChain())
and job concept (to prevent erratic additions to __jobQueue
and adds Future
s to track job times.)
- Adds EventDispatched, an implementation of mediator pattern. That enables your app to decouple from events happening at the Motor Driver level. You still need to pass in a callable but that callable can fire events that will be handled by your app. En ecense you add extension points using events to hook your app to, instead of adding the logic directly inside the passed callable. EventDispatcher itself is a
BlockingQueueWorker
so it has it's own thread to dispatch published events to registered handlers. - Simplified client code by adding
signedSteps()
method to Drivers, so that the driver itself can decide if it's clockwise or counter clockwise (negative steps number is counter clockwise steps). - Improved README and docstrings, still more updates missing to catch up with new features.
- Huge win (90-100x) in performance and sorting of log messages (from
print()
). multiple thread printing caused a mess inSTDOUT
,tprint()
proxies (not literally) print and stores messages in a map.flush_streams()
dumps logs toSTDOUT
cleaning the in-memory map, each thread's output will be in it's own chunk of output, prefixed by timestamp in microseconds (running RPI must get 10x faster than RPI 4B to start causing timestamp collisions, i.e. two immediate logs are apart by ~10uS). - added at exit handlers to ensure tprint dumps the map to STDOUT when your app ends or crashes. Usage:
import stepper_motors_juanmf1.atexit_handlers
.
This is ready for anyone to test, and could be just the same as next stable, but I didn't have the time to thoroughly test it. As my focus was to add need features from a client perspective and have it work for me.
Main areas still pending test:
- micro-stepping modes (always used full step mode)
- How well threads are scheduled with multiple motors running.
v0.0.6-MVP
Fixed all package issues enabling the library to be pip installed and import
ed into your projects.
Static & Dynamic implementations for following Acceleration strategies & driver combinations implemented, for GenericMotor
and PG35S_D48_HHC2
(retail&datasheet) motors:
def getFlatDRV8825With(self, stepperMotor, directionPin, stepPin):
def getLinearDRV8825With(self, stepperMotor, directionPin, stepPin):
def getExponentialDRV8825With(self, stepperMotor, directionPin, stepPin):
def getCustomTorqueCharacteristicsDRV8825With(self, stepperMotor, directionPin, stepPin, transformations=None):
# Benchmark specific.
def getInteractiveDRV8825With(self, stepperMotor, directionPin, stepPin, minSpeedDelta, minPps):
Also robust Benchmark
module to stress test motors and extract suitable torque characteristics for runtime operation is provided. See README for details.
pip package (currently on test pypi servers):
https://test.pypi.org/project/stepper-motors-juanmf1/#files
Install this release manually:
Download Wheel here
# cd to where you downloaded it
$ pip install --upgrade stepper_motors_juanmf1-0.0.6-py3-none-any.whl
Install form Index pip install -i https://test.pypi.org/simple/ stepper-motors-juanmf1==0.0.6