Iam using 28byj-48 stepper motor and I want to know how to control its speed without using any library. I got to know that we need to add delays in between steps but I don't know how much delay I need to add and how delay effects the rpm. It is very much helpful if anyone suggest me how to do this.
1 Answer
A stepper motor always needs a driver. As the ULN2003 (or similar) driver is normally shipped together with the 28byj-48 motor, I will assume, that you have this driver.
The ULN2003 has 6 pins:
Vcc and ground need to be connected to your power source. Note, that it is risky to connect Vcc to the 5V pin of the Arduino. While that might work, when there is no load on the motor, a loaded stepper motor can draw rather high currents. Letting these current run through the Arduino might fry the voltage regulator or the power switching diode. High currents should always flow past the Arduino, not through it.
The other 4 pins (which are marked as IN1 to IN4 on my ULN2003 driver board) are for controlling the phases. You need to connect these 4 pins to 4 individual digital outputs on your Arduino. As these are the phases of the stepper motor, you need to activate them in the correct order. You have this pattern
1000 0100 0010 0001
for full steps, and this pattern
1000 1100 0100 0110 0010 0011 0001 1001
for half steps. Each digit of each number represents the status of the corresponding phase; 1 means activated/HIGH, 0 means deactivated/LOW. To move the stepper motor forward, you move in the list of phases down. To move backwards, you move up in the list.
When using a stepper motor, the speed is determined by the number of steps per time interval. Let's assume, we want to use delay()
, which is really easy, though not recommended (see explanation below), we can do steps and delay()
inbetween:
void loop(){
step();
delay(10);
}
This code would do a step and then delay for 10ms. Thus we have about 1 step every 10ms. With 64*64=4096
steps per revolution (the motor itself seems to have 64 steps; additionally there is a gear with ratio 64 mounted on it; this might be different for you) we get a full revolution every 4.096s. When you use half the delay()
, the speed will be double: with 5ms delay we get a full rotation every 2.048s. So you can use the delay()
to set the speed of the motor.
Now we need the step()
function, that I used above. There are multiple ways of writing this in code. I would propose to put the pins and phases into arrays and iterate through them with a static variable, which holds the current position in our phase pattern. Something like this:
//in global scope defining the pins for the phases
int stepper_pins[4] = {2, 3, 4, 5};
void step(bool forward){
const uint8_t phase_pattern[][4] = {
{1,0,0,0},
{0,1,0,0},
...
};
static uint8_t current_step = 0;
if(forward){
current_step = (current_step + 1) % 4;
} else {
current_step = (current_step - 1) % 4;
}
for(uint8_t i=0;i<4;i++){
digitalWrite(stepper_pins[i], phase_pattern[current_step][i]);
}
}
We hold the phase pattern in a 2-dimensional array. The variable current_step
is declared static
, so it will keeps its value between the executions of the function. Then - depending on the parameter forward
- we increment or decrement the current step and take that value modulo 4 (the number of phase patterns). That ensures, that current_step
stays in the index range of our phase pattern array and will wrap around from the end of the pattern to the start and vice versa. After that, we loop through the 4 stepper pins and set them according to the current element in the phase_pattern
array. You can easily adept that code for half steps.
Note, that this code is totally untested. Also this can be reached with way less code (at least for full steps), but I think this code is better understandable.
Now: Why not using delay()
? This function will block the execution of other code. In that time the Arduino is just fiddling thumbs. In general that is considered bad practice. It is good, when you only need that one functionality and no responsiveness. But lets assume, you want to add a button, so that the motor reacts to your button presses. Long delay()
calls will impact the responsiveness of your code. So instead you could use a non-blocking coding style. In the Arduino world this is easily done with the millis()
function, which returns the number of milliseconds since startup and thus acts like a clock. Refer to the BlinkWithoutDelay
example, that comes with the Arduino IDE, and to the many tutorials on the web, that you can find with search terms like "Arduino millis tutorial" or something like that.
EDIT:
how your code controlling the motor speed?
The delay()
call is determining the motor speed. If you want to change the speed, you need to change the value of the delay. You didn't mention any input device, so I just leave the speed constant. But of course you can define a variable for the delay and change that delay based on some input device. How exactly that is done depends on your requirements, mainly what type of input you want to use.
if we didn't specify any delays in between steps, will it spin at its max rpm?
When you don't use any delay, then most likely your code will run too fast for the motor. The driver will set the motor phases very very fast. So fast, that the motor cannot follow that (because it has a specific inertia). (Much like the wheels of your car can loose the grip on the street and spin without moving the car, the stator of the motor can loose the magnetic grip on the rotor, which leads to further rotating phases, but a rotor, that is standing still) So you reach the maximum speed before that and it depends on the motor, the driver, how much load is on the motors and how much current your power source can give you (I once tried to provide 3 of these motors with a 1A power supply, but they moved very weak, until I upgraded to a bigger power supply, that can provide about 5A, I think). You need to test yourself, how fast you can drive your motors. So try to lower the delays step by step, until the motor cannot move in your setup anymore. Then you have the minimum delay, and the maximum speed.
Note: The delay()
function won't be accurate for very low delays in the single digit milliseconds. In that case you might wanna use delayMicroseconds()
, which is more accurate in that range and also can get in you in the microsecond range.
-
Your explanation is wonderful,but how your code controlling the motor speed Commented Jan 19, 2021 at 6:02
-
And one more question,if we didn't specify any delays in between steps, will it spin at its max rpm? Commented Jan 19, 2021 at 6:06
-
@Akashbabutammali I added explanations for both questions in my answer.– chrislCommented Jan 19, 2021 at 7:31