maandag 2 december 2013

Microstepping with Arduino

I bought these stepper motors online for a project I'm working on. I'm trying to build a small CNC machine to cut and drill in light materials such as plastic housings or PCBs. The main issue for this purpose will be accuracy in the stepper motors that drive the X- and Y-axis. Torque is not a big deal, since I won't be cutting hard materials.

These motors were cheap for a reason: the step angle is 3.75°, making 96 steps in one revolution. That's not very accurate as steppers go, so for my purpose they may not be suitable. That's te reason why I tried to write some new Arduino code to make them more accurate using microstepping.

As you can see on the picture, the motor comes with six wires, so I could choose to drive it like a unipolar or a bipolar stepper motor. I chose the latter method, since my L293D driver chips support 0.5 Amps current per winding, which is exactly what the supplier claims to be the working current of the motor.

The Arduino code I wrote can now drive the stepper motor in full stepping, half stepping and microstepping. Full stepping would be the best choice if you want maximum torque, half stepping and microstepping are more useful if you need accuracy.

I hooked it up to an oscilloscope to see what waves come out in the different methods. Note that this is only half of the story, meaning the pictures only show one winding (A,B). I use a very old machine as you can see, hooking up two channels to the four wires of the motor would shortwire the driver chip because the scope uses a common ground between the channels. Actually, I had to make the mistake first to find out that the motor stopped and things got hot very fast when connecting channel two ;-)

Now, just imagine channel two (C,D) showing the exact same picture, only with a 90° phase shift. This is what it looks like:



ABCD
1+-+-
2+--+
3-+-+
4-++-
ABCD
1+-+-
2+---
3+--+
4---+
5-+-+
6-+--
7-++-
8--+-
ABCD
1+-+-
2+-½-
3+---
4+--½
5+--+
6½--+
7---+
8-½-+
9-+-+
10-+-½
11-+--
12-+½-
13-++-
14-½+-
15--+-
16½-+-

Full stepping is pretty straight-forward. Just switch polarity on channels (A,B) and (C,D).

Half stepping introduces four extra steps (2,4,6,8) where only one of the four wires is connected to Vcc (the plus side of the power source of the motor), the other three are connected to ground. This means that only one winding is activated in these steps.

In microstepping, eight new steps are introduced which have columns marked '½' for convenience. What it actually means is that my Arduino code switches at a high frequency between two half stepping steps, creating these thick vertical lines on the scope. Step 6 is actually a fast alternation between step 5 and 7.

This is one of these steps in detail. Note that other options are possible with this approach, because when I use these waveforms, the duty cycle can be altered.

This example has a duty cycle of 25%, so it's 25% high and 75% low.




This is what happens when we would create even more steps with different duty cycles.

Instead of inserting one '½' step (or '50% step' like step 6 above), we could insert three new steps 25%, 50%, 75%.




The only difference between the previous microstepping and this one is the vertical thick lines being a bit thicker. But this is what really happens in the code: the duty cycle is incremented from 25 to 50 and then 75%. This creates a 32 steps microstepping model.




Check out this video where I tried to check how far I could go with this motor. I used a mirror on the motor and a powerful LED flashlight to see the refection on the wall. That's the only way to notice these small changes.



I boosted it up to 64 steps, but that's not really useful. In fact, I'm now assuming that a 25% duty cycle in the waveform correponds to a 25% movement between the steps and that's just not true. In fact, in the video I already adjusted some values to correspond to actual movement of the light. So a 25% duty cycle corresponds to a movement of 40 or 50%. It's a bit trial and error and only meaningful up to 32 steps in my setup.

Still, I'm pretty happy with my results! It means I can use my motors at least in 16 steps microstepping, maybe 24 or 32. It means my motors will be at least four times more accurate !

UPDATE
After more testing, I found that boosting the voltage near to the maximum allowed for my motor (so it gets its 500mAmps per winding), results were much more accurate. Even 96 microsteps were possibible resulting in a perfect lineair movement of the motor, much better than the 64 steps in the video.

The source code can be found here:
HTML readable
ZIP source file --> zipped .ino file (Arduino)

This is the connection scheme used, use any stepper motor driver instead of L293D. Use any Arduino pins you want, just change A,B,C,D variables in the code.


15 opmerkingen:

  1. Super! Merci beaucoup pour mon Rail Photo!!!

    BeantwoordenVerwijderen
  2. Fantastic work, thanks for sharing this information

    BeantwoordenVerwijderen
  3. Hi, very nice work
    can you please provide schematic for testing the code
    thanks

    BeantwoordenVerwijderen
  4. I've added a schematic from this setup. I used a driver chip L293D, but you can use any bipolar stepper driver or driver board you want.

    BeantwoordenVerwijderen
  5. Hello, nice piece of code, did you ever try to use that code to emulate one of those "easy drivers" (or A4988 etc... ), ... for instance, an arduino pro mini could behave like an easy driver, running your slightly modified program, to receive pulses and direction from an other "arduino grbl"... I was just wondering if an arduino pro mini would be fast enough to do that...

    Thank you for this instructive tutorial.

    jrb.

    BeantwoordenVerwijderen
    Reacties
    1. I've never tried it but I agree that it would be the next logical step. It will certainly be fast enough, even now my code spends most of its processor time just waiting. But meanwhile (this post is 5 years old) I bought me a mini cnc machine for only 100$ in China, so this DIY idea is a bit out of date for me ;-)

      Verwijderen
  6. Yes... it was just a thought, it struck me that nobody ever tried that, or if they did they didn't brag about it :-). Specially, when looking at controller like this : http://www.watterott.com/en/SilentStepStick-TMC2100-5V-with-Pins you kind of wonder about a DIY justification, other than the mere challenge... besides, I got a bunch of old strong steppers...
    Can I inquire about this Chinese CNC you bought, I'm currently also looking at those...
    Thank's for your time and answer
    jrb.

    BeantwoordenVerwijderen
    Reacties
    1. Thanks for the tip, I didn't know these controllers. I just ordered this even cheaper replacement model on Aliexpress, just to try it out (I bought the cheapest for 6.48$): https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180309001817&SearchText=TMC2208

      the link for the cnc: https://www.aliexpress.com/item/NEW-ANNOYTOOLS-CNC-1610-500mw-2-5w-ER11-GRBL-Diy-mini-CNC-laser-engraving-machine-3/32803240894.html?spm=a2g0s.9042311.0.0.Ff1xWO

      Verwijderen
  7. Hi Jnageox,

    Thanks for sharing the microstepping concept to us, I tried using the same program and failed in continuous rotation of motor, the motor is having lot of jerks and doesnt move. i am suspeting the sequence fo motor coil exitation, can you please cross verify it and let me know the correct sequence.
    for (int j = 0; j < pulseCount; j++){
    switch (st){
    case 1: one();break;
    case 2: two();break;
    case 3: three();break;
    case 4: four();break;
    case 11: oneB();break;
    case 12: twoB();break;
    case 13: threeB();break;
    case 14: fourB();break;

    case 21: one();break;
    case 22: two();break;
    case 23: three();break;
    case 24: four();break;
    case 31: oneB();break;
    case 32: twoB();break;
    case 33: threeB();break;
    case 34: fourB();break;

    }

    delayMicroseconds(dt1);

    switch (st){
    case 1: one();break;
    case 2: two();break;
    case 3: three();break;
    case 4: four();break;
    case 11: oneB();break;
    case 12: twoB();break;
    case 13: threeB();break;
    case 14: fourB();break;

    case 21: oneB();break;
    case 22: twoB();break;
    case 23: threeB();break;
    case 24: fourB();break;
    case 31: two();break;
    case 32: three();break;
    case 33: four();break;
    case 34: one();break;
    }
    delayMicroseconds(dt2);

    }
    Regards,
    ram

    BeantwoordenVerwijderen
  8. IM HAVING THE SAME PROBLEM AND I would guess it is because our motors are not 7.5 degree. mine is 1.8. but i am having trouble finding where he has coded in this parameter

    BeantwoordenVerwijderen
  9. It's most likely due to the activation pattern. I have a 1.8-degree stepper, which works just fine with this code.

    BeantwoordenVerwijderen