My original Raspberry Pi (Model B) is now acting as an awesome media centre downstairs on the main TV, streaming 1080p HD movies across my home network via an amazing piece of (free) software called RaspBMC. This is basically a heavily modified version of XBox Media Centre which has been adapted to run on the RPi, and it runs really well (on a Model B Rev 2 at least). The RaspBMC software is about to have a major overhaul to a completely new framework called OSMC which should provide an even more awesome experience, but for now RaspBMC works perfectly.
My Raspberry Pi 2 is currently running something called RetroPie, which is a nifty bit of software that runs in conjunction with the Emulation Station front end to provide a superb little emulator of vintage games. I'm currently running this on a 42" TV using an Xbox 360 controller but I plan to acquire a 3.5" tft and cram it all into an old handheld system, to make a portable games machine that can emulate all the old classics such as ZX Spectrum, Commodore 64, Amiga, SNES, etc.. But that's for a different project (and a different blog post).
So that just leaves the Raspberry Pi Model B+. This is the unit I now use for messing about with. I haven't been doing much lately, so rather that let my hobby fade, I decided to try something new. I'd heard of stepper motors, used them in work in fact, but I had no real idea of how they functioned or were controlled. So off I trotted to eBay and blagged a few small stepper motors for experimentation. They weren't too expensive, so it's not the end of the world if I blow them up. These are the ones I bought, but that link might not last forever, so for reference they are "5V 28BYJ-48 4-Phase Stepper Motor with ULN2003 Driver Board". They were just under £4 each with free delivery.
Stepper motor and driver board
The above picture shows what you get. How they can make something like that, offer free delivery, sell it for £4 and still make a profit is beyond me, but I digress.
Anyway, how to get this thing working? And more importantly, how to get it controlled via the RPi?
After some research (you don't get instructions with the motor) I found that there are a few different types of stepper motor, and also a few different ways of controlling them. For the sake of reference (and to keep this post relatively short) I'm only going to explain how I did it with this particular model.
So the driver board needs a permanent 5V supply. Perfect, we have a 5V rail on the RPi, so we can use that as long as the required current isn't too high. The 5V rail is protected by a 750mA fuse, but that fuse also protects everything else on the board, so we have to be careful not to overload it.
As for actual motor directional control, this is where things get interesting. Unlike a normal motor where you just apply power and off it goes, stepper motors are built with a series of coils that need to be activated in a certain sequence to generate the magnetic field needed in order to turn the armature. (The armature is the actual part that spins). Having control over these individual coils means we can have very accurate control of the angular position of the armature. In fact, we can move it in tiny little steps - hence the term 'Stepper Motor'.
The driver board (the square bit with the microchip on in the above picture) allows us to send a low voltage signal which is in turn used to activate a gate which allows a higher voltage through the chip to energise a coil in the motor. Notice I said coil, not coils. This particular motor has four coils, so we have four inputs on the driver board, one for each coil.
Half-stepping and Full-stepping
Before I go any further, take a quick look at this diagram...
As you can see, there are four coils, each with an input (A, B, C & D) and they all have a common return. These 5 wires are the 5 you can see running from the driver board to the motor in the first picture. The armature in the middle is the part that spins. Without going into the theory of how electric motors work, here is the (very) basic premise of what makes this motor spin...
The armature is a permanent magnet, and as you know, magnets attract each other if the polarity is opposing. Also, when you pass an electric current through a coil which is wrapped around a ferrous bar (or torus, or any shape really) a magnetic field is generated in that medium. So, referring to the above diagram, if we generate a magnetic field in coil 1, then the armature will spin around and align itself with that coil. Then, if we turn the power off coil 1 and energise coil 2, the armature spins around and aligns with that one. I think you get the picture.
Please note that this is a very simple representation of how a stepper motor works. In reality, the armature has a a number of magnetised areas (16 in the case of our motors) which align with "teeth" that are magnetised on the stator (the part that houses the coils), but that's way beyond the scope of this blog. Plus I need a cuppa just now.
Anyway, energising the coils in the correct order causes the armature to spin. Now there is a slight twist on this. (See what I did there?) We can energise the coils in the order A > B > C > D and the motor would indeed work. It does, I've tried it. As you can probably guess, this is called "Full Stepping" and it means the armature "points" to one coil, then the next, then the next etc.. This gives us a reasonable output speed, but not much turning force (Torque). We can get much better torque, at the expense of rotor speed, by using a method called "Half Stepping".
"Half Stepping" is where we energise coil 1, then coils 1 AND 2, then coil 2, then coils 2 AND 3, then coil 3 etc... Basically creating an extra point between coils for the armature to align with. This works because of the way a magnet will align itself mid-way between two identical fields. Physics, or something.
So now obviously we need eight steps instead of four, to make our armature complete a revolution. This won't be a problem as we are going to use the Raspberry Pi to energise the coils in the right order, by means of a Python program controlling our old friends, the GPIO pins. We connect 4 GPIO pins to the 4 inputs on the stepper motor driver board and we're ready to do some coding. Note in the following picture, I've massively over-complicated things by using a piece of breadboard as a junction box. I didn't have any female to female jumper leads, so had to join some female to males. Anyhow, trust me there are only 6 wires between the RPi and the stepper driver; 2 power and 4 control.
As usual, click for a larger image
So onto the code. The easiest (although not only) way to apply power to certain GPIO pins in a specific order is by use of a list. We just scroll through the values of a list, if it's a 0 we turn the GPIO pin (and therefor the motor coil) off, if it's a 1 we turn the GPIO pin (and motor coil) on. When we get to the end of the list, we just jump to the top and start again. This will keep our motor rotating indefinitely. Here's the code...
Click for a larger view
So for those interested, a breakdown of the code..
The #import libraries section just grabs the required libraries to save us having to write code which has already been written by someone a lot cleverer than me. We need the 'time' library because we use a delay to control how fast our motor will run.
The next three sections set up the RPi, telling it we want to use the BCM standard for addressing the GPIO pins, set up a small list to tell our program which physical pins to use in this case, sets them all up for output rather than input, and then sets all their values low.
The #define sequence area of the program is the main coil control list I was talking about. If you look at the columns of 0's and 1's, imagine the leftmost column representing coil A on the motor, the second column represents coil B and so on. If you look carefully, you'll see it's actually a list inside another list. Hmm, hard to explain. The main list (called Seq) has 8 items. Each of those items contains 4 further items which are the 0's and 1's. This is known in most programming languages as a multi-dimensional array, but I might start sounding like I know what I'm on about, so I'll stop there.
Anyway, the #main loop part is, strangely enough, the main loop of the program that actually causes stuff to happen. More on that in a sec.
Finally, the #cleanup when done part just resets all the GPIO's and is good practice when using input/output of any kind on a microcontroller. Having said that, eagle-eyed readers will notice that this part never actually gets executed as the main loop is set to run continuously. The reason for this is because I only wrote this program to demonstrate this single blog post, it will be expanded as time goes on to incorporate more functions etc.
So that main loop eh? Complex? Not really. The "while True" line just means "keep going forever".
Next we run a 'for' loop using a variable called 'halfstep' that counts up from 1 to 8.
Within that loop, we run another 'for' loop using a variable called 'pin' that counts up from 1 to 4.
This next line is the meat and potatoes of it all...
...that just basically sets the right GPIO pin to the right value, depending on what point in the loops the program is. Remember 'pin' is counting from 1 up to 4, for each iteration of 'halfstep' which itself is counting from 1 up to 8. Sounds complicated to the uninitiated but nested loops are common practice in any programming language.
The 'time.sleep' line is just used to put a small delay between activating the GPIO pins. If you send the signals too fast, then cheap motors can't react in time and all hell breaks loose.
Here's a short video of it actually running...
...and one of it slowed down so you can see the LED's on the driver board representing the outputs from the RPi GPIO pins. Each LED is connected to one coil on the motor stator. The armature doesn't appear to be spinning at all in this video, but trust me it is. I had to slow the video down so much (to show the LED sequence) that the rotor appears stationary.
So that's probably one of the most complex blog posts I've made in a while. Next time I'll be making the stepper motor run in reverse, showing how we have precise control over armature position, and if all goes well and I don't burn the house down, getting two steppers to run independently on one Raspberry Pi.