Raspberry Pi running 4 5V stepper motors from GPIO

I’ve been playing around with some stepper motors with driver boards that I bought from eBay. They have a lot of potential and I’m planning to use them on an astronomy project… but more on that later.

The motors were £1.66 each including postage. Not the fastest delivery ever but then they were from Hong Kong.

The actual boards which arrived were much nicer than those pictured on the eBay lot and were manufactured by LC Technology. Below is a picture of the actual board and the accompanying stepper motor and cable and here’s a link to the LC Tech page about the board. The stepper motors are all 5V so can be run off the Raspberry Pi’s 5V power supply pin.

a5146d48-6ea5-4935-8284-ee63545f6aad

450px-Stepper_motor
Here’s a video of the boards in action:

And here’s a still just in case you don’t want to sit through the video! 🙂
SAMSUNG

I’ve built this on a breadboard connected to the GPIO using a breakout board from HobbyTronics. It’s almost identical to the Pi Cobbler but has a nifty power light and 3.3v regulator on board. Plus they’re based in the UK, which helped with the postage at the time.

As you can probably see, each motor board is run from 4 GPIO pins plus 5V and Ground. I needed male-to-male bell wire for the 4 GPIO connections and male-to-female jumper wires for the power and ground pins that stick up from the board. For those replicating this experiment, your four GPIO wires connect to the pins on the board labelled IN1-IN4. I’ve yet to find out what the other pins do, and there certainly are a lot of them! Note: the control boards are too wide to plug completely into the breadboard but fortunately you don’t use all the pins at one end, so all mine are hanging over the edge. This isn’t great as they tend to pull the breadboard apart a little, but it’ll do for this experiment.

The stepper motors are then connected to the boards using a supplied cable. When the motor is working, the LEDs on the control board light up (in sequence, but they’re going so fast in the video above that you can’t really tell that).

I’ve put the Python code for this experiment on GitHub. The main Motor class was taken from work done by Stephen Phillips on his blog. Here’s his original post. My code is available at https://github.com/recantha/stepper-pi

There is a main driver script – test-all-motors.sh – which fires off 4 parallel runs of the test-motor.py script with 4 different sets of 4 GPIO pins.

For those interested, I am using the following physical pins as control pins for the motors: 8,10,12,16 and 18,22,24,26 and 3,5,7,11 and 15,19,21,23. Some of these pins have alternate uses (for example serial tx and rx) but it was necessary to use them as general output pins to get the 16 pins I needed.

What’s next?

Well, at the moment the motors each drive a bit of paper, just to show the movement. However, they have a reasonable amount of torque. So, I’m hoping to use them to control, hopefully on multiple axis, a webcam and eventually an official camera module. This will form the main part of the hardware for an upcoming astronomy project. The code for this is starting to be built as a GitHub repository.

11 comments for “Raspberry Pi running 4 5V stepper motors from GPIO

  1. I’ve been testing Stephen’s code with a single steeper configuration and have found that several consecutive move_to angle requests suffer from steps being missing due to the reset to 0 of all pins before the bigsteps for loop in the move_cw and move_acw functions. Eliminating the reset, the motor is able to execute multiple move_to angle requests and get back to the zero position without inaccuracies… Have you experienced something similar or am I getting it wrong?
    And thanks for the post!

    • Hi. I had noticed that it wasn’t optimal. I’ve now switched to focussing just on the move_cw and move_acw rather than the move-to-a-specific-angle because of the type of project I’m doing.

    • Hi JOrtiz
      I’m having similar inaccuracy problems as you – could you demonstrate your solution by showing some ‘corrected’ code. I’m having trouble spotting what changes to make.

      Thanks
      Chris

      • Hi Chris,
        Apologies for the late response. I’ve been away…

        Hope you find this useful:

        #####################################################
        #!/usr/bin/env python

        # This code was originally written by Stephen C Phillips.
        # It is in the public domain, so you can do what you like with it
        # but a link to http://scphillips.com would be nice

        # J Ortiz have modified the code to sort out apparent inaccuracy problem as per comment above. May 2013.
        # J Ortiz: Movement is limited to position 3072 out of 4000 for the application this code is designed for. This restriction could be removed from the code for other purposes.
        # J Ortiz: Caveats as usual, this works nicely and accurately for my application. You should make sure this is going to work in your system without causing any damage before you try. I take no responsibility for any damage this might cause.
        # J Ortiz: Added simple command based interface to define required position (new).
        # J Ortiz: It uses pickle to save current position on file so that it has memory and it can return to position 0 even after a switch off.

        # It works on the Raspberry Pi computer with the standard Debian Wheezy OS and

        from random import randrange
        from time import sleep
        import argparse
        import pickle
        import RPi.GPIO as GPIO

        # Use BCM GPIO references instead of physical pin numbers
        # BCM GPIO references equivalents: GPIO24, GPIO25, GPIO8, GPIO7
        #GPIO.setmode(GPIO.BCM)

        # Use physical references
        # Physical pins to use 18,22,24,26
        GPIO.setmode(GPIO.BOARD)

        class Motor(object):
        def __init__(self, pins):
        # Define advanced sequence
        # as shown in manufacturers datasheet
        self.StepCount = 8
        self.Seq = []
        self.Seq = range(0, self.StepCount)
        self.Seq[0] = [1,0,0,0]
        self.Seq[1] = [1,1,0,0]
        self.Seq[2] = [0,1,0,0]
        self.Seq[3] = [0,1,1,0]
        self.Seq[4] = [0,0,1,0]
        self.Seq[5] = [0,0,1,1]
        self.Seq[6] = [0,0,0,1]
        self.Seq[7] = [1,0,0,1]

        #SeqACW = Seq[::-1]
        # Choose a sequence to use

        self.pins = pins
        self.deg_per_step = 5.625 / 64
        self.steps_per_rev = int(360 / self.deg_per_step) # 4096
        try:
        with open(‘mpos.ini’): pass
        except IOError:
        f=open(‘mpos.ini’,’w’)
        pickle.dump(0,f)
        f.close()
        f=open(‘mpos.ini’,’r’)
        self.pos = pickle.load(f)
        f.close()
        self.seqpos = self.pos % 8
        for p in self.pins:
        # pfio.digital_write(p,0)
        GPIO.setup(p, GPIO.OUT)
        GPIO.output(p, 0)
        #Initialise from latest/stored position
        for i in range(0,4):
        # pfio.digital_write(self.pins[i],self.Seq[self.seqpos][i])
        GPIO.output(self.pins[i],self.Seq[self.seqpos][i])

        def zero_pin(self):
        for p in self.pins:
        # pfio.digital_write(p,0)
        GPIO.output(p, 0)

        def _set_rph(self, rph):
        “””Set the turn speed in RPH.”””
        self._rph = rph
        # T is the amount of time to stop between signals
        self._T = (60.0 * 60.0 / rph) / self.steps_per_rev

        # This means you can set “rph” as if it is an attribute and
        # behind the scenes it sets the _T attribute
        rph = property(lambda self: self._rph, _set_rph)

        def move_to(self, target_pos):
        # Make sure there is a 1:1 mapping between angle and stepper angle
        steps = target_pos – self.pos
        print “moving ” + `-steps` + ” steps to get to ” + `-target_pos` + ” ” + `self._T`
        if target_pos < self.pos:
        self._move_cw(-steps)
        else:
        self._move_acw(steps)
        # self.pos = -target_pos

        def _move_acw(self, steps):
        for i in range(steps):
        self.seqpos += 1
        # If we reach the end of the sequence
        # start again
        if (self.seqpos==self.StepCount):
        self.seqpos = 0

        # Wait before moving on
        sleep(self._T)
        for pin in range(0, 4):
        xpin = self.pins[pin]
        if self.Seq[self.seqpos][pin]!=0:
        # pfio.digital_write(xpin,1)
        GPIO.output(xpin,1)
        else:
        # pfio.digital_write(xpin,0)
        GPIO.output(xpin,0)

        # Save new position in mpos.ini file
        f=open('mpos.ini','w')
        #pickle.dump(self.pos+i+1,f)
        pickle.dump(self.pos+steps,f)
        f.close()

        def _move_cw(self, steps):
        for i in range(steps):
        self.seqpos -= 1
        # If we reach the end of the sequence
        # start again
        if (self.seqpos 3072:
        pos = 3072
        print “Movements are limited to range (0, 3072)”
        if pos < 0:
        pos = 0
        print "Movements are limited to range (0, 3072)"
        m.move_to(-pos)
        m.zero_pin()
        GPIO.cleanup()

        ##################################################

        Kind regards,
        Jose Ortiz

  2. Hi,
    I followed the following tutorial
    http://www.raspberrypi-spy.co.uk/2012/07/stepper-motor-control-in-python/

    I have got the stepper motor to turn continuously in one direction and then in reverse. I have looked at your file test-motor.py . In this file where do you assign the 4 GPIO for the stepper motor. Basically I want the stepper motor to turn 90 degrees in one direction and then wait for a action and then turn 90 degrees
    back to the original position.

    Would you be able to point me in the right direction so I can get my stepper motor to turn a specified amount of degrees.

    I am using the 5V Stepper Motor With ULN2003 Board.

    Thanks.

    • “Probably” is the best answer I can give you. With sufficient circuitry and power supply, I’m sure you could hack it to do so.

  3. Hi-
    Cool project!
    I’m Just starting out with the RPi 3 and wanted to build a project to run 3 stepper motors. I purchased a 4 motor controller shield with 4 motor drivers (A4988). Do you know how I would figure out how to connect the expansion board up to the RPi to run the motors from the expansion board? Controlling the simple single motor is pretty straightforward, but the extension board is a whole new world. Here’s what I’m using: https://smile.amazon.com/gp/product/B07DFK6ZJW/ref=ox_sc_act_title_1?smid=A28ZWXW3ZSVNZU&psc=1 I’m using this product because it could handle the slightly higher amperage than the requirements of my stepper motors (12v, 1.5A)– which also happen to be for 3d printers.
    Thanks for the pointers!

    • Hi Tad. I’ve taken a look and I’m sorry but I don’t have a clue how you would hook that up! 🙁 Try asking on the Raspberry Pi forums – give them as much detail as you possibly can and hopefully someone will be able to help!

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.