Saturday 21 March 2015

Twins

In my last blog, I set myself 3 challenges..

  Get a stepper motor to run in reverse
  Demonstrate precision control of the armature position
  Get two motors running independently, from a single RPi

I did a bit of googling and found that the motors I am using draw a maximum of 92mA under full load, and that includes power used by the driver board. The theoretical maximum current draw for two motors running concurrently is therefor 184mA. Given that the RPi has a safety fuse rated at 750mA, this leaves just over half an Amp to run the RPi itself. I don't want to push my luck, so for the dual-motor experiment I'm going to use an Ethernet connection rather than WiFi (the WiFi dongle is USB powered which means more load on the fuse).

Anyway, on to challenge 1...

Get a stepper motor running in reverse

While this sounds an easy thing to do, it's not quite that straightforward when dealing with arrays, especially multi-dimensional ones. After a few tries (and fails), I worked out the simplest way of doing this is by having two separate control lists, one for forward and one for reverse. We then just run the forward control list for an amount of time, then switch to the reverse control list, then back again etc...

Here's the modified control program which now allows forward and reverse control.

click to enlarge

You can see the two lists, the second one just being a reverse of the first. It is actually possible (and more efficient) to have a single list and have the control pointer run backwards, but for the sake of simplicity, I went with two lists. However, we might need advanced control of a list position pointer for the third challenge, which is something I look forward to taking on*.
[*Not really, it's giving me cold sweats thinking about it]

You might have noticed the number 512 there in those loops. There's a reason I used that particular number and it's explained in the next section, but for now here's a video of the forward/reverse control in action...

Forward and reverse motion

Next...

Precise control of armature position

Probably the best way of demonstrating this is to have the motor stopping and starting at specific points, something a normal AC or DC motor simply couldn't do. Well it could if you used a power control inverter and some method of obtaining the shaft rotational position (a pulse counter or high resolution tachometer or something), but even then it it's not hugely accurate.

First, I did a little research to find out exactly how many steps were used to make the output shaft of our stepper motor rotate a full 360 degrees. I should mention here that the shaft sticking out of the motor unit isn't the armature. That would give a pretty awesome rotational speed, but wouldn't have enough torque to be of any use. The units are geared down internally in order to give us usable rotational power, but at the expense of speed. It turns out that 512 complete turns of the armature results in 1 single turn of the output shaft with a speed variation ratio of 1:64. That basically means the output shaft is spinning 64 times slower than the actual armature.

So now we know that if we send 512 sequential steps to the motor, the output shaft will rotate once. (Remember the number 512 from the control loops in the earlier section? That's why I used that particular number.) Breaking this down, we could send it 256 steps to make it do half a turn. It follows that sending it 128 steps will make it do a quarter of a turn - or 90 degrees. I think you get the idea.

So I modified our basic Python program to do a few things differently. Firstly, it's now looking out for when I manually stop the program running, and if I do, it "cleans up" the GPIO pins before quitting. This just means it sets all the pins to a logical low state, it's a good habit to get in to. Secondly, instead or running through a never-ending loop, the controlling part of the program actually counts up to 128 (remember 128 steps equates to a 90 degree turn of the motor output shaft). Finally, there is a delay statement which makes the program sit idle for a second before running the count to 128 again.

Quarter turn program - click to enlarge

The result of these changes can be seen in the video below. The motor shaft turns 90 degrees, waits a second, turns another 90 degrees etc... and carries on until I stop it manually. Try getting that kind of positional control out of a normal motor. Not gonna happen easily.

Quarter-turn steps

Finally...

Two stepper motors running independently, controlled by a single Raspberry Pi

OK, here's where things get tricky. I'll admit, I had a pretty decent idea of how to complete the first two challenges even before I started them, for this one I'm winging it.

Before we start, here's a drawing of how the dual driver boards are physically wired to the RPi.
GPIO wiring - click to enlarge

Each driver board is supplied power from the 5V rail (and Ground) of the RPi. I simply used an additional four GPIO pins to control the second motor. Before we get into independent motor control, we need to test the RPi can actually drive two motors, so here's the code to do that...

 Dual motors - click to enlarge

You can see that I've assigned a second set of GPIO pins as outputs, and initialised them. Later in the program, in the control loops, I've just added an extra line so the control signals are sent to the second motor as well as the first. That's the absolute simplest way to test if something works or not, send it known good control signals, and see if it mirrors the first device.

So even though that modified code will run two separate motors, they aren't being controlled independently, they are basically just receiving the exact same signals, and will do exactly the same thing. There is no way to tell one motor to do something, without the second motor doing exactly the same. Anyway, at least it worked, and here's the video to prove it...

Please ignore my water bill in the background...

So now we know the hardware is physically capable of driving two motors, and those motors are controlled from two separate sets of GPIO pins, it's "just" a case of writing some Python code to allow them to be individually controlled. Here goes...

Code to control 2 motors independently

Well, after a bit of head scratching and some trial and error, some code finally emerged that allows the two motors to run independently of each other. I decided early in the process that it's a lot simpler to stick with separate sequence lists for forward and reverse rather than having a bidirectional program pointer. I know that time is coming, it's just not yet. I've commented the code itself, so I won't go into detail about what each line does, but this is the general idea...

The RPi picks two random numbers for each motor. The first of these numbers will define how many steps the motor will take. Remembering that with these particular motors 512 steps equals one complete revolution of the output shaft, I limited the number to be no more than 256. This is purely for demonstration purposes, so we have to wait less time before a potential direction change. Which brings me on to the second random number. This can only be one of two possible values, and it decides which direction the motor will run in. Basically, there is an "if" statement in the motor control loop that can take one of two paths, depending on which number was chosen.

I'd like to thank my friend David Somers for explaining to me how the random number generator works in Python :)

Finally, a (very dodgy quality) video of the motors running.

Random...

As you can see, they run for a random time in a random direction. I apologise if you can hear my daughter laughing in the background, she's recently discovered the wonders of red wine.

So, now I know the RPi is capable of running two motors, and I am capable of writing code to control them independently of each other. Whatever next, a robot?..


No comments:

Post a Comment

Please leave a comment...