Stepper Motor Control In Python

Having played with LEDs, switches and buzzers I felt the natural next step was playing with a stepper motor or two. This might form part of an idea I had to create an automated stop motion animation “turn table” for rotating and photographing objects.

There is a huge selection of motors to buy but I decided to experiment with a 28BJY-48 with ULN2003 control board.

The reasons I chose this device where :

  • It is cheap
  • Widely available from both overseas and UK sellers
  • Easy to obtain with a controller board
  • Small but relatively powerful
  • Runs on 5V
  • Easy to interface

I ordered two from “4tronix_uk” on eBay and they arrived the next day. There are additional details in the Stepper Motor 28BJY-48 Datasheet

Interfacing With The Pi

The motor connects to the controller board with a pre-supplied connector. The controller board hasĀ  4+2 pins that need to be connected to the Pi header (P1).

  • 5V (P1-02)
  • GND (P1-06)

and

  • Inp1 (P1-18)
  • Inp2 (P1-22)
  • Inp3 (P1-24)
  • Inp4 (P1-26)

The P1-XX references above represent the Pi header pins I used. These are defined in the Python example below in the StepPins list so if you use different pins be sure to update the Python list as well. You can use other GPIO pins if required just remember to update your Python script.

To rotate the stepper motor you provide a sequence of “high” and “low” levels to each of the 4 inputs in sequence. By setting the correct sequence of high and low levels the motor spindle will rotate. The direction can be reversed by reversing the sequence.

Python Script

Here is a copy of the script I used to rotate the stepper motor. It uses version 0.2.0 of the RPi.GPIO library and defines a 4-step and 8-step sequence.

#-----------------------------------
# Name: Stepper Motor
#
# Author: matt.hawkins
#
# Created: 11/07/2012
# Copyright: (c) matt.hawkins 2012
#-----------------------------------
#!/usr/bin/env python

# Import required libraries
import time
import RPi.GPIO as GPIO

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO signals to use
# Pins 18,22,24,26
# GPIO24,GPIO25,GPIO8,GPIO7
StepPins = [24,25,8,7]

# Set all pins as output
for pin in StepPins:
  print "Setup pins"
  GPIO.setup(pin,GPIO.OUT)
  GPIO.output(pin, False)

# Define some settings
StepCounter = 0
WaitTime = 0.5

# Define simple sequence
StepCount1 = 4
Seq1 = []
Seq1 = range(0, StepCount1)
Seq1[0] = [1,0,0,0]
Seq1[1] = [0,1,0,0]
Seq1[2] = [0,0,1,0]
Seq1[3] = [0,0,0,1]

# Define advanced sequence
# as shown in manufacturers datasheet
StepCount2 = 8
Seq2 = []
Seq2 = range(0, StepCount2)
Seq2[0] = [1,0,0,0]
Seq2[1] = [1,1,0,0]
Seq2[2] = [0,1,0,0]
Seq2[3] = [0,1,1,0]
Seq2[4] = [0,0,1,0]
Seq2[5] = [0,0,1,1]
Seq2[6] = [0,0,0,1]
Seq2[7] = [1,0,0,1]

# Choose a sequence to use
Seq = Seq1
StepCount = StepCount1

# Start main loop
while 1==1:

  for pin in range(0, 4):
    xpin = StepPins[pin]
    if Seq[StepCounter][pin]!=0:
      print " Step %i Enable %i" %(StepCounter,xpin)
      GPIO.output(xpin, True)
    else:
      GPIO.output(xpin, False)

  StepCounter += 1

  # If we reach the end of the sequence
  # start again
  if (StepCounter==StepCount):
    StepCounter = 0
  if (StepCounter<0):
    StepCounter = StepCount

  # Wait before moving on
  time.sleep(WaitTime)

In this example the wait time is set to 0.5 seconds. To make the motor turn faster you can reduce this value. I found I could reduce it to 0.004 before the motor stopped working. If the script runs too fast the motor controller can’t keep up. This performance may vary depending on your motor and its controller.

The 4 step sequence is faster but the torque is lower. It’s easy to stop the rotation by holding the motor spindle. The 8 step sequence is slower but the torque is much higher. For my turntable application I prefer the torque over speed so I will be using the 8 step sequence.

As with all Python scripts that use the GPIO library it needs to be run using “sudo” :

sudo python stepper.py

Press Ctrl-C to quit.

You can now control a stepper motor using a Raspberry Pi and some Python script. Add another motor and you’ve got the beginnings of a small robot!

This entry was posted in General and tagged , , . Bookmark the permalink.

8 Responses to Stepper Motor Control In Python

  1. David says:

    As I understand it, the torque is higher when you select two inputs because you have twice the number of coils “activated”. If this is the case, then surely your 8 step sequence actually does High Torque turn (2 inputs), Low Torque turn (1 input), High Torque turn (2 inputs), Low Torque turn (1 input)…

    I could be very wrong, but think you may not be using the entire torque available.

    • Matt says:

      The 8 step sequence is the official one in the datasheet. The 4 step version was just one I tried because it was easy to implement in my Python script. I think what you are saying is correct but I think that’s just the way you have to drive the motor.

  2. Can you connect more than one motor to the Pi?

    • Matt says:

      Yes you can. As long as the 5V supply can provide the current and you’ve got 4 GPIO outputs to drive each motor you can add more. Technically you could add 4 using 16 GPIO pins. With a 1A rated supply you’ve got 300mA to play with on the 5V pin once the Pi has taken it’s 700mA.

  3. Stu says:

    Thanks for this post, I was able to get my stepper motor spinning in next to no time. I found that I needed to add a few 1/100ths of a second WaitTime or I got buzz but no spin. Probably a current thing, but for now I’m just glad to have graduated beyond flashing LEDs.

    • Matt says:

      I think stepper motors sometimes need a bit of time to complete a “step” before the next sequence is applied. I’m wondering if I might need to re-introduce a small delay now that the new version of the RPi.GPIO library (0.3.1a) is much faster.

  4. Stu says:

    For what it’s worth, this main loop does away with the expensive array lookups. It must be more efficient because I need another 0.001 of delay ;-)

    #alt. loop
    mask = 3 # set to 1 or 3
    while True:
    # print mask
    GPIO.output(24,mask & 1)
    GPIO.output(25,mask & 2)
    GPIO.output(8, mask & 4)
    GPIO.output(7, mask & 8)
    mask = (((mask & 1)<>1
    time.sleep(0.003)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>