Projects

Unistep2

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 examples
  • Add metadata and library info
  • Repackage 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.

8 thoughts on “Unistep2

  1. 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();

    }

    1. Hi Jin,

      So from your example I see a few things:

      • the moveTo() function takes an unsigned int as it’s argument, so the function is ignoring the sign, moveTo() should be used as a movement to the absolute position of the stepper, defined from 0 to the number of steps you have set one revolution as. To say it simply, it’s like telling your stepper “Go to 3 o’clock”. It will try to extrapolate the shortest path.
      • In your example your call to move is in the loop, without any other logic, so you’re calling the same function again and again. You probably simplified your code just to make a point, but you don’t need to call the function constantly, just run() needs to be called in the loop.

      Hope this helps.

    2. 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

      }

      1. 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.

  2. 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

    1. 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?

  3. 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

    1. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.