easystepper: add non blocking movement and dynamic speed - #894
Open
zombieleet wants to merge 1 commit into
Open
Conversation
Move does not return until the motor stops. A program cannot read a sensor or a remote control while a motor turns. The speed is also fixed at New. This adds an API that leaves the loop with the caller. SetRPM, SetRPMs change speed, also while a motor turns MoveAsync start a movement of n steps and return at once Start turn until Stop Update do one step if a step is due Stop, IsMoving control and read the movement Move and Off keep their behaviour, so existing programs do not change. Move had an error of one step. The first pass of the loop applied the step the motor was already in, so Move(n) moved n-1 steps and Move(1) did not move at all. Move and DualDevice.Move now do all n steps and share their step logic with MoveAsync, so both give the same coil sequence. Update must not do a burst of steps when the caller is late, because a motor loses its position if it must catch up. It does one step and starts the schedule again. The dual proportional calculation needs 64 bits. Two step counts near 65535 overflow a uint32 and the slower motor then gets too few steps. Tested on an ESP32 with a 28BYJ-48 motor and a ULN2003 board.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
A stepper motor is slow. A 28BYJ-48 needs 2048 steps for one turn. At 10 rpm
that turn takes 6 seconds.
Movedoes not return until the motor stops. The program can do nothing inthose 6 seconds.
There is a second limit.
Newcalculates the delay between steps one time andkeeps only that delay. The speed cannot change after that.
Why this is a problem
A stepper motor is common in a robot or in a machine that positions a part.
These programs must do other work while a motor turns.
Moveit stops only after the movement is complete.DualDeviceturns two motors together at one speed. A robot with one motoron each wheel turns a corner with a different speed on each wheel.
the motor turns.
A goroutine for each motor is not a good solution here. The caller loses
control of the sequence, and each goroutine needs its own stack.
The solution
Updatedoes one step if a step is due. The caller keeps the loop.SetRPM,SetRPMsMoveAsyncStartStopUpdateStop,IsMovingMoveandOffkeep their behaviour. Existing programs do not change. The newcode costs nothing when a program does not use it. The
examples/easystepperbinary for microbit is 4344 bytes with this change and 4400 bytes without it.
Three problems found in the tests
Movewas one step short. The first pass of the loop applied the step thatthe motor was already in.
The value of
stepNumbershows the result in 4 step mode.MoveandDualDevice.Movenow do all n steps. They use the same step code asMoveAsync. The blocking API and the non blocking API give the same coilsequence.
Updatedid a burst of steps after a slow loop. The time of the next stepcame from the last time plus the delay. This prevents drift. It is wrong when
the caller is late. The time of the next step is then in the past.
A motor cannot do steps faster than the delay. It loses its position if it must
catch up. With a delay of 4ms and a loop that stopped for 100ms, the motor did
25 steps with no wait.
Updatenow does one step and starts the schedule again.The dual calculation needs 64 bits. Two step counts near 65535 overflow a
uint32.
MoveAsync(100000, 100000)gave the second motor 42949 steps. It nowgives 100000 steps.
Test on hardware
ESP32 with a 28BYJ-48 motor and a ULN2003 board. The LED shows the result. Its
rhythm does not change when the speed of the motor changes.
Output:
The times agree with the motor. A half turn is 1024 steps. The delay at 12 rpm
is
60 / (2048 x 12), which is 2.441ms, so the time is 2.500s.The ramp does 102, 205, 307 and 410 steps in the first four seconds. That is
1024 steps. The last 1024 steps at 15 rpm take 2.0s. The total is 6.0s.
examples/easystepper/async/main.gois the same test without the LED.