Sunday, November 17, 2013

Review: Arduino Motor Drivers - AdaFruit Motor Shield vs RepRap StepStick

Summary

While the old AdaFruit Motor Drive shield is cheap and versatile, it's also not very good. It struggles with even small motors, and if you want anything more sophisticated than "forward" and "back" then it's just not going to perform well.

The "StepStick" board is based on a more advanced chip that amazed me with its power. (I thought thermal shutdown was for certain, on a device that small without heatsinks... I was wrong.) But it is specialized to do one job - push stepper motors - and therefore lacks some flexibility to drive other motor types.

The A4988 is simply superior technology. Once you go DMOS, you realize how much BJT transistors suck. And having built stepper drivers before, I can appreciate its dead-simple microstepping interface. But the Motor Shield is easier to use.

Experimental Setup. AdaFruit motor driver + /Leonardo on top,  
Micro Pro + StepStick on the bottom.

Moving Stuff Around with Arduinos

Over the last few weeks, I've been putting some "robots" together. This is the first time I've added Arduinos to the mix, and so I wanted to try out some of the cheaper and more common hardware on eBay and see if it was any good.

I used various old motors and power supplies I had lying around, but the Arduinos and motor drivers are new, and barely weeks old at this point.
  • Arduino Leonardo (clone) $12
  • AdaFruit L293D Motor Shield (clone) $6.15
  • Micro Pro (clone) $7.30
  • RepRap StepStick (clone) $3.99
All the gear tested came from ShenZen or Hong Kong via eBay, and I'm generally very impressed with the quality and value of what I've received so far. A lot of this gear is often cheap because it's considered "flawed" in some way, but usually this is a result of design or specification, and the kind of classic mistakes (connectors on the 'wrong' side, from the point of view of convenience) that we've all made. The actual build quality is great.

AdaFruit Motor Shield (v1)

The AdaFruit motor shield is a good example. For $6.15, it is a lot of physical hardware. But the design isn't the best, and has dated pretty badly. I found it necessary to trim the pins on the connector blocks with some side-snips to make the shield fit correctly. (And I was also concerned by the sub-millimeter clearance between the M4 connector and the ICSP/SPI pins on the Leonardo.. Hmm.. high volts right next to the CPU. Safe!)

AdaFruit has actually stopped making this version - the v2 shield is much better in every way. But the simplicity and availability of the components means there will probably be clones made for years.

What Leonardo Compatibility Issues?

Astute readers might know that the v1 shield is not officially supported on the newer Leonardo, but I have a few skills, so that situation didn't last long. Physically it's compatible, but the Leo is a little different internally from the Uno or Nova and the stock library makes some assumptions. 
I have a new class in my Droid library called the "Motivator" that can PWM any pin(s) for DC current control. Since it's the pin/PWM/Timer assignments that changed most on the Leo, this was the 'secret sauce' needed to make it run all four motors in DC chopper mode. If anyone needs the code, drop me a line.

Arduino Leonardo hidden by AdaFruit Motor Shield (v1)



And generally it works, but those L293D's get hot. And 'speed control' doesn't necessarily help - the transistors generate a lot of switching heat, so PWM can make things worse


Classic Tamiya toy gearbox, with good quality DC motors.
Sounds like banshees in a sack when running.
The board was simply not capable of driving all four motors at once, or even two at once for any length of time. But in a "classroom" situation where you need to slap something together in 10 minutes which won't run for much longer than that, this is a fairly foolproof solution.

But for permanent emplacement, I just wouldn't trust it. And it uses up (or makes inaccessable, like the SPI connector) too many other resources that a 'real' project would need.

RepRap "StepStick" A4988

It took me a while to believe that the single chip below completely outperformed both L293D drivers in the Motor Shield, but it does. Allegro really need to be congratulated on producing a first-class device, and whoever at the RepRap project picked it as their driver of choice should also be given a round of applause as well.
The Allegro A4988 Stepper Driver chip on the "StepStick" RepRap board.
The module drives bigger motors with more capability, requires fewer pins on the Arduino (always a critical thing) and frees up other internal microcontroller resources like timers. I ran it at twice the voltage of the Motor Shield (12V instead of 6V) with greater current. It has the usual modern array of thermal and short protection, which I inadvertently tested by wiring up the stepper wrong.



Pulled from an '80's era Epson 160-column dot-matrix printer.
They don't make 'em like they used to.

This was not the first stepper I tried, but the module was 'overdriving' my smaller motors and making them heat up (while remaining stone cold itself.) so I wanted to see how large it could go. Driving this big motor at full current (actually more than twice it's rated power) finally got the A4988 warm. Not hot, just warm. 

I tested out the 1/16 microstepping, and it was smooth and precise. (little steppers are more jittery, but these big ones have enough spindle mass to microstep perfectly.)

I've also tried using the module to drive just a single DC motor - which does work quite well, although you are essentially sacrificing half the chip's capability by only using one channel. (Because the other channel is phase-linked, it is mostly useless for driving a second DC motor unless you have a "tank" configuration where sharing power between two wheels might make sense)



The "Micro Pro".
Leonardo equivalent, but a fraction of the size.

If you're wondering where the Arduino is, it's the other tiny board. I am loving the "Micro Pro". I lose two pins compared to it's big brother, but also 9/10ths the volume. Otherwise, it is exactly the same Atmel chip that's on the Leo.

The issue with the A4988 is that it's not a beginner's device, and it's not targeted at Arduino. There are no "libraries" to drive it, (although it's pretty simple) so I wouldn't ask a classroom full of kids to add them to their projects unless I wanted a lot of magic smoke to come out of drivers, arduinos, or even host PCs when they got the 5V and 12V lines mixed up.

But for old pros, it's a beautiful little chip, with many possibilities.

Conclusions

While the A4988 is a better driver, I'm coming to the understanding that both of these technologies have had their day. The only reason to get either is because you have a drawer full of old-school motors and projects already provisioned with them.

If you're designing a new device, then you want to use BLDCs - brushless DC motors - which are essentially the love child of both the previous technologies. Brushless motors are very much like three-phase steppers (instead of two-phase) with less "detents", or like DC motors with an 'electronic commutator'. These are hooked up to ESCs (Electronic Speed Controllers) that decode a digital PWM signal and drive the motors with momentary currents of 20 or 30 amps.

These BLDC motors are more quiet, efficient and reliable than the previous generation, thanks to modern neodymium (and dysprosium) magnets, and our quantum FET mastery. Kudos to the Remote Control model community for pushing the envelope there.

If you look inside an ESC, you will often find what is essentially a commercial Arduino (Atmel 328 being quite popular) in charge of a bank of MOSFETs. A motor driver shield plus microcontroller in one. For $7. It's really hard to beat that. Some are reprogrammable.

If you're designing a new project, start with them. Forget steppers and DC. They're so last millenium.



5 comments:

  1. could you please send me the motorshield working with leonardo boards. thx

    ReplyDelete
  2. the adapted motorshield libary would be nice to have. thx

    ReplyDelete
  3. I need the code for the leonardo compatible motorshield lib!!! big thx!

    ReplyDelete

  4. /*
    The base device class for dealing with the adafruit motor shield. Mostly this just
    sends a direction byte to the shift register - all the actual "motor control" depends
    on application. (Mostly using PWM, or the Motivator)
    */
    class AdaMotorDevice {
    protected:
    static const int PWM_0A = 6;
    static const int PWM_0B = 5;
    static const int PWM_1A = 9;
    static const int PWM_1B = 10;
    static const int PWM_2A = 11;
    static const int PWM_2B = 3;
    static const int DIR_EN = 7;
    static const int DIR_SDA = 8;
    static const int DIR_CLK = 4;
    static const int DIR_LATCH = 12;
    // latch bit mappings
    static const int LATCH_1A = 2;
    static const int LATCH_1B = 3;
    static const int LATCH_2A = 1;
    static const int LATCH_2B = 4;
    static const int LATCH_3A = 0;
    static const int LATCH_3B = 6;
    static const int LATCH_4A = 5;
    static const int LATCH_4B = 7;
    //
    byte _motor_forward[4];
    public:
    // constructor
    AdaMotorDevice() {
    // since we have so many to do..
    int out[] = { LOW, HIGH, LOW, LOW, HIGH, HIGH, LOW, LOW, LOW, HIGH };
    for(int i=3; i<13; i++) {
    pinMode(i, OUTPUT); digitalWrite(i,out[i-3]);
    }
    // all motors start forward.
    memset(_motor_forward, 0x01, 4);
    update_direction();
    }
    // destructor
    ~AdaMotorDevice() {

    }
    void forward(byte motor) {
    if(motor<4) _motor_forward[motor] = 1;
    }
    void reverse(byte motor) {
    if(motor<4) _motor_forward[motor] = 0;
    }
    void exec() {
    update_direction();
    }
    private:
    // update the motor shield with the latest direction information
    void update_direction() {
    // rebuild the direction byte
    byte d = 0;
    d |= _motor_forward[0] ? (1<<LATCH_1A) : (1<<LATCH_1B);
    d |= _motor_forward[1] ? (1<<LATCH_2A) : (1<<LATCH_2B);
    d |= _motor_forward[2] ? (1<<LATCH_3A) : (1<<LATCH_3B);
    d |= _motor_forward[3] ? (1<<LATCH_4A) : (1<<LATCH_4B);
    // send the update
    send_direction(d);
    }

    // send direction byte to motorshield shift register
    void send_direction(byte dir) {
    // enable the shift register
    // digitalWrite(DIR_EN, HIGH);
    // release the latch before transfer
    digitalWrite(DIR_LATCH, LOW);
    // and start clocking out the bits
    shiftOut(DIR_SDA, DIR_CLK, MSBFIRST, dir);
    // and set the latch
    digitalWrite(DIR_LATCH, HIGH);
    // this should always be low, but take a moment to be sure
    digitalWrite(DIR_EN, LOW);
    }
    };

    ReplyDelete
  5. could you upload the .h and .cpp files?
    Would be great :(

    ReplyDelete