A non-blocking Arduino library for controlling 28BYJ-48 stepper motors.
Github: https://github.com/reven/Unistep2
Rationale
28BYJ-48’s are little inexpensive 5v geared stepper motors that are particularly pesky in terms of what’s needed to drive them. They are halfstep steppers and require an 8 step control signal to drive them efficiently. They usually come with (equally inexpensive) ULN2003 driver boards that make connecting them to the Arduino much easier.
I had no success driving them with the standard stepper libraries (Stepper or AccelStepper). There was always resistance and stutter, resulting in increased heat and noise. I finally came across two libraries that worked: Tyler Henry’s CheapStepper, which I couldn’t get to drive two steppers simultaneously without issues; and Matthew Jones’s Unistep, which drove two or more steppers perfectly but in a blocking fashion.
So I decided to create a non-blocking version based on Unistep and added some extra functionality, but I wanted to recognize the contributions made by others.
Features
- Non-blocking
- Can manage 2 or more steppers
- Extra functions to control state of steppers
- More energy efficient
- Precise timing avoids noise, heat, stutter, stalling, etc.
Installation
Download the zip in Releases on github and use the library manager to add it to your libraries. Alternatively you can install manually into your Arduino library folder.
Use
Just call
#include <Unistep2.h>
at the begining of your sketch and construct the stepper objects with the following call in your setup() function:
Unistep2 stepper(p1, p2, p3, p4, stepsPerRev, stepDelay);
where p1 to p4 are the pins you’ve connected your ULN2003 to, stepsPerRev are the steps that your stepper takes to do one revolution (4096-ish in the 28BYJ-48’s) and stepDelay is the delay between each step in microseconds (900 is the fastest that seems to work without issues).
Then you must call
stepper.run()
in your loop. Delaying functions will interfere with the stepper movement.
Function descriptions
- move(int steps): Moves the stepper the indicated amount of steps. If steps is negative movement will be counter-clockwise.
- moveTo(unsigned int pos): Moves the stepper to an absolute position between 0 and stepsPerRev.
- currentPosition(): Returns the current absolute position of the stepper.
- stepsToGo(): Returns the amount of steps remaining for the stepper to complete the assigned movement. Negative will mean counter-clockwise.
- stop(): Stops the current movement and powers down the pins to save energy and avoid heat generation. Is called automatically after each movement, but is available to be called by the user.
To-do
Create examplesAdd metadata and library infoRepackage as plugin zip
Tip jar
If you find this useful in any way, feel free to leave a tip in my bitcoin address if you feel so inclined:
bc1qn7zrnkk47fzwkf5uqyaqu9dzl7mtyrh5h2ef33
License
This library is released into the public domain.
Hi Reven, I tried out your library and it solves a lot of problems I am facing running stepper motors simultaneously. However, I did face one problem when I was using the library which is if I call moveTo command exceeding 15000 steps, the stepper motor will just move in one direction no matter whether the value is positive or negative. looking forward for your reply. below is my code.
#include
// Define some steppers and the pins they will use
Unistep2 stepperX(2, 3, 4, 5, 20000, 500);
void setup()
{
// Your setup code here
// The library initializes the pins for you
}
void loop()
{
// We need to call run() frequently during loop()
stepperX.moveTo(16000);
stepperX.run();
}
Hi Jin,
So from your example I see a few things:
Hope this helps.
Hi Reven,
Thank you for the reply. Can you please advice me based on the below code? Thanks in advance
#include “Unistep2 .h”
Unistep2 stepperX(2, 3, 4, 5, 5000, 1000);
void setup() {
}
void loop() {
stepperX move to a position
(do something)
stepperX move to another position
}
Hi Jin,
I don’t really know what you’re trying to acomplish, so it’s hard to give you a based example. When you say move to position I’m guessing you mean an absolute position, like 1500 for example.
I would probably do something like this in my loop:
stepperX.run();
stepeprX.moveTo(1500);
{check stepper to see if it’s still moving}
{do something else}
{check to see if that something else has finished}
stepperX.moveTo(4500);
The utility of my library is that it is not blocking, i.e. the stepper moves in the background while your code does something else. If you do not need that and you want to do a linear logic (move, then do something, then move), you could do that with a blocking library -see my post above- and not have to check the status.
Hi, instead of the standard stepper application “make a defined number of steps” i want to make the stepper motor drive continously, speed and direction e.g. controlled from a joystick . Later for 4 motors independently . How is this done with your library?
Thanks in advance,
Hans Gruber
Hi Hans,
I don’t think that this library is a good fit for what you have in mind. A function for continuous movement could be added, but I don’t think stepper motors are an ideal candidate for that application. Stepper motors move… well, in steps. So the library lets you count and control those steps.
For what you’re doing you would be better off with DC motors or BLDC motors, that could be controlled (normally with a controller board) with a routine that puts them in motion and then listens to user input (analog joystick, for example, for direction and acceleration) and modulates the motors accordingly (extrapolating analog signal to PWM pulse to the controller). I don’t know, something like that?
Hi Reven, great work. But a little hint. To use the moveTo function, there is needed to set the zero position. This function is missing. Example, if powering on, the stepper can start on any position, so it needs to go to a zero position by reading end switches. After found that, there is a need to set the zero position. Only in this way is it always possible to approach a specific position.
Is it possible that you include this function in the library?
Greetings, Olli
Hi Olli,
These steppers don’t have end switches, so a function to zero them is out of the scope of the library, unfortunately. I think that would fall into the scope of the sketch. It would be easy to get the current position when the end switch is triggered (arbitrarily number) and set it as a zero with a local variable or counter. This would also make it possible to track bigger numbers, because the motors steps are bound to 4096 anyway.
Hey man, I dig your library. Modifyingt right now to fit a robotic arm, in a system with multiple mcus that is a pain in the ass on timing. I’m trying to create two stepper objects, and then combine the sequences in 4 bit chunks and send them out to a shift register. The goal is driving two uln2003s, and use 3 wires instead of . I’m curious…. a few of the class functions return a value. Is there a reason you took this approach instead of just reading the cars?
Hello Haven,
I am using your library but in my application I needed to change the movement speed during the programm execution. So I add the following function to you lib:
void Unistep2::newSteptime(unsigned long newdelay)
{ steptime=newdelay; }
Ofcourse I changed .h, .cpp, and keywords
Maybe you could put something like that in the future versions. I think the number of steps also would be changed outside constructor. Something like newStepsPerRevolution( int newsteps)…
Thanks,
Antonio
Hi, thanks for this. I’ve waded through the stepper lib’s for a non-blocker on an attiny85 and this seems the best so far. I do need speed control for the application I have so I added :
Unistep2.h:
// Allow the speed to be changed 1000 fast : 10000 slow
void setspeed(int newdelay);
and in
Unistep2.cpp
// Change speed (delay between steps)
void Unistep2::setspeed(int newdelay){
// TODO: Limit the values to the range 1000 to 100000
steptime = newdelay;
}
Seems to work. I know _nothing_ of c let alone c++ so I hope it’s not gauche.
Hi Grant,
I might get around to test it, but if I remember correctly from the tests I ran, bending delay to change the speed can have unexpected consequences; these steppers are fussy.
From a project/sketch design point of view, I think it would be a much better idea to find a delay value that makes the stepper happy, and to rely on non blocking timed loops to take each step according to the speed one desires.
I’ll put it on my to-do list…
Hi Reven!
I was wondering if there was any way to adjust the stepDelay throughout the sketch in order to change the speed of a stepper motor actively. I’m trying to make a clock face that you can control the speed that the hands move at with an input method.
Hi Grant,
I’ve been away for some time, but checking your comment I saw that there were other people that had the same need and actually got it to work. Hopefully some of the comments above can be useful to you. Check out the other Grant’s comment. Are you sure you two aren’t the same person? 😀