User Tools

Site Tools


oak:tutorials:stepper_motor

This is an old revision of the document!


Oak: Controlling a Stepper Motor with an A4988 Driver

This lesson teaches you how to:

  • Control a stepper motor with an A4988 stepper motor driver,
  • Expose functions and variables to the Particle Cloud, for remote control via OakTerm, the Particle mobile app, or
  • Build a custom html page to command the stepper motor over the internet

Components Used:

Part Quantity Identification
Oak with soldered headers 1
Stepper motor 1 *
Stepper motor driver 1 A4988
DC power supply, 8-35V 1
Jumper wires 5
Electrolytic capacitor, ~100uF 1 50-200 uF

*Note: Most stepper motors in the ≤2A range will work for this lesson, including both bipolar and unipolar stepper motors with current and voltage ratings below 2A and 8V. The A4988 is not compatible with 5-lead unipolar motors. Refer to A4988 documentation and motor specifications when selecting a motor for this project.

Concepts:

Stepper Motors: A complete description of stepper motors is beyond the scope of this lesson. Adafruit's article All About Stepper Motors is an excellent summary of how stepper motors work and how they are used. For the purpose of this lesson, the important thing to understand is that they step between discrete positions. For example, a stepper motor with 200 steps per revolution (typical), moves in 1.8° increments and may only turn to 200 specific positions (unless you use microstepping which the A4988 is capable of, but that's a topic for another day..).

How a stepper motor driver works: In order to force the motor to step from one position to the next, a driver circuit must energize the coil(s) in such a way to attract the rotor toward the next position and/or repel it from the current position. The direction the rotor steps depends on the polarity of the coil(s). Stepper motors are typically driven by individual current pulses or square waves, with each pulse corresponding to a single step.

You could, in theory, drive a stepper motor in a single direction using a single field effect transistor (FET) controlled from a single GPIO pin from your Oak, but you'll probably want to be able to drive your motor in both directions. To do that, you'll need to power each phase with 4 FETs each, configured as H-bridges. That's 8 FETs that you would need to signal in various combinations depending on direction.

The A4988 and similar stepper motor drivers include two H-bridge circuits, one for each phase, with additional logic that takes the burden of signaling the 8 individual H-bridge FETs and abstracts their coordinated operation to two signals: step and direction. Each pulse into the the step pin signals the A4988 to drive the motor 1 step in either the CW or CCW direction, depending on whether the direction pin is high or low.

CAUTIONS:

This circuit includes parts that can get hot enough to burn you and parts which can cause damage if installed incorrectly. Exercise caution when assembling and operating this circuit. Proceed at your own risk.

The A4988 driver can get very hot!

  • The A4988 driver can get hot enough to burn you, even during normal operation.
  • If you have an IR gun, use it to monitor the A4988.
  • Do not use your finger as a temperature gauge.
  • Heat dissipation in the A4988 is a function of your motor's impedance, external torque on the motor, supply voltage, and drive speed. When you first start moving the motor, command at slow speeds for limited periods of time and gradually work up to faster speeds while monitoring the temperature of the A4988 driver. Max speed might not be much more than 60 RPM (1 rev/sec, or 200 steps/sec for 200 step/rev motor).

Do not install the capacitor backwards!

Do not apply motor power supply backwards!

  • This circuit does not have reverse polarity protection.
  • Connecting power supply leads in backwards can destroy your A4988, or worse.
  • Double check power supply polarity before you connect to the A4988.
  • From personal experience (oops), plugging in 12Vdc backwards for 3 seconds, the chip got hot but was not damaged.

You MUST set the current limiting trim pot for your motor

  • The trim potentiometer on the A4988 is initially set to some random value.
  • The initial value may allow the A4988 to push more current than your motor can handle.
  • Follow instructions below.

Circuit:

Wait! Before connecting your Oak to the A4988 stepper motor driver, consider flashing the sketch below and experimenting with it to become familiar with how it works. By default, this sketch uses pin1 for the step signal specifically to give you a visual indication of when the motor should step. Try commanding a step rate of 2 (step/sec) and watch the LED flash twice per second, then try changing the speed. You can do similar experiments with commanding direction if you remap the direction signal to pin1 in the sketch in order to see the LED turn on or off as you command direction (-1 or 1).

Step 1: Connect the electrolytic capacitor

  • Connect the ~100uF capacitor across the A4988 VMON and GND pins, being very careful to connect in the correct polarity. Electrolytics usually have a stripe or “-” indicator on the side that should connect to ground. If you connect the capacitor backwards, it may explode when you apply power.

Step 2: Connect motor power supply to the A4988

  • If you're using a wall-wart transformer, unplug it from the wall. If you're using a benchtop power supply, turn it off.
  • Connect supply+ to the A4988 VMOT pin, and supply- to the neighboring GND pin.
  • Be very careful not to get these backwards, otherwise your board will overheat.

Step 3: set coil current limits on A4988 driver

  • The following steps outline this process. If any of this doesn't make sense, read the Current Limiting section on Pololu's A4988 page and watch their very informative video on youtube.
  • You need to know the maximum per-phase limit for your motor (use rating current, if per-phase current is not provided in your motor's datasheet).
  • Decide what current limit you want to use.
    • The current limit you choose must be less than or equal to your motor's rating to avoid overheating your motor and/or the driver. The motor and driver will run cooler if you operate with a current limit lower than your motor's rating. It is recommended that you start with a current limit equal to half of your motor's rating, monitor the temperature of the A4988 at this lower initial operating point, then gradually increase the limit later if you need more power and if the motor and driver do not get too hot.
  • Calculate reference voltage, Vref, based on your selected max current, Imax:
    • If your A4988 was manufactured by Pololu in Jan 2017 or later: Vref = 8*Imax*0.068
    • Otherwise: Vref = 8*Imax*0.050 = 0.4*Imax
  • At this point, only your motor power supply and capacitor should be plugged into the A4988.
  • Apply motor power
  • Measure voltage between motor supply ground and the center of the trim pot on the A4988
  • Adjust the trim pot until the voltage equals your calculated Vref.
    • Tip: to measure Vref as you adjust the trim pot at the same time, use an alligator clip to connect your multimeter Vin+ lead to the shaft of a small metal screwdriver which you use to turn the trim pot.
  • Turn your motor supply power OFF.

Step 4: Connect the stepper motor to the A4988 driver

  • You turned off or unplugged your motor power supply, right?
  • You'll need to figure out which leads from the stepper motor go to which pins on the A4988.
    • The A4988 driver powers two phases (coils) simultaneously - one through pins A1 and A2, and the other through pins B1 and B2. Your stepper motor may have more leads than you need. If you have access to the datasheet for your motor, look up its type and wire coloring scheme. Otherwise, you'll need to measure resistance between pairs of leads to determine which pair connects to the ends of one coil (coil “A”), and which pair of other leads connects to the other coil (coil “B”) (it doesn't matter which coil is A and which is B), per instructions in the following table.
    • Once you've identified end-leads for each coil, you can connect one coil's end leads to A1 and A2 (order doesn't matter), and the other coil's end leads to B1 and B2 (order doesn't matter). The Pololu A4988 FAQ provides handy diagrams to help with this.
# Leads (Probable) Type Connection Mapping
4 2-phase bipolar Easy! The four leads connect to two coils. Determine which leads pair together by measuring resistance/continuity between them. Connect the end-leads from one coil to A1 and A2, and the end-leads form the other coil to B1 and B2 (order doesn't matter).
5 2-phase unipolar Sorry, the A4988 cannot drive this type of motor.
6 2-phase unipolar Measure resistance between leads to group the leads into 2 sets of 3, according to continuity. Within each set, measure resistance across pairs of leads to find the pair with the highest resistance - these leads connect to the ends of one of the coils, while the third lead is a center tap, which we won't use (this diagram may be useful). One pair of end-leads will connect to A1 and A2, while the other set of end-leads connects to B1 and B2 (order doesn't matter).
8 2-phase unipolar This one is complicated; it has 2 coils per phase, and the coils can be configured in series (recommended by Pololu for use with A4988) or parallel. Refer to the connection guide in the Pololu FAQ.

Step 5: Test motor connections

  • Your power supply is still turned off or unplugged, right?
  • At this point, only the capacitor, the (turned off) motor power supply, and the stepper motor should be plugged into the A4988.
  • Try to twist the shaft of your motor with your fingers. It will feel stiff but it should turn. You'll feel it “tick” through the detent (step) positions. If you can't turn it at all, then you might have a problem; make sure none of your leads are shorted together, and make sure the A4988 is off. If you were able to turn the motor, then proceed.
  • Turn on or plug in your motor power supply.
  • You may or may not see/hear/feel the slightest twitch of the motor.
  • Make sure nothing is getting hot. The A4988 might get slightly warm.
  • Try to twist the motor shaft again with your fingers. The shaft should be much harder, if not impossible to run. If that's true, then you're in good shape. The A4988 driver is actively counteracting the torque you apply to the motor, in order to hold motor position.
  • Turn off or unplug your motor power supply.

Connect the Oak to the A4988

  • Motor power is off, right?
  • Unplug your Oak from USB or its own power supply.
  • Connect a jumper from the Oak's Vcc pin to the A4988 VDD pin. This powers the A4988 logic circuits.
  • Connect a jumper from the Oak's Gnd pin to the A4988 GND pin.
  • Connect a jumper from the Oak's P0 pin to the A4988 DIR pin.
  • Connect a jumper from the Oak's P1 pin to the A4988 STEP pin.
  • Connect a jumper between the A4988's RESET and SLEEP pins.

Power up!

  • Turn on the Oak.
  • Turn on or plug in motor power to the A4988.
  • Make sure the A4988 is not getting too warm.

Code:

const int pinStep = 1;
const int pinDirection = 0;
const int durationStepPulseMs = 1; //ms
const int maxStepsPerSec = 4;

int stepDirection = 0;       // -1 for CCW, 1 for CW, 0 for unset
double stepSpeed = 0;        // steps per sec
int stepPeriodMs = 0;   // ms per step
int waitBetweenStepsMs; // ms

bool doMotion = false;

char outStr[32] = "";  //buffer for strings to Particle.publish
char* str_end;  // needed for string conversion error checking


// the setup function runs once when you press reset or power the board
void setup() {
  // Initialize step and direction pins:
  pinMode(pinDirection, OUTPUT);
  digitalWrite(pinDirection, LOW);
  pinMode(pinStep, OUTPUT);
  digitalWrite(pinStep, LOW);

  // Setup Particle function handles:
  Particle.function("motion",motion);
  Particle.function("setspeed",setSpeed);
  Particle.function("setdir",setDirection);

  // Setup Particle variable accessors:
  Particle.variable("speed",stepSpeed);
  Particle.variable("direction",stepDirection);
  Particle.variable("do_motion",doMotion);
  Particle.variable("step_period",stepPeriodMs);
  Particle.variable("step_wait",waitBetweenStepsMs);
}



// the loop function runs over and over again forever
void loop() {
  //
  if( doMotion && stepSpeed>0 && (stepDirection==-1 || stepDirection==1) ){
    doOneStep();
    delay(waitBetweenStepsMs);
    
  } else {
    delay(100);
  }
  
}


int motion(String startOrStop){
  if( strcmp("start",startOrStop.c_str())==0){
    doMotion = true;
    return 1;
  } else if( strcmp("stop",startOrStop.c_str())==0){
    doMotion = false;
    return 0;
  } else {
    doMotion = false;
    Particle.publish("motion() error","expected \"start\" or \"stop\"");
    return -1;
  }
}



int setSpeed(String strStepsPerSecond){
  // Attempt to convert the string to a double:
  stepSpeed = strtod(strStepsPerSecond.c_str(), &str_end); // steps per sec
  
  // Check if the string converted properly:
  if (*str_end != '\0') {
    sprintf(outStr, "Unable to convert \"%s\" to float", strStepsPerSecond.c_str());
    Particle.publish("setSpeed() error", outStr);
    stepSpeed = 0;
    return -1;
  }

  // Calculate step period (ms between steps):
  stepPeriodMs = (stepSpeed==0) ? 1000 : 1000/stepSpeed;  //ms
  waitBetweenStepsMs = stepPeriodMs - durationStepPulseMs;
  return stepPeriodMs;
}



int setDirection(String dirRequest){
  // Expect "1" or "-1"
  if( strcmp(dirRequest.c_str(),"-1")==0 || strcmp(dirRequest.c_str(),"1")==0 ){
    stepDirection = atoi(dirRequest.c_str());
  } else {
    Particle.publish("setDirection() Error","direction must be -1 or 1");
    stepDirection = 0;
  } 
  
  // Set direction pin:
  digitalWrite(pinDirection, (stepDirection==1)?HIGH:LOW );  // set direction pin
  
  return stepDirection;
}


// This function applies a single STEP pulse:
void doOneStep(){
  digitalWrite(pinStep, HIGH);  // start step pulse
  delay(durationStepPulseMs);   // hold step pulse
  digitalWrite(pinStep, LOW);   // stop step pulse
}

The sketch above exposes 3 functions to the Particle Cloud. You can access these functions via OakTerm, the Particle mobile app, or via direct http GET/POST exchanges.

  • motion(start) starts motion, if you previously configured speed and direction.
  • motion(stop) stops motion.
  • setspeed([stepsPerSecond]) sets the motor speed in steps per second.
  • This accepts floating point values. For example, value 0.5 steps 1 step per 2 seconds.
  • You can command a different speed while the motor is running.
  • setdir(-1 or 1) sets motor direction.
  • Whether 1 corresponds to CW or CCW depends on which coil you hooked up to A and B.
  • You can command a different direction while the motor is running.

Stepper Controller Web Interface

  • The following is a fairly crude demonstration of one way to send POST/GET commands to the Particle API to remotely interface with your Oak and the attached stepper motor.
    • Replace MY_DEVICE_ID with your device ID and MY_ACCESS_TOKEN with your access token, then save as stepper_controller.html, anywhere you'd like.
<!DOCTYPE>
<html>
  <head>
    <title>Stepper Motor Controller</title>
  </head>
  
  <body>
  
    <h3><a href=http://digistump.com/wiki/controlling_a_stepper_motor_via_a4988_driver>Oak Stepper Motor Controller</a></h3>
  
    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/setspeed" method="POST" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
	  Set speed:  
      <input type="text" name="speed" value="">
      <input type="submit" value="Submit">
    </form>
	
    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/setdir" method="POST" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
	  Set direction:  
      <input type="submit" name="args" value="-1">
      <input type="submit" name="args" value="1">
    </form>
  
    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/motion" method="POST" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
      <input type="submit" name="args" value="start">
      <input type="submit" name="args" value="stop">
    </form>

    <br>

    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/speed" method="GET" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
      <input type="submit" value="check speed">
    </form>

    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/direction" method="GET" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
      <input type="submit" value="check direction">
    </form>
	
    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/do_motion" method="GET" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
      <input type="submit" value="check do_motion">
    </form>
	
    <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/step_period" method="GET" target="replyFrame">
      <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> 
      <input type="submit" value="check step_period">
    </form>
	
    <br>
    <iframe name="replyFrame" width="100%" height="100%" />
  </body>
</html>

Conclusion:

Where to go from here, potential uses, etc.

oak/tutorials/stepper_motor.1484419030.txt.gz · Last modified: 2017/01/14 10:37 by Rover#18