Stepper motor weird behavior: won't work at slow speeds BUT it works at fast speeds

Hello! I'm working on an easy, that hasn't been that easy for me, project. It basically is an Arduino Uno, a DRV8825, a XL6009 DC-DC boost converter, and a stepper motor.
The project is a Barn Door Star Tracker, a device that counters the earth rotation movement so you can take long exposure pictures with a DSLR camera (And have stunning photos of deep space objects :milky_way: :artificial_satellite: :comet: )
Here is a picture of it:


The camera goes on the ball head mount. The stepper is on the left side of the hinge

The device is supposed to rotate the stepper very slowly, +/- 1.09RPM and when you press a button it will move fast so you can adjust the position of the camera.

The stepper motor I'm using is a 17HS4023 NEMA 17 which works at 12v so I use a XL6009 Buck to boost 5V to 12V.

I mounted everything on a breadboard, powered it with a 5V 2.1Amp USB Power Bank and IT WORKED flawlessly. Then I decided to take the next step and design a custom made PCB to mount it nicely and in a smaller space. In the PCB I opted for just an Atmega A328P and the minimun components it needs to work properly.

Here is the schematic I made in Easy EDA


Yes, I know. It ain't nice or properly aligned. I'm a lawyer who has never studied anything related to mechatronics before

After I received and mounted the components on the PCB I noticed a weird behavior in the stepper motor.

The problem is that it won't spin at a slow speed, it just makes weird noises BUT when I press the buttons to move it faster it spins normally!

Things I've tried:

  • Mounted everything back to a bread board. The motor works again.
  • Tried different stepping configurations (1/4, 1/8, 1/16, 1/32) and none of them will make the motor spin slow (mounted on my PCB)
  • Re adjusting the potentiometer in the DRV8825 following this steps but the problem persists.
  • Using a 5V 3A power source connected to the PCB instead of the Power Bank. Doesn't fix the issue.
  • Checked Every trace of the PCB with a multimeter but everything seems ok to me.
  • Checked the code I'm using but it seems to me that there ain't anything wrong.
  • Googled the problem I'm having but I haven't find an answer so far.

The code I'm using:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Control box for Astrophotohraphy barn door tracker
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// By Nicolas Dupont  https://www.thingiverse.com/ndupont/about
//
// Based on https://www.thingiverse.com/thing:1133193  by fermunoz https://www.thingiverse.com/fermunoz/about
//
// Release history   
// v0     Original code by fermunoz
// v1     Added button control
// v2     Added tracking ON/OFF control
// v2.1   Solved the motor disable that was not working properly

// SOME MATH :
// radius of the barn door tracker = 200mm (hinge to threaded rod)
// full revolution is 2 * radius * PI = 2 * 200 * 3.141592 = 1256.6368mm
// a full day is 23:56 = 23 * 60 + 56 = 1436 minutes
// movement speed (of the hinge) = 1256.6368 / 1436 = 0.87509 mm/min at threaded rod level
// the M5 stdandard picth is 0.8mm
// Rotation speed of the large gear = 0.85509 / 0.8 = 1.0939 RPM
// Larger gear has 43 teeth, the small one has 10 teeth, gear ratio = 43 / 10 = 4.3
// Small gear (and motor) speed has to be 1.0939 * 4.3 = 4.7036 RPM

// That's 60 / 4.7036 = 12.76 sec/turn ==> useful value to check is all is ok.

// NEMA17 motor usually have 200 steps/rotation 
// Stepper pulses = 4.7036 * 200 = 940.72 steps/min or 15.679 pulses/sec
// with 16x microstepping = 250.86 pulses/sec --> 3.986ms delay between pulses = 3986ยตs
// with 32x microstepping = 501.72 pulses/sec --> 1.993ms delay between pulses = 1993ยตs



#define DELAY 3997 //3997 = 1.09 RPM of the large gear  ==>  WITH 1/16 microstepping  (original value from fermunoz


// Setting the variables

const int motor_dir = 8;          // Output pin for DIR control of the driver
const int motor_step = 9;         // Output pin for STEP control of the driver
const int motor_enable = 10;      // Output pin for ENABLE control of the driver
const int led = 13;               // Output pin for the LED

int ledState = LOW;               // Will store the current ON/OFF state of the LED
unsigned long previousMillis = 0; // used for timing
const long interval = 500;        // interval for the blinking LED

int tracking=1;                   // Tracking ON/OFF state
const int btn_up = 2;             // Input pin for the UP/FORWARD push button
const int btn_down = 3;           // Input pin for the DOWN/REWIND push button
int btnreadup=0;                  // Will store the UP button status
int btnreaddown=0;                // Will store the DOWN button status
int fastratio=1;                  // variable containing the ratio that will be applied to the delay between motor pulses

// the setup routine runs once when you press reset:
void setup() {                
  pinMode(motor_step, OUTPUT);    // The 3 motor control line are set as OUTPUT
  pinMode(motor_dir, OUTPUT); 
  pinMode(motor_enable, OUTPUT); 
  pinMode(led, OUTPUT);           // The LED pin is also an OUTPUT...

  pinMode(btn_up, INPUT_PULLUP);  // Push button input are set as INPUT with PULLUP enable (+5V is applied with an internal resistor)
  pinMode(btn_down, INPUT_PULLUP);// And the switches will have an inverted logic = ACTIVE_LOW  (the button will apply the ground to the inputs)

}

// the loop routine runs over and over again forever:

void loop() {
    if(tracking==0) {                                                                     // If tracking is disabled...
                      digitalWrite(motor_enable,HIGH);                                    // disable the motor  (inverted logic on the driver)
                      while(digitalRead(btn_up)+digitalRead(btn_down)==2) {delay(50);     // wait until a button is pressed
                                                                           toggle_led();} // and blink fast
                      tracking=1;
                    }
          else                                                                            // IF tracking is not disabled
              {
              digitalWrite(motor_enable,LOW);                                            // enable the motor  (inverted logic on the driver)
              unsigned long currentMillis = millis();                                     // read current timer
              if(currentMillis - previousMillis >= interval) {                            // if time has passed more than the specified interval
                              // save the last time you blinked the LED 
                              previousMillis = currentMillis;                             // store the current timer
                          
                              toggle_led();                                               // call the toggle_led() function, that will invert the LED output
                            }

             btnreadup=digitalRead(btn_up);                                               // read the button UP status, will return 0 if pressed and 1 if not (inverted logic)
             btnreaddown=digitalRead(btn_down);                                           // read the button DOWN status, will return 0 if presses, and 1 if not (inverted logic)
             if(btnreadup+btnreaddown==0) {tracking=0; delay(2000);}                      // if both the buttons are pressed (0+0=0), stop the tracking and wait for 2 sec
             if(btnreadup+btnreaddown==2) {fastratio=1;}                                  // if no button is pressed (1+1=2), set the ratio to 1
             else {fastratio=800;}                                                        // if any button was pressed, set the ratio to 800
          
             if(btnreaddown==1) {digitalWrite(motor_dir,LOW);}                            // if the button DOWN was pressed, invert the motor DIRECTION
             else {digitalWrite(motor_dir,HIGH);}                                         // else setp the motor to the FORWARD direction
             
              digitalWrite(motor_step, LOW);                                              // pulse the motor ouput LOW
              digitalWrite(motor_step, HIGH);                                             // set the motor ouput HIGH again
              delayMicroseconds(DELAY/fastratio/2);     // /2 for 1/32 microstepping      // pause the defined time, with ratio applied
             } //else
}


void toggle_led()                                                                         // function that inverts the LED status
{
 // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)                                                                  // logic that reads and invert the LED status variable
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(led, ledState);                                                          // actual toggle of the LED ouput
}

What could be causing the issue I'm having? Thanks in advance for your opinions.
I have to apologize if my writing isn't that clear, English is not my first language and everything I know about Arduino and electronics comes from YouTube and forums like this.

What is 'fast' and what 'slow' for you? If you set 'fastratio' to 800 you get a delay time of

delayMicroseconds(DELAY / fastratio / 2);
 = delayMicroseconds(3997 / 800 / 2);
 = delayMicroseconds(2);

That is far too fast for the stepper.

With fastratio = 1 you get
delayMicroseconds(1998);
what may be ok for the stepper

What's that 5V intended for? The stalled stepper draws up to 6A at 12V (2 * 4 Ohm) unless you power it down between the slow steps.

No, the current is determined by the DRV8825 which is a current driver. The rated current for this motor is 0.7A per Coil. But that's not the current drawn from the power source. That's significantly smaller. The coil current only flows between the coils and the buffer capacitor. 100ยต is the least possible value, more is better.

@hackobo Did you adjust the current at the DRV8825 correctly?

Did you adjust the current at the DRV8825 correctly?

Yes I did. In fact I tried every way to adjust it described here but I had no luck. I even tried to adjust the little potentiometer while the motor was powered to see if I could fin the sweet spot but it didn't work either.

About the code, I didn't write it and I barely understand how it works exactly. What bugs me is that the same code works when mounted on a breadboard, both slow and "fast" but it won't spin "slow" on my PCB :neutral_face:

Could there be some issue with the PCB itself...? Wild imagination but some track that's supposed to be connected between the two layers but isn't, instead acting like a capacitor...blocking at slow pulse rates but allowing pulses to go through at higher rates...?

I think that the issue may be something like you describe. At first I thought that the traces from the controller to the motor might be too thin so I bridged them with cables but didn't fix the issue. I'll check every bias and every trace again.

Hackobo. I would look very carefully at the solder connections on the board. From the photo, a few look like they bridge into the shield layer (if that is what the big grey part is) and it looks like at least one cold solder joint. To check for bridging, with all power removed, you can look for zero continuity from the joint in question to the shield or nearby potential bridge, but be aware of what component you are testing across, ie, a coil might show as a short when it is not. Use a magnifying glass if needed to look for bridges and a possibly and Xacto knife or similar to cut the bridge (or remove the solder and try again.) Definitely in the circuit board (or wiring) if it works repeatedly on the protoboard.
Good luck!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.