Inspired by @Gordon writeup to control a stepper motor here, I decided to write a control module for the ubiquitous 28BYJ-48 stepper. These are used everywhere and are manufactured by the millions, so they can be had for very cheap (I just bought 10 with free shipping on eBay for about U$1 apiece). In "4 step" mode there are 2048 steps in a full turn. 8 stepping gets you 4096 discrete steps per 360 degrees.
Note, this is a work in progress, so there are still aspects/concepts evolving in how it works. For now, though, here's what's implemented:
connect(pin1, pin2, pin3, pin4): Used to initialize the driver when loading the module. The pins are the 4 stepper motor coil drivers. Returns an object for controlling the attached stepper motor.
obj.step([ccw[, step8]]): Turns the stepper one step. Optional flags, if true, change direction to counter-clockwise (default is clockwise), and to step with the 8-step schema vs. the 4-step schema (read up on stepper motors, and this will be totally clear).
obj.move(steps[, ccw[, step8[, fnDone]]]): Move the motor shaft 'steps' steps. The true/false flags 'ccw' and 'step8' operate as explained above; the optional parameter 'fnDone' is a callback that gets invoked with the move is completed; this parameter is necessary because the call is non-blocking -- i.e. doesn't wait for the move to complete. Negative 'steps' values will simply reverse the sense of the 'ccw' flag -- i.e. moving -100 steps with ccw 'true' will move cw.
obj.moveAngle(angle[, ccw[, step8[, fnDone]]]): Same as obj.move() except the amount is specified in angular degrees rather than steps.
obj.zero(): Set the current position as location 0 for the following two functions.
obj.moveTo(target[, ccw[, step8[, fnDone]]]): Move to specific step count relative to zero set.
obj.moveToAngle(target[, ccw[, step8[, fnDone]]]): Move to a specific location relative to zero, target in angular degrees.
Properties of the stepper class that can be set separately:
obj.speed: A float value between 0.0 and 1.0, where 1.0 is the maximum speed the shaft can turn, and still maintain accuracy. Setting to 0.5 will cause the shaft to turn half as fast. This parameter affects the delay time between steps, which right now seems to only work 100% reliably if 3ms, but works almost 100% reliably at 2ms so long as the initial steps are a bit slower to allow acceleration of the internal, geared-down motor. I'm still playing with this. Default is 1.0 when the object is created.
stepper = require("28BYJ48").connect(B3, B4, B5, B6);
/* on instantiation, the driver will be zeroed at the stepper's current position */
stepper.moveAngle(45); //turn clockwise 45 degrees
stepper.move(256, true); //turn counterclockwise 256 steps, which is 45deg in 4 step mode
stepper.move(-1024, false, true); //turn counterclockwise 1024 steps in 8-step mode; ==90deg
stepper.moveTo(90, false, false, done); //will turn 180deg/1024 steps clockwise in 4-step mode, then call function 'done()'
...just make sure you do not get a dud!
Nice, thanks! Would you be happy to submit this when you're happy with it? To be honest nothing apart from the angle+speed makes this specific to those steppers, so it might be worth making it a more general module name?
Does this ramp the speed up and down as well? Looks like it might... Some things that might be fun:
Yeah, it does "ramp-up" -- that's part of what I'm investigating. The stuttering happens when it isn't given enough time to accelerate to rotational speed before the fastest intervals between step changes. That's what the check in .move() for the first 10 steps is all about. I'm working on that algorithm to get it to be rock-solid and not stutter. Oh, and the stuttering from setting a new "request" while currently working on a current move -- definite bug, but easy to fix!
As far as being generic, yeah, it almost is. I already decided to make the small changes necessary to make it totally general, then populate it with defaults for the 28BYJ48 so it's ready to go "out of the box" for that stepper, since they're so common. The only specific parameter really is the steps/rotation.
@Gordon good ideas for some additional functionality too! The stop() definitely... Some of the other more complex functionality (like with feedback from sensors like a limit switch) I had in mind for application coding, hence the inclusion of the step() method in the prototype rather than as a private function in the module... the step() method keeps track of position, so functionality can be easily extended with step() and zero() (and stop() which I'll add).
@allObjects yeah, "duds" are always a risk when ordering cheap from China via ebay. And they've gotcha if one or more is bad, 'cause there's no point in trying to return or get a refund on such small amounts (a dollar or two) from those sources.
That's the trade-off... a risk premium. I've been very luck so far, and everything's been solid that's I've ordered from SLC (Slave Labor China). Some of the fabric my wife has ordered came with Opium residue on it though. Are they ever going to unchain the children from those looms? :-) :-) :-)
Good work dealing with stepper motors at this level. I did a CNC drill for PC boards a few years back but I used the EMC2 software to control the steps to the motors on the 3 axis.
It occurred to me that an optical lever could be of use.
Attach clamp glue the motor frame to the table.
Attach a small plane mirror to the motor shaft so the flat of the mirror is parallel to the shaft.
From a few feet away fix a LASER pointer to the table so that the beam hits the mirror.
The reflected beam should make a spot on the wall.
Mark the spot on the wall.
Now step the motor one step and see how much the beam moves on the wall.
A full 360 degrees of steps should align the beam back on the wall spot..
The EMC2 website:
Use a parallel PC port to control direction and steps on 4 axis and uses G code files.
I used the coordinates in the Eagle drill files and a C++ program to create the G-code file for my drill.
G-code on Arduino
Playing to the gear ratio - if a reduction gear is attached - helps with figuring out how many steps make 360 degrees. ...and once in a while 'go back' to calibration point (end switch / light gate) to reset 0... Using Espruino for running a stepper fast can be an issue because of other things that can go on. From performance page we know that you can loop over two pin set()s about 4K times/sec 0.25ms/cycle. Two pin sets is pretty little... an optimized interval construct on 2ms and considering the optimized (array-ed) pin sets for the stepper leave about 1.5..1.75 ms left for to do other things, until you will notice at least slow down, but more so stuttering (leaving the stepper running at max speed over some time just placed on a sounding surface will bring that to our ear as hum with interceptions...).
Don't worry about formatting, just type in the text and we'll take care of making sense of it. We will auto-convert links, and if you put asterisks around words we will make them bold.
For a full reference visit the Markdown syntax.
© Espruino, powered by microcosm.
Report a problem