Stepper Motor control with DRV8825

Hello All,

This is my first post and I don't have much knowledge of electrical, but I have to do a project to automate a Spray gun mechanism.

I have NEMA 17 stepper motor connect to pulley and controlled by belt drive. Motor is connect to Motor drive DRV8825. I have two limit switches, which when pressed, it should change the direction of motor.

I have also added a 24V valve to control the Spray Gun which is connected to MOS Module IRF520N. Below i have added a design of the circuits and have given 12V of power to control the whole setup. I am giving my commands from GUI made in python.

I want to automate the cycles to spray the liquid when motor is started. The valve should open at the same time when motor is started and when limit switch triggers the valve should close. The motor should wait for the delay time given and restart again to opposite direction until other side limit switch is triggered. The valve should also start at the same time and close accordingly to the motor's working.

Below is the code I have made:

// Pin definitions
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 7
#define RIGHT_LIMIT_SWITCH_PIN 6
#define LEFT_LIMIT_SWITCH_PIN 5
#define VALVE_PIN 1 // Valve control pin

// Variables
volatile bool motorRunning = false;
int rpm = 60; // Default RPM
bool direction = true; // true = Right (Forward), false = Left (Reverse)
int stepDelay = 1000; // Default delay in microseconds
int limitSwitchDelay = 1000; // Delay in milliseconds at the endpoint
bool rightLimitSwitchTriggered = false; // Flag for right limit switch
bool leftLimitSwitchTriggered = false; // Flag for left limit switch
int reverseMicrosteps = 75; // Number of microsteps to release the limit switch
int cycles = 0; // Number of cycles
int currentCycle = 0; // Current cycle count
bool resetMode = false; // Flag for reset mode
bool valveAutoMode = false; // Auto mode initially OFF (wait for user command)
bool valveState = false; // Valve initially OFF

void setup() {
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(ENABLE_PIN, OUTPUT);
  pinMode(RIGHT_LIMIT_SWITCH_PIN, INPUT_PULLUP);
  pinMode(LEFT_LIMIT_SWITCH_PIN, INPUT_PULLUP);
  pinMode(VALVE_PIN, OUTPUT);

  // Disable motor and keep valve closed at startup
  digitalWrite(ENABLE_PIN, HIGH);
  digitalWrite(VALVE_PIN, LOW);

  // Serial Communication
  Serial.begin(9600);
  while (!Serial) {
    ; // Wait for serial port to connect
  }
}

void loop() {
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n');
    command.trim();
    handleCommand(command);
  }

  if (resetMode) {
    handleReset();
    return;
  }

  if (motorRunning) {
    if (direction) { // Moving right (forward)
      if (digitalRead(RIGHT_LIMIT_SWITCH_PIN) == LOW && !rightLimitSwitchTriggered) {
        rightLimitSwitchTriggered = true;
        handleRightLimitSwitch();
      } else {
        stepMotor();
      }
    } else { // Moving left (reverse)
      if (digitalRead(LEFT_LIMIT_SWITCH_PIN) == LOW && !leftLimitSwitchTriggered) {
        leftLimitSwitchTriggered = true;
        handleLeftLimitSwitch();
      } else {
        stepMotor();
      }
    }
  }
}

void handleCommand(String command) {
  if (command == "START") {
    motorRunning = true;
    direction = true; // Start by moving right
    digitalWrite(DIR_PIN, HIGH); // Set direction to right
    digitalWrite(ENABLE_PIN, LOW); // Enable motor
    if (valveAutoMode) controlValve(true); // Open valve if auto mode
  } else if (command == "STOP") {
    motorRunning = false;
    digitalWrite(ENABLE_PIN, HIGH); // Disable motor
    if (valveAutoMode) controlValve(false); // Close valve if auto mode
  } else if (command.startsWith("SET_RPM")) {
    rpm = command.substring(8).toInt();
    stepDelay = calculateStepDelay(rpm);
  } else if (command.startsWith("SET_DELAY")) {
    limitSwitchDelay = command.substring(10).toInt();
  } else if (command.startsWith("SET_REVERSE_STEPS")) {
    reverseMicrosteps = command.substring(17).toInt();
  } else if (command.startsWith("SET_CYCLES")) {
    cycles = command.substring(10).toInt();
    currentCycle = 0; // Reset cycle count
  } else if (command == "RESET") {
    resetMode = true;
  } else if (command == "VALVE_ON") {
    valveAutoMode = false; // Disable auto mode
    controlValve(true);
  } else if (command == "VALVE_OFF") {
    valveAutoMode = false; // Disable auto mode
    controlValve(false);
  } else if (command == "VALVE_AUTO") {
    valveAutoMode = true; // Enable auto mode
  }
}

int calculateStepDelay(int rpm) {
  int stepsPerRevolution = 200; // 1.8° stepper motor without microstepping
  long stepsPerMinute = rpm * stepsPerRevolution;
  long stepDelayMicroseconds = (60L * 1000000L) / stepsPerMinute;
  return stepDelayMicroseconds;
}

void stepMotor() {
  digitalWrite(STEP_PIN, HIGH);
  delayMicroseconds(stepDelay);
  digitalWrite(STEP_PIN, LOW);
  delayMicroseconds(stepDelay);
}

void handleRightLimitSwitch() {
  if (valveAutoMode) controlValve(false); // Close valve at limit switch

  digitalWrite(DIR_PIN, LOW); // Reverse direction
  for (int i = 0; i < reverseMicrosteps; i++) {
    stepMotor();
  }

  delay(limitSwitchDelay);

  direction = false;
  digitalWrite(DIR_PIN, LOW);
  rightLimitSwitchTriggered = false;

  if (valveAutoMode) controlValve(true); // Open valve again when motor restarts

  if (cycles > 0) {
    currentCycle++;
    if (currentCycle >= cycles) {
      motorRunning = false;
      moveToLeftLimit();
    }
  }
}

void handleLeftLimitSwitch() {
  if (valveAutoMode) controlValve(false); // Close valve at limit switch

  digitalWrite(DIR_PIN, HIGH); // Reverse direction
  for (int i = 0; i < reverseMicrosteps; i++) {
    stepMotor();
  }

  delay(limitSwitchDelay);

  direction = true;
  digitalWrite(DIR_PIN, HIGH);
  leftLimitSwitchTriggered = false;

  if (valveAutoMode) controlValve(true); // Open valve again when motor restarts
}

void handleReset() {
  motorRunning = false;
  digitalWrite(ENABLE_PIN, HIGH); // Disable motor
  controlValve(false); // Close valve
  delay(1000);
  moveToLeftLimit();
  resetMode = false;
}

void moveToLeftLimit() {
  motorRunning = true;
  direction = false;
  digitalWrite(DIR_PIN, LOW);
  digitalWrite(ENABLE_PIN, LOW);

  while (digitalRead(LEFT_LIMIT_SWITCH_PIN) == HIGH) {
    stepMotor();
  }

  handleLeftLimitSwitch();
  motorRunning = false;
  digitalWrite(ENABLE_PIN, HIGH);
}

void controlValve(bool state) {
  if (!valveAutoMode) { // Manual mode
    digitalWrite(VALVE_PIN, state ? HIGH : LOW);
  } else { // Auto mode
    if (state) {
      digitalWrite(VALVE_PIN, HIGH); // Open valve
    } else {
      digitalWrite(VALVE_PIN, LOW); // Close valve
    }
  }
}

My questions are:

  1. I cannot the speed of the motor by RPM commands, if i give 100 rpm and shift directly to 1000 the motor still works on 100rpm.
  2. For valve operation what modifications more i can do to make it work independently, irrespective of working of the motor.

If you need any more info, please let me know.
Thanks for the help

Do you have a specific question or issue, or are you just inviting general review comments?

Yes.
What is the problem?
Does it work or not?

I have edited the post and added questions.

The Motor is working and valve is also opening and closing, but for valve automate mode, i am facing errors.

There's a few issues with the way you calculate stepDelay. I suggest :

int calculateStepDelay(int rpm) {
  long stepsPerRevolution = 200; // 1.8° stepper motor without microstepping
  long stepsPerMinute = (long)rpm * stepsPerRevolution;
  long stepDelayMicroseconds = (60L * 1000000L) / stepsPerMinute / 2;
  return stepDelayMicroseconds;
}

Also going from 100 to 1000 RPM instantly might cause the motor to stall. You might need to implement an acceleration profile.

Any suggestions how can I control the StepsPerRevolution or RPM of the motor.
right now when I give the command of 200 rpm and stop the motor and give 600 rpm, the motor still works on 200rpm

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