Search code examples
pythonpython-3.xraspberry-pigpiomotordriver

Programming in Python: Controlling Stepper Motor + Raspberry Pi Zero + L293D IC


(Warning! I am not educated on this topic)

Hey folks. I'm posting here because I have a friend who desperately needs help with her project. I'm familiar with scripting, but not too much with programming. I do work in IT, so I'll do my best to provide the necessary information. She's trying to program a Raspberry Pi Zero to control a stepper motor using Python 3. Simple as that.

She followed these tutorials. Looks like she used the parts and wiring from #1 and the code from #2:

  1. https://tutorials-raspberrypi.com/how-to-control-a-stepper-motor-with-raspberry-pi-and-l293d-uln2003a/

  2. https://www.raspberrypi.org/forums/viewtopic.php?f=49&t=55580

Helpful pictures here. This is her actual setup: https://photos.app.goo.gl/WJbCo4UU3wAdo8913

Helpful notes: She mentioned she is not using a resistor between the power source and the L293D Driver IC.

Parts Used:

-Raspberry Pi Zero (Pi 2 or 3 was recommended, but the Zero has the same pin-out as the 2 & 3. She just had to solder on her own double-header)

-12V DC Power Bank

-Nema 17 Stepper Motor (https://www.amazon.com/STEPPERONLINE-17HS13-0404S1-Stepper-Motor-Printer/dp/B00PNEQ9T4)

-L293D Motor Driver IC (https://www.amazon.com/NDRTJM-SHOMPFL1045-L293D-Stepper-Driver/dp/B008XCGLNM)

-Breadboard w/ jumper cables (Duh!)

The code that she's using is below. When she attempts to run it, the motor just vibrates. Seems like it's repeatedly taking a step forward and a step back. No error codes are received. She also tried using another Nema 17 Stepper Motor that drawed 2A, but dropped down to the Nema 17 that draws .4A and gets the same result.

import RPi.GPIO as GPIO
import time

#variables

delay = 0.05
steps = 500

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

#Enable GPIO pins for ENA and ENB for stepper

enable_a = 18
enable_b = 22

#Enable pins for IN1-3 to control step sequence
 coil_A_1_pin = 17 #black
coil_A_2_pin = 4 #green
coil_B_1_pin = 24 #red
coil_B_2_pin = 23 #blue

#Set pin states

GPIO.setup(enable_a, GPIO.OUT)
GPIO.setup(enable_b, GPIO.OUT)
GPIO.setup(coil_A_1_pin, GPIO.OUT)
GPIO.setup(coil_A_2_pin, GPIO.OUT)
GPIO.setup(coil_B_1_pin, GPIO.OUT)
GPIO.setup(coil_B_2_pin, GPIO.OUT)

#set ENA and ENB to high to enable stepper

GPIO.output(enable_a, True)
GPIO.output(enable_b, True)

#function for step sequence

def setStep(w1, w2, w3, w4):
     GPIO.output(coil_A_1_pin, w1)
     GPIO.output(coil_A_2_pin, w2)
     GPIO.output(coil_B_1_pin, w3)   
     GPIO.output(coil_B_2_pin, w4) 

#loop through step sequence based on number of steps

for i in range(0, steps):
     setStep(1,1,0,0)
     time.sleep(delay)
     setStep(0,1,1,0)
     time.sleep(delay)
     setStep(0,0,1,1)
     time.sleep(delay)
     setStep(1,0,0,1)
     time.sleep(delay)

#reverse previous step sequence to reverse motor direction

for i in range(0, steps):
     setStep(1,0,0,1)
     time.sleep(delay)
     setStep(0,0,1,1)
     time.sleep(delay)
     setStep(0,1,1,0)
     time.sleep(delay)
     setStep(1,1,0,0)
     time.sleep(delay)

If there is ANYTHING I missed or more information that you require, please let me know and I will respond quickly! Any help is greatly appreciated! Thanks in advance!


Solution

  • It looks like you're most of the way there... but the particular sequence isn't making the stepper step. With the L293D, the IO pin values are essentially what we drive the coil with, and I guess here coil_A and coil_B are the two coils with 1 and 2 being the ends of them (two coils is typical in a bipolar stepper motor). So the states you've applied are:

    1100  == ==   No power
    0110  << >>   both coils energised
    0011  == ==   No power
    1001  >> <<   both coils energised the opposite way
    

    That doesn't provide a directional guide for the motor, and will most likely just lead to vibration. Try a full step pattern, where you flip the direction of one coil at a time:

    fullsteps = ((0,1,0,1), (0,1,1,0), (1,0,1,0), (1,0,0,1))
    
    for i in range(0, steps):
        for pattern in fullsteps:
            setStep(*pattern)
            time.sleep(delay)
    

    The next variant one might try is half stepping, where we let the coils take two steps to transition from one direction to another:

    halfsteps = ((0,1,0,1), (0,1,0,0), (0,1,1,0), (0,0,1,0), 
                 (1,0,1,0), (1,0,0,0), (1,0,0,1), (0,0,0,1))
    

    Upon second glance, that is in fact the pattern used in your first link (just below the comment "adjust if different" - just reversed and two half-steps out of phase with the version here).

    At all times at least one coil is powered, keeping the motor from falling into an unknown position.

    If we compare the tables shown in http://www.nmbtc.com/step-motors/engineering/full-half-and-microstepping/ their tables use the order A B ~A ~B, while your code used A ~A B ~B. So another way to make the code work should be just swapping B and ~A:

    def setStep(w1, w3, w2, w4):
        GPIO.output(coil_A_1_pin, w1)
        GPIO.output(coil_A_2_pin, w2)
        GPIO.output(coil_B_1_pin, w3)   
        GPIO.output(coil_B_2_pin, w4)