Arduino Uno, DRV8825, Steppermotor problem

Hello,

I'm having problems with functioning of stepper motor.
Im making a gearselector, Forward-Neutral_Reverse.
With 3 pushbuttons and 3 control led's
Components:
Oled 0.91" screen.
Arduino uno
DRV8825
42SHDC3025-24B motor
3 Pushbuttons
3 Leds
External powersource (12V) for powering motor.
Breadboard powersupply
1 capacitor 470uf (a cross feed motor.

What i want it to do:
After homing, move to neutral.
And then be able to react to wich pushbutton is pressed, and move motor to that fixed location.

What it does now:
It home's motor speed is good, no weird noices, everything runs nice.
Max_speed and Max_accelration, have effect on homing settings.

But when i press button for example "Reverse" motor moves but very slowly and stutters.
All buttons and leds are doing what asked, screen is update to current location.

The only thing that does not works the way i expected is the motor speed.
No matter how i set Max_speed and Max_ acceleration, this has no effect.

I tryed changing stepperdriver, but i dont think thats the issue. Because motor works fine while homing.
So i'm kinda stuck now, could use some help.

Everything is connected as seen in Pin Definitions, drv8825 reset_sleep to 5v, fault not connected, gnd to arduino.

Thanks in advance

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <AccelStepper.h>

// Pin definitions
#define BUTTON_FORWARD_PIN 6
#define BUTTON_NEUTRAL_PIN 7
#define BUTTON_REVERSE_PIN 8
#define LIMIT_SWITCH_PIN 9
#define RESET_PIN 1

#define LED_FORWARD_PIN 3
#define LED_NEUTRAL_PIN 2
#define LED_REVERSE_PIN 10

// OLED Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Stepper motor
#define STEP_PIN 4
#define DIR_PIN 5
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);

// Gear positions
enum GearPosition {NEUTRAL, FORWARD, REVERSE};
long initial_homing = 0;
GearPosition currentPosition = REVERSE;
const int stepsPerRevolution = 200;
// States for LEDs and display
const int ledPins[] = {LED_FORWARD_PIN, LED_NEUTRAL_PIN, LED_REVERSE_PIN};

bool homingComplete = false;

void setup() {
  // Initialize serial monitor
  Serial.begin(115200);
  
  // Initialize pins
  pinMode(BUTTON_FORWARD_PIN, INPUT_PULLUP);
  pinMode(BUTTON_NEUTRAL_PIN, INPUT_PULLUP);
  pinMode(BUTTON_REVERSE_PIN, INPUT_PULLUP);
  pinMode(LIMIT_SWITCH_PIN, INPUT_PULLUP);
  pinMode(RESET_PIN, INPUT_PULLUP);
  
  
  
  
  for (int i = 0; i < 3; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
  ledTest();
  // Initialize the stepper motor
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(700);

//Serial.println("Starting homing process...");  // Homing process
while (!digitalRead(LIMIT_SWITCH_PIN) == LOW) { // Make the Stepper move CW until the switch is deactivated
  stepper.moveTo(initial_homing);  
    stepper.run();
   initial_homing--;
  delay(5);
  }
//if (digitalRead(LIMIT_SWITCH_PIN) == LOW) {  // When the limit switch is LOW, move CCW
    //stepper.moveTo(initial_homing);  
    //stepper.run();
    //initial_homing++;  // Moving in the CCW direction (decreasing position)
    //delay(5);
    //serial.printIn("Neutral");
  //}
  //stepper.stop();

  currentPosition = 0;
  // Optionally, move to neutral position after homing
  moveStepperToPosition(NEUTRAL);

  // Wait for the motor to reach neutral position
while (stepper.distanceToGo() != 0) {
    stepper.run();
  }

  // Print "ready neutral" after homing and reaching neutral
  //Serial.println("ready neutral");
  // Initialize OLED display
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);  // Stay in infinite loop if OLED fails to initialize
  }

  display.display();
  delay(2000); // Wait for a second for startup

  // Update display initially
  homeGearShift();
  updateDisplay();
}
void ledTest() {
  // Perform LED test by lighting up LEDs in sequence
  digitalWrite(LED_FORWARD_PIN, HIGH);
  delay(500);  // LED on for 500 ms
  digitalWrite(LED_FORWARD_PIN, LOW);
  
  digitalWrite(LED_NEUTRAL_PIN, HIGH);
  delay(500);  // LED on for 500 ms
  digitalWrite(LED_NEUTRAL_PIN, LOW);
  
  digitalWrite(LED_REVERSE_PIN, HIGH);
  delay(500);  // LED on for 500 ms
  digitalWrite(LED_REVERSE_PIN, LOW);
}
void loop() {
  // Check the limit switch to set home position if not already done
  if (digitalRead(RESET_PIN) == LOW) {
    resetHoming();
  }

  // After homing, limit switch triggers are ignored (homingComplete is true)
  if (!homingComplete) {
    shiftToNeutral();
    Serial.println("Neutral");
    return;  // Do nothing until homing is completed
  }


  // Handle button presses for shifting gears
  if (digitalRead(BUTTON_FORWARD_PIN) == LOW) {
    shiftToForward();
    Serial.println("Forward");
    delay(500);
  }
  if (digitalRead(BUTTON_NEUTRAL_PIN) == LOW) {
    shiftToNeutral();
    //stepper.run();
    Serial.println("Neutral");
    delay(500);
  }
  if (digitalRead(BUTTON_REVERSE_PIN) == LOW) {
    shiftToReverse();
    Serial.println("Reverse");
    delay(500);
  }
//if (digitalRead(LIMIT_SWITCH_PIN)  == LOW) {
  //Serial.printIn("Neutral");
  // Update the stepper motor position continuously
  stepper.run();
  
  // Update display and LEDs based on current position
  updateDisplay();
}

void shiftToForward() {
  if (currentPosition != FORWARD) {
    moveStepperToPosition(FORWARD);
    currentPosition = FORWARD;
  }
}

void shiftToNeutral() {
  if (currentPosition != NEUTRAL) {
    moveStepperToPosition(NEUTRAL);
    currentPosition = NEUTRAL;
  }
}

void shiftToReverse() {
  if (currentPosition != REVERSE) {
    moveStepperToPosition(REVERSE);
    currentPosition = REVERSE;
  }
}

void moveStepperToPosition(GearPosition position) {
  // Define the stepper motor position for each gear
  int targetPosition = 0;
  switch (position) {
    case FORWARD:
      targetPosition = 100; // example position for Forward
      break;
    case REVERSE:
      targetPosition = -100; // example position for Reverse
      break;
    case NEUTRAL:
      targetPosition = 0; // example position for Neutral
      break;
  }
  
  stepper.moveTo(targetPosition);
}

void homeGearShift() {
 while (digitalRead(LIMIT_SWITCH_PIN) == LOW) {  // Limit switch is LOW (not pressed)
    stepper.moveTo(initial_homing);
    stepper.run();
    initial_homing--;
    delay(5);  // Small delay to prevent excessive speed
  }
stepper.stop();

//currentPosition = -100;

moveStepperToPosition(NEUTRAL);

while (stepper.distanceToGo() != 0){
  stepper.run();
}

 // Serial.println("Ready Neutral");

homingComplete = true;
digitalWrite(LED_NEUTRAL_PIN, HIGH);
  digitalWrite(LED_FORWARD_PIN, LOW);
  digitalWrite(LED_REVERSE_PIN, LOW);
  //digitalWrite(BUTTON_NEUTRAL_PIN, LOW);
//display.print("Ready Neutral");
  
  //updateDisplay();
}

void resetHoming() {
  // Reset the homing state and allow limit switch to be used again
  homingComplete = false;
  initial_homing = -1;  // Reset the homing counter
  currentPosition = NEUTRAL;

  // Move stepper to re-home position (go to limit switch again)
  stepper.setCurrentPosition(0);  // Reset current position
  homeGearShift();
}

void updateDisplay() {
  display.clearDisplay();
  
  // Set text size
  display.setTextSize(3);  // Set text size to 2 (larger)

  // Set text color
  display.setTextColor(SSD1306_WHITE);

  // Get the width of the text to center it
  int16_t x1, y1;
  uint16_t textWidth = 0;

if (homingComplete) {
    //display.getTextBounds("Neutral Ready", 0, 0, &x1, &y1, &textWidth, NULL);
   // display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
  //display.print("Neutral Ready");
  
  //} else {
  // Display gear position
  switch (currentPosition) {
    case FORWARD:
      display.getTextBounds("Forward", 0, 0, &x1, &y1, &textWidth, NULL);
      display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
      display.print("Forward");
      digitalWrite(LED_FORWARD_PIN, HIGH);
      digitalWrite(LED_NEUTRAL_PIN, LOW);
      digitalWrite(LED_REVERSE_PIN, LOW);
      break;
    case REVERSE:
      display.getTextBounds("Reverse", 0, 0, &x1, &y1, &textWidth, NULL);
      display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
      display.print("Reverse");
      digitalWrite(LED_FORWARD_PIN, LOW);
      digitalWrite(LED_NEUTRAL_PIN, LOW);
      digitalWrite(LED_REVERSE_PIN, HIGH);
      break;
    case NEUTRAL:
      display.getTextBounds("Neutral", 0, 0, &x1, &y1, &textWidth, NULL);
      display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
      display.print("Neutral");
      digitalWrite(LED_FORWARD_PIN, LOW);
      digitalWrite(LED_NEUTRAL_PIN, HIGH);
      digitalWrite(LED_REVERSE_PIN, LOW);
      break;
    //case FORWARD:
      //display.getTextBounds("Forward", 0, 0, &x1, &y1, &textWidth, NULL);
      //display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
      //display.print("Forward");
      //digitalWrite(LED_FORWARD_PIN, HIGH);
      //digitalWrite(LED_NEUTRAL_PIN, LOW);
      //digitalWrite(LED_REVERSE_PIN, LOW);
     // break;
  }
  }
  // Update OLED display
  
  display.display();
}


I messed arround with the code a litle, and i got it working now..so thnks Will020..

I saw that there was a " ```
while (stepper.distanceToGo() != 0){
stepper.run();

// Handle button presses for shifting gears
if (digitalRead(BUTTON_FORWARD_PIN) == LOW) {
shiftToForward();
Serial.println("Forward");
delay(500);
}
if (digitalRead(BUTTON_NEUTRAL_PIN) == LOW) {
shiftToNeutral();
//stepper.run();
Serial.println("Neutral");
delay(500);
}
if (digitalRead(BUTTON_REVERSE_PIN) == LOW) {
shiftToReverse();
Serial.println("Reverse");
delay(500);
}
//if (digitalRead(LIMIT_SWITCH_PIN) == LOW) {
//Serial.printIn("Neutral");
// Update the stepper motor position continuously
while (stepper.distanceToGo() != 0) {
stepper.setMaxSpeed(1000);
stepper.setAcceleration(800);
stepper.run();
}

And this is working i have full controle over movement.

There is one more thing i like to change:

What it does:
When program starts, motor rotates ccw un til limitswitch is HIGH. Than the motor rotates the exact rev's back as where the motor was in startup position. And it will make that postition the "Neutral" position.

What i would like:
On start up, motor rotate CCW until limitswitch is HIGH, Than set that location as -800. Then move to "Neutral" location 0


Thanks in advance

Use setCurrentPosition(-800) to set the position, then moveTo(0)

Hi @will020 ,

I have copied your application (the version from Post #1) to Wokwi

See here: https://wokwi.com/projects/424150168327984129

You found already that stepper.run() has to be called frequently to move the stepper.

Some observations:

  • Serial TX is using pin 1 so you should change the RESET_PIN from 1 to e.g. 11 not to interfere with the Serial communication
  • updateDisplay() is called and executed in loop frequently without any need; you could limit the call to the event when currentPosition has changed
  • The reason for the "stutter effect" depends on this concept:
  // Handle button presses for shifting gears
  if (digitalRead(BUTTON_FORWARD_PIN) == LOW) {
    shiftToForward();
    Serial.println("Forward");
    delay(500);
  }

While you press the FORWARD button in every loop this if statement and the delay(500) is executed and effects the execution of stepper.run().

  • The sketch does not handle the situation that two or more of the buttons are pressed simultaneously. This may lead to unwanted behaviour.

In total I would recommend to restructure the sketch as follows:

  • Create a state machine with the states (HOMING, GOREVERSE, GONEUTRAL, GOFORWARD, RESET)
  • Create a function that handles the buttons (reset, reverse, neutral, forward) and switches the state (see states above)
  • Call updateDisplay() only once when the state has changed

That's your choice of course, so please don't feel pressured, but it would make troubleshooting and adding more features a lot easier...

Good luck!
ec2021

I got it to work how i want it now.
Thanks for the feedback.

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <AccelStepper.h>

// Pin definitions
#define BUTTON_FORWARD_PIN 6
#define BUTTON_NEUTRAL_PIN 7
#define BUTTON_REVERSE_PIN 8
#define LIMIT_SWITCH_PIN 9
#define RESET_PIN 1

#define LED_FORWARD_PIN 3
#define LED_NEUTRAL_PIN 2
#define LED_REVERSE_PIN 10

// OLED Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Stepper motor
#define STEP_PIN 4
#define DIR_PIN 5
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
enum GearPosition {NEUTRAL, FORWARD, REVERSE};
long initial_homing = -1;
GearPosition currentPosition = NEUTRAL;
const int stepsPerRevolution = 200;
// States for LEDs and display
const int ledPins[] = {LED_FORWARD_PIN, LED_NEUTRAL_PIN, LED_REVERSE_PIN};

bool homingComplete = false;

const int FORWARD_POSITION = 1800;  // Example position for Forward
const int REVERSE_POSITION = 100;   // Example position for Reverse
const int NEUTRAL_POSITION = 950;  // 950 = ca.35mm 
long homePosition = -1;            // The home position in steps
long maxSteps = 100000;            // Maximum steps for the homing procedure (just a large number to ensure movement)


void ledtest();
void homeGearShift();
void updateDisplay();
void resetHoming();
void homeStepper();

void setup() {
  // Initialize serial monitor
  Serial.begin(115200);

  
  // Initialize pins
  pinMode(BUTTON_FORWARD_PIN, INPUT_PULLUP);
  pinMode(BUTTON_NEUTRAL_PIN, INPUT_PULLUP);
  pinMode(BUTTON_REVERSE_PIN, INPUT_PULLUP);
  pinMode(LIMIT_SWITCH_PIN, INPUT_PULLUP);
  pinMode(RESET_PIN, INPUT_PULLUP);

  for (int i = 0; i < 3; i++) {
    pinMode(ledPins[i], OUTPUT);
  }


  ledTest();
  delay(1000);

  // Initialize the stepper motor
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(600);
  
  homeStepper();

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);  // Stay in infinite loop if OLED fails to initialize
  }

  display.display();
  delay(1000); // Wait for a second for startup

  
  updateDisplay();  // Update display initially
}

void ledTest() {
  // Perform LED test by lighting up LEDs in sequence
  digitalWrite(LED_FORWARD_PIN, HIGH);
  delay(500);  // LED on for 500 ms
  digitalWrite(LED_FORWARD_PIN, LOW);

  digitalWrite(LED_NEUTRAL_PIN, HIGH);
  delay(500);  // LED on for 500 ms
  digitalWrite(LED_NEUTRAL_PIN, LOW);

  digitalWrite(LED_REVERSE_PIN, HIGH);
  delay(500);  // LED on for 500 ms
  digitalWrite(LED_REVERSE_PIN, LOW);
}

void loop() {
  // After homing, limit switch triggers are ignored (homingComplete is true)
  if (!homingComplete) {
    stepper.moveTo(NEUTRAL);
    stepper.run();
    Serial.println("Homing_Complete");
  } // Do nothing until homing is completed

  // Handle button presses for shifting gears
  if (digitalRead(BUTTON_FORWARD_PIN) == LOW) {
    shiftToForward();
    Serial.println("Forward");
    delay(50);
  }
  if (digitalRead(BUTTON_NEUTRAL_PIN) == LOW) {
    shiftToNeutral();
    Serial.println("Neutral");
    delay(50);
  }
  if (digitalRead(BUTTON_REVERSE_PIN) == LOW) {
    shiftToReverse();
    Serial.println("Reverse");
    delay(50);
  }

  stepper.run();
  
  // Update display and LEDs based on current position
  updateDisplay();
  updateLEDs(currentPosition);
}

void shiftToForward() {
  if (currentPosition != FORWARD) {
    moveStepperToPosition(FORWARD);
    currentPosition = FORWARD;
  }
}

void shiftToNeutral() {
  if (currentPosition != NEUTRAL) {
    moveStepperToPosition(NEUTRAL);
    currentPosition = NEUTRAL;
  }
}

void shiftToReverse() {
  if (currentPosition != REVERSE) {
    moveStepperToPosition(REVERSE);
    currentPosition = REVERSE;
  }
}

void moveStepperToPosition(GearPosition position) {
  // Define the stepper motor position for each gear
  int targetPosition = 0;
  switch (position) {
    case FORWARD:
      targetPosition = FORWARD_POSITION; // example position for Forward
      break;
    case REVERSE:
      targetPosition = REVERSE_POSITION; // example position for Reverse
      break;
    case NEUTRAL:
      targetPosition = NEUTRAL_POSITION; // example position for Neutral
      break;
  }

  stepper.moveTo(targetPosition);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }
}

void homeStepper() {
  Serial.println("Starting homing procedure...");

  // Set initial speed to move towards the limit switch
  stepper.setMaxSpeed(900);  // Slower speed for homing
  stepper.setAcceleration(700);  // Slower acceleration for homing

  // Move towards the limit switch until it's triggered
  while (digitalRead(LIMIT_SWITCH_PIN) == HIGH) {
    // Move motor towards the limit switch (in reverse direction)
    stepper.moveTo(-maxSteps);
    stepper.run();
  }

  // When limit switch is triggered, set the current position as home (0)
  stepper.setCurrentPosition(homePosition);
  homingComplete = true; // Set homing complete flag

  // Stop the motor
  stepper.stop();
  Serial.println("Homing complete.");
  
  
  // Optionally, you can move away from the limit switch to avoid staying pressed
  // Move a small distance forward
  delay(500);
  stepper.moveTo(NEUTRAL_POSITION);  // Move 100 steps forward
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }

  // Reset speed and acceleration after homing
  stepper.setMaxSpeed(1000);  // Default max speed
  stepper.setAcceleration(600);  // Default acceleration
}

void resetHoming() {
  // Reset the homing state and allow limit switch to be used again
  homingComplete = false;
  initial_homing = -1;  // Reset the homing counter
  currentPosition = 0;

  // Move stepper to re-home position (go to limit switch again)
  stepper.setCurrentPosition(0);  // Reset current position
  homeGearShift();
}

void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(3);  // Set text size to 2 (larger)
  display.setTextColor(SSD1306_WHITE);

  int16_t x1, y1;
  uint16_t textWidth = 0;

  if (homingComplete) {
    switch (currentPosition) {
      case FORWARD:
        display.getTextBounds("Forward", 0, 0, &x1, &y1, &textWidth, NULL);
        display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
        display.print("Forward");
        break;
      case REVERSE:
        display.getTextBounds("Reverse", 0, 0, &x1, &y1, &textWidth, NULL);
        display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
        display.print("Reverse");
        break;
      case NEUTRAL:
        display.getTextBounds("Neutral", 0, 0, &x1, &y1, &textWidth, NULL);
        display.setCursor((SCREEN_WIDTH - textWidth) / 2, SCREEN_HEIGHT / 2 - 10);  // Center horizontally and position vertically
        display.print("Neutral");
        break;
      
      }
  }
  display.display();
}

void updateLEDs(GearPosition position) {
  digitalWrite(LED_FORWARD_PIN, LOW);
  digitalWrite(LED_NEUTRAL_PIN, LOW);
  digitalWrite(LED_REVERSE_PIN, LOW);

  switch(position) {
    case FORWARD:
      digitalWrite(LED_FORWARD_PIN, HIGH);
      break;
    case REVERSE:
      digitalWrite(LED_REVERSE_PIN, HIGH);
      break;
    case NEUTRAL:
      digitalWrite(LED_NEUTRAL_PIN, HIGH);
      break;
  }
}

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