This is a guide to help with developing software for stepper motors. There are already some stepper motor tutorials available but these concentrate mainly on the physical properties of stepper motors and only glance briefly at actually controlling them.
Its often thought best to buy a commercial stepper motor driver, but what happens if you dont want to pay for one or just want to create your own direct software? Thats what I hop to address here.
Before you continue on this tutorial I suggest that you do read the other stepper motor tutorials so you can better understand what you are trying to control and also understand the step patterns involved.
The setup I am using is:
1.5 degree bipolar stepper motor
L298 dual h - bridge
Your setup might differ but the software techniques are easily replicated for other setups
Basic Control Methods
First of all it is easier to define the pins you will be using to control your stepper motor:
#define mout1 PORTDbits.RD0
#define mout2 PORTDbits.RD1
#define mout3 PORTDbits.RD2
#define mout4 PORTDbits.RD3
If you have read the other tutorials, you will no doubt have seen the different methods of control. Wave, Full Step and Half Step, I like to implement these as a 3 dimensional array:-
//phasetype:- 0 = wave ; 1 = full step ; 2 = half step
For wave and full step mode, we should only need to supply 4 elements for the 2nd array list but to integrate half step mode into the array we need to double the sequences up for wave and full step modes. This means that we need to increment these two modes by 2 for each step.
so in order to use the array you will need to do something like this:
mout1 = phaseArray[*phasetype*][*phaseposition*];
mout2 = phaseArray[*phasetype*][*phaseposition*];
mout3 = phaseArray[*phasetype*][*phaseposition*];
mout4 = phaseArray[*phasetype*][*phaseposition*];
mout refers to the pins we have defined earlier
*phasetype* refers to the 1st array dimension, if we set this as 1 then we will be operarting with full step mode
*phaseposition* refers to what step cycle we are currently on. Incrementing this by 2 will send us to the next step cycle in the array.
the number in the 3rd array dimension just refers to the port state for the current cycle.
so looking at the array defined above:
mout1 = phaseArray;
mout2 = phaseArray;
mout3 = phaseArray;
mout4 = phaseArray;
would produce the following:
mout1 = 1
mout2 = 0
mout3 = 1
mout4 = 0
Here is a full program that uses the array above to control a stepper motor with continuous forward motion
The program controls the steps at 5000us Lets try it out
Its working, but its a bit slow. Lets try with a 1500us step delay intead
Its better but still a bit slow. Lets try it with a 500us step delay
Whoops, it stalls. It wont move at all at 500us. Is 1500us the fastest we can go then?
Well the answer is no. We can move a lot faster.
Stepper motors have to start slow in order for the coils to catch. Once its spinning, you can slowly ramp up the speed.
Notice in the videos how the motors are moving bit they are really jittery, they are suffering from mechanical resonance at a slow speed.(more on this later).
Follow to the next page to see how to drive your motor faster.
Ramping Up The Speed
We know from the previous page that if we try to start the stepper motor with fast pulses then it just sits there and hums away not turning.
We need to start the stepper off slowly and gradually increase the speed of the steps (ramping up).
The following C file is the same as the previous. The only difference is the delay between pulses decrements until it the delays between steps are 200us and then it just stays stepping at that level.
So Lets Test It Out
As you can see, the stepper motors speed increased well beyond what was capable in the basic control method. we couldnt get the stepper to move at all at 500us phase changes and now its spinning at 200us changes.
This seems perfect at first until you realise the downside. There is a playoff between speed and torque, the faster your stepper motor is driven to, the lower torque you can get from it. this is because when the phases change, the voltage is being reversed in the coils so the incoming current has to fight against the collapsing field built up by the previous phase. The faster your motor spins, the less time it has to push against the existing current and re-energise the coil. Choosing a faster more efficient h-bridge can help this as can driving your stepper above its rated voltage (a current limiting resistor should be used for each stage) but you will always lose some torque.
An upside to ramping up your steppers is that the mechanical jitter becomes less noticeable. when the motor spins faster the mechanical resonance swaps out for electrical resonance causing a high pitched humming or ringing noise.
This was noticable when i tested it but i dont know how well it came out in the video.
Okay so now weve seen how to use a stepper motor to go forwards continuously, but that isnt what stepper are about. The next page shows how to control the stepper motors positionally.
This page is going to add a simple function to our program that allows the stepper motor to be controlled positionally.
Notice how the 'struct' called motor has a value called stepsleft that we initialised as 0 but havent used so far. We want to make a function that allows us to move the motor a predefined number of steps.
The motors used have a 1.5 degree stepping angle this makes 240 steps for each full revolution (360degrees / 1.5). so when we make the function, a good test will be to tell it to step 200 times and see if it makes a full circle.
The motors that i am using come from sparkfun and are supposed to have a step angle of 1.8 degrees meaning that I should only need 200 steps per revolution. Trying this I was consistantly 1/6 of a full circle out, so keeping the coils energised meant that I could maually rotate it and count how many steps i was out. This turned out to be 40 steps and 1.5 x 240 = 360 so I think the datasheet must be the wrong one (the motor is a generic case style with no markings so its difficult to tell). Its important to know the correct amount of steps or you are going to build up massive error along the way.
For this example, speed ramping isnt used. It just moves the motor at a slow speed.
Here is the new program:
The program has changed a bit, Weve added the ability for the motor to go forwards or backwards.
If we call moveSteps(240); the wheel should do a full revolution forwards
if we call moveSteps(-240); the wheel should do a full revolution backwards
Lets test the forward movement
Now im happy with this part of the program, its time to add speed ramping. The next page describes a trapezoidal ramping technique
When I ramped the motors up to a high speed earlier, the program just assumed the motors kept going and never happened to stop. If we were to combine this ramping with the positional program then the motors would ramp up to speed and then just stop when the specified number of steps have passed.
Unfortunately, its not that simple.
If I sent the motors going at high speed and just stopped them, the momentum we carry them forwards and back emf would make it difficult for a coil to energise correctly. To put it simply, if you just try and stop the motor dead from high speed it will keep going for a while and you lose steps and accuracy.
To combat this, we can ramp the stepping speed back down just like we ramped it up. This is known as a trapezoid ramping profile as in the picture below.
Time is along the bottom and pulse frequency is on the left.
To implement this we have to do the following:
set a variable for the minimum speed of the motor
set a variable for the maximum speed of the motor
set a variable for the value of the required number of steps divided by 2
set a variable for the current speed of the motor (we can use the delay time)
while the current speed is lower than the maximum speed and the number of steps left is greater than the total number of step divided by 2 we are going to ramp up the speed.
when the speed reaches the maximumspeed or the number of steps left equals the total number of steps divided by 2 we are going to continue at the current speed until the number of total steps divided by 2 minus the number of steps left equal 0
we now decrement the current speed until either we reach the minimum speed or there are no steps left to perform.
Here is the C file to add trapezoidal ramping
There is really very little added, just a couple more variables in the struct, some initialising in the setupMotor(), some initialising in moveSteps(), and also some if's in moveSteps()
I have alse changed the moveSteps() call to 12000 steps so we can see it ramping up to speed - travelling at speed - then ramping back down again.
You can adjust the ramping speeds etc.. if your motors are capable of it. Also I made the ramping down become equal to the ramping up, you may find that you can ramp 1 way faster than the other, this was just an overview of a basic technique that can be built on.
See the next page for improving ramping technique
As you saw in the previous page, a trapezoidal stepping profile can increase the speed of your stepper motor considerably. But does it achieve the motors potential?
Well that depends on the ramp up gradient, a steep gradient will stall the motor at a relatively low speed. But using a persistant shallow gradient will take a lot longer to increase speed aswell as creating a lot of jitter at the lower speeds.
If we could calculate a sinusoidal increase gradient rather than just a straight linear ramp, this would allow us to achieve even greater speeds.
Calculating and effectively producing a stepping profile like this could be time consuming for the microcontroller, so maybe just altering the gradient to a different linear pofile at different speeds would work almost as well.
Take the maximum speed and minus the minimum speed.
For the first quarter of this, increase the speed by 4
For the second quarter increase the speed by 3
For the third quarter increase the speed by 2
For the fourth quarter increase the speed by 1
As represented here
By decreasing the acceleration level the faster it goes then the less chance you have of stalling.
The example program on the previous page actually does the opposite of this. Because I used the delay cycles as a way of changing the speeds it meant that a shallow gradient happened at slow speed which built up to a steep gradient at high speeds. Although on reflection the program is wrong, it does demonstrate that trapezoidal ramping is easy to achieve and shows that we can take a stepper motor to high speeds. - in fact because the gradient was reversed, my stepper motor was nowhere nearing the speeds it is capable of.
By optimizing these profiles, enhanced speed ranges can be achieved but at the expense of torque. Is there anything that we can do about that? Maybe we can reduce the ratio of lost torque a bit. See the next page
Enhanced control methods
Sinusoidal power switching.
When the stepper motor is being used in the previous examples, we basically send full power to a coil 1 direction and then switch it so we are sending full power to same coil but in the other direction. We are basically sending a square wave and then reversing it. This makes it difficult for the incoming power to energise the coil.
Sinusoidal switching is where we energise the coil slowly using pwm and then slowly reduce the power before switching the powers direction and slowly energizing and de-energising again.
It still takes some time to do this but it would allow us to control whats happening better and allow is to squeeze as much torque as we can from it.
Using a system like this in full step mode would let us be de – energizing 1 coil while the other is fully energized, then once the first coil is fully energized reduce the power to the other coil creating a system similar to half stepping but hopefully keeping the speed and torque.
Most of the expensive stepper motor control boards use sinusoidal energizing methods along with trapezoidal stepping methods.
If anybody has anything to add or spots any mistakes you can post it or PM me in the forum