How to make the 28BYJ-48 stepper motor run more efficiently?

Aside from using an efficient driver, what factors in the software code affect efficiency? I heard the Accelstepper.h library is more efficient than the default stepper library. Why is that? Please tell me which of the parameter settings affects efficiency. (I want my motor to run as cool as possible for a given speed)

Here is the code I'm using:

#include <AccelStepper.h>
#define HALFSTEP 8

// Motor pin definitions
#define motorPin1 3 // IN1 on the ULN2003 driver 1
#define motorPin2 4 // IN2 on the ULN2003 driver 1
#define motorPin3 5 // IN3 on the ULN2003 driver 1
#define motorPin4 6 // IN4 on the ULN2003 driver 1

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
stepper1.setMaxSpeed(1000.0);
stepper1.setAcceleration(100.0);
stepper1.setSpeed(200);
stepper1.moveTo(20000);

}//--(end setup )---

void loop() {

//Change direction when the stepper reaches the target position
if (stepper1.distanceToGo() == 0) {
stepper1.moveTo(-stepper1.currentPosition());
}
stepper1.run();
}

any advice or comments?

The motor temperature is increased by the motor current, which heats the motor (and is controlled by a suitable motor driver) and reduced by heat dissipation, usually by air motion.

There is little to nothing you can do with the Arduino to control these factors, or the motor efficiency. Stepper motors are simply not efficient.

What is it that you really want to do?

jremington:
The motor temperature is increased by the motor current, which heats the motor (and is controlled by a suitable motor driver) and reduced by heat dissipation, usually by air motion.

There is little to nothing you can do with the Arduino to control these factors, or the motor efficiency. Stepper motors are simply not efficient.

What is it that you really want to do?

Thanks.

I need a motor to rotate 180 degrees in one direction, and reverse 360, and repeats...

I understand a servo motor will do this as well but all the servo motor I tried are very noisy. The 28-byj48 seems to be quiet. Three questions:

  1. Why is a servo motor more efficient than stepper motor for something like this?

  2. Do you know the max rpm one can get out of the 28-byj? Mine isn't even spinning that fast and it's getting warm quickly (although it doesn't get burning hot. It stays warm up to a point, that's good)

I appreciate it.

Because if there is no force on the servo then it does not have to use power to hold position. A stepper always uses power to hold position.

"Too hot to touch" is a good operating temperature for a stepper. If it glows or sets fire to nearby objects then it is too hot and you should take steps. Big ones, as fast as possible, towards the fire exit.

jremington:
There is little to nothing you can do with the Arduino to control these factors, or the motor efficiency. Stepper motors are simply not efficient.

I understand steppers are inherently inefficient, but just wanna know if there are ways to tweak the code to make it more efficient for a given speed/torque requirement. Because according to this tutorial:

"The default stepper library that comes pre-installed with the Arduino IDE supports the full-step method only and has limited features. It does not run the 28BYJ-48 motors very efficiently"

paulwece:
I understand steppers are inherently inefficient, but just wanna know if there are ways to tweak the code to make it more efficient for a given speed/torque requirement. Because according to this tutorial:

28BYJ-48 Stepper Motor with ULN2003 driver and Arduino Uno – 42 Bots

"The default stepper library that comes pre-installed with the Arduino IDE supports the full-step method only and has limited features. It does not run the 28BYJ-48 motors very efficiently"

Is the concept of "duty cycle" applicable to steppers?

For a lot of applications, you might be able to reduce the current being provided when the motor is not actually moving. This would reduce "holding torque", but you might not need much. I'm not sure whether any of the common controllers support this sort of capability; if you can get away with zero holding torque, you might be able to disable the driver completely between movement.

use the code below which is much better

//Written By Nikodem Bartnik - nikodembartnik.pl
//#define STEPPER_PIN_1 D0
//#define STEPPER_PIN_2 D1
//#define STEPPER_PIN_3 D2
//#define STEPPER_PIN_4 D3
byte STEPPER_PIN_1=D0;
byte STEPPER_PIN_2 =D1;
byte STEPPER_PIN_3 =D2;
byte STEPPER_PIN_4 =D3;
//int step_number = 0;
byte step_number = 0;
void setup() {
pinMode(STEPPER_PIN_1, OUTPUT);
pinMode(STEPPER_PIN_2, OUTPUT);
pinMode(STEPPER_PIN_3, OUTPUT);
pinMode(STEPPER_PIN_4, OUTPUT);

}
void loop() {
for (int a = 0; a<2048; a++){
OneStep(false);
delay(100);
}
for (int a = 0; a<2048; a++){
OneStep(true);
delay(100);

}

}

void OneStep(bool dir){
if(dir){
switch(step_number){
case 0:
digitalWrite(STEPPER_PIN_1, HIGH);
digitalWrite(STEPPER_PIN_2, LOW);
digitalWrite(STEPPER_PIN_3, LOW);
digitalWrite(STEPPER_PIN_4, LOW);
break;
case 1:
digitalWrite(STEPPER_PIN_1, LOW);
digitalWrite(STEPPER_PIN_2, HIGH);
digitalWrite(STEPPER_PIN_3, LOW);
digitalWrite(STEPPER_PIN_4, LOW);
break;
case 2:
digitalWrite(STEPPER_PIN_1, LOW);
digitalWrite(STEPPER_PIN_2, LOW);
digitalWrite(STEPPER_PIN_3, HIGH);
digitalWrite(STEPPER_PIN_4, LOW);
break;
case 3:
digitalWrite(STEPPER_PIN_1, LOW);
digitalWrite(STEPPER_PIN_2, LOW);
digitalWrite(STEPPER_PIN_3, LOW);
digitalWrite(STEPPER_PIN_4, HIGH);
break;
}
}else{
switch(step_number){
case 0:
digitalWrite(STEPPER_PIN_1, LOW);
digitalWrite(STEPPER_PIN_2, LOW);
digitalWrite(STEPPER_PIN_3, LOW);
digitalWrite(STEPPER_PIN_4, HIGH);
break;
case 1:
digitalWrite(STEPPER_PIN_1, LOW);
digitalWrite(STEPPER_PIN_2, LOW);
digitalWrite(STEPPER_PIN_3, HIGH);
digitalWrite(STEPPER_PIN_4, LOW);
break;
case 2:
digitalWrite(STEPPER_PIN_1, LOW);
digitalWrite(STEPPER_PIN_2, HIGH);
digitalWrite(STEPPER_PIN_3, LOW);
digitalWrite(STEPPER_PIN_4, LOW);
break;
case 3:
digitalWrite(STEPPER_PIN_1, HIGH);
digitalWrite(STEPPER_PIN_2, LOW);
digitalWrite(STEPPER_PIN_3, LOW);
digitalWrite(STEPPER_PIN_4, LOW);

}
}
step_number++;
if(step_number > 3){
step_number = 0;
}
}

You could reduce the current through the motor by:

  • Using a lower supply voltage.
  • Adding a resistor in series.

Either way the stepper won't be able to move as fast or provide as much torque.

You will gain efficiency by converting your motor to run as a bipolar motor. You can run it that way without changing anything, or you can open it up, and cut the common connection between coils, so that it has 2 independent coils. Then drive it with an 8825 or similar motor driver.

Changing Unipolar Steppers To Bipolar | Hackaday

1 Like

Found this test sketch, seems to work well, pin numbers are different though, 8, 9, 10, 11.

/*
  Sketch for 28BYJ-48 with ULN2003 on UNO, Nano, Pro Mini
  uncomment line 40 for half step mode, 42 for full step, NOT BOTH
  set variable tEnd to microsteps per second, initially set to 12 RPM

   pin 8 to pin 1 on ULN2003, pin 16 to pink,   coilA
       9 to pin 2,                15    yellow, coilC
      10 to pin 3,                14    orange, coilB
      11 to pin 4,                13    blue,   coilD

   Type a number in top of serial monitor for steps to go,
    -2 billion (CCW) to 2 billion (CW) & press [ENTER].
*/
uint32_t tStart;
uint32_t tEnd = 1220UL; // steps/usec = 1000000 / (68.231 * RPM),(half step)
                        // multiply by 2 for full step
           // full step
const byte fSteps [8] = {0x01, 0x02, 0x04, 0x08, 0x01, 0x02, 0x04, 0x08};
           // half step
const byte hSteps [8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09};
byte cntr = 0;
long stg; // steps to go

void setup()
{
  Serial.begin(9600);
  DDRB = 0x0F; // set pins 8,9,10,11 to OUTPUT
}
void loop()
{
  if (Serial.available() > 0)
    {
      stg =  Serial.parseInt();
      Serial.println(stg);
    }
  if (stg != 0)                   
  {
    tStart = micros();
    while(micros() - tStart < tEnd);
    // uncomment the following line for half step mode 4096 steps/rev
    PORTB = (hSteps[cntr & 0x7] & 0x0F) | (PORTB & 0xF0);
    // uncomment the following line for full step mode 2048 steps/rev
   //PORTB = (fSteps[cntr & 0x7] & 0x0F) | (PORTB & 0xF0);

      // sets direction, adds to or subtracts from stg
      // depending on direction
    stg < 0 ? cntr-- : cntr++;
    stg < 0 ? stg++ : stg--; 
  }
}

And here's a p-channel mosfet switch to reduce standby current (heat), pull the output pin LOW for normal operation, HIGH for standby, 150 Ohm resistor cuts current to about 30%.

vp2206-1.png