Stepper motor with a lead screw

Hi guys,

I have a couple of questions and would greatly appreciate some advice. I am working on a project which uses a NEMA 23 stepper motor to rotate a lead screw (resulting in linear motion of the lead screw nut). The motor is connected to a TB6600 stepper motor driver which is set to 3200 pul/rev. I am using a 4x4 keypad to enter different values with an I2C LCD. I am using an Uno microcontroller.

In my code, I have set a 'desiredLinearDistance' to 100mm, but in practice the travel distance of the lead screw nut seems to be around 82mm (and this doesn't change no matter what value I set the desired distance to). Is this a problem with the 'linearDistanceToSteps' function?

Additionally, any linear speed value I enter on the keypad seems to result in a real speed which is double that value. Eg. if I enter a speed of 10mm/s, the lead screw nut actually travels at around 20mm/s.

I'm going to dump my code here, so apologies for the long post:

#include <DFRobot_LCD.h>     // Include the DFRobot_LCD library
#include <Keypad.h>          // Include the Keypad library

// Define the LCD object
DFRobot_LCD lcd(16, 2);

// Define the keypad layout
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};      // Connect keypad ROW0, ROW1, ROW2, ROW3 to these Arduino pins.
byte colPins[COLS] = {5, 4, 3, 2};      // Connect keypad COL0, COL1, COL2, COL3 to these Arduino pins.
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// Define stepper motor control pins
const int dirPin = 12;   // Direction pin
const int stepPin = 13;  // Step pin

// Direction constants
const int COUNTERCLOCKWISE = 1;
const int CLOCKWISE = 0;

// Global variables
int linearSpeedA = 0;     // Speed for counter-clockwise rotation (A)
int linearSpeedC = 0;     // Speed for clockwise rotation (C)
int stationaryTimeB = 0;    // Time to leave motor stationary (B)
int repetitionCountD = 0;   // Number of times to repeat the cycle (D)
bool isCycleActive = false; // Flag to indicate if the cycle is active

// Lead screw parameters
const int effectiveLeadScrewPitch = 8; // Pitch of the lead screw in millimeters per revolution
const int stepsPerRevolution = 16*200; // Number of steps per revolution of the stepper motor

// Desired linear distance in milimeters
const int desiredLinearDistance = 100; // Desired linear distance in milimeters

void setup() {
  // Set the motor control pins as outputs
  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);

  // Initialize the LCD
  lcd.init();
  const int colorR = 255;
  const int colorG = 255;
  const int colorB = 255;

  // Display initial messages
  lcd.setCursor(0, 0);
  lcd.print("Press A, B, C, D");
  lcd.setCursor(0, 1);
  lcd.print("Press # to enter");
}

void loop() {
  char key = keypad.getKey(); // Read the keypad

  if (key) {
    // Handle key press events
    switch (key) {
      case 'A':
        // Set rotation speed for immersion
        linearSpeedA = readIntegerFromKeypad("Immersion Rate");
        break;

      case 'B':
        // Set dwell time
        stationaryTimeB = readIntegerFromKeypad("Dwell Time")*1000;
        break;

      case 'C':
        // Set rotation speed for withdrawal
        linearSpeedC = readIntegerFromKeypad("Withdrawal Rate");
        break;

      case 'D':
        // Set repetition count for the cycle
        repetitionCountD = readIntegerFromKeypad("Number of Cycles");
        break;

      case '#':
        // Start the cycle
        if (!isCycleActive) {
          isCycleActive = true;
          startCycle();
        }
        break;
    }
  }
}

// Function to read an integer value from the keypad
int readIntegerFromKeypad(const char* prompt) {
  lcd.clear();
  lcd.print(prompt);

  int value = 0;
  char buffer[16];
  byte index = 0;

  while (true) {
    char key = keypad.getKey();

    if (key == '#') {
      lcd.clear();
      return value;
    }

    if (key >= '0' && key <= '9' && index < sizeof(buffer) - 1) {
      buffer[index++] = key;
      buffer[index] = '\0';
      value = atoi(buffer);

      lcd.setCursor(0, 1);
      lcd.print(buffer);
    }
  }
}

// Function to start the cycle
void startCycle() {
  lcd.clear();
  lcd.print("Dipping...");

  // Convert desired linear distance to steps
  int steps = linearDistanceToSteps(desiredLinearDistance);

  for (int i = 0; i < repetitionCountD; i++) {
    // Move down
    setMotorDirection(COUNTERCLOCKWISE);
    stepMotorA(steps, linearSpeedA);

    // Stationary period
    delay(stationaryTimeB);

    // Move up
    setMotorDirection(CLOCKWISE);
    stepMotorC(steps, linearSpeedC);
  }

  // Cycle complete
  isCycleActive = false;
  lcd.clear();
  lcd.print("Cycle Complete");
}

// Function to set the motor direction
void setMotorDirection(int direction) {
  digitalWrite(dirPin, direction);
}

// Function to step the motor down
void stepMotorA(int steps, int linearSpeedA) {
  // Calculate the delay between steps based on the linear speed
  unsigned long stepDelayA = 1000000 / (linearSpeedA * stepsPerRevolution / effectiveLeadScrewPitch);

  for (int i = 0; i < steps; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(stepDelayA);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepDelayA);
  }
}

// Function to step the motor up
void stepMotorC(int steps, int linearSpeedC) {
  // Calculate the delay between steps based on the linear speed
  unsigned long stepDelayC = 1000000 / (linearSpeedC * stepsPerRevolution / effectiveLeadScrewPitch);

  for (int i = 0; i < steps; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(stepDelayC);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepDelayC);
  }
}

// Function to convert desired linear distance to steps
int linearDistanceToSteps(float desiredLinearDistance) {
  // Calculate the number of revolutions needed
  float revolutions = desiredLinearDistance / effectiveLeadScrewPitch;

  // Calculate the number of steps required based on revolutions
  int steps = revolutions * stepsPerRevolution;

  return abs(steps);
}

Thanks very much for any help!

Is this code you have written? I suggest that you break it down to baby steps, just try one function at a time and build up.

  • Prove you can output steps and move the motor each way

  • Prove that you can move a set number of steps and the nut moves the desired amount

  • Show that the motor speed is as expected

etc etc, building and testing each function as you go.

I looked at your setup() and cannot find any code to set your initial position of the lead screw. Your description also does not include any information on the power supply for the stepper motor.
Initial conditions are important, since your stepper will always begin at a full step position, even though your program may assume it is at a microstep position.

I am planning to add a limit switch to set the starting position. Even if the motor begins at full step position, I can't see how that would account for an 18mm discrepancy in travel distance (unless I'm missing something?). I understand that one full step of the motor is 1.8deg. My lead screw has 8mm pitch.

The stepper motor driver accepts 9-42V DC. I am using a 12V 3A power supply. The stepper is rated at 2.8A.

I read your post before you deleted it! By your description of the problem, if you moved the same distance back and forth, eventually there would be No actual movement at all because the actual movement is a fixed difference, no matter the direction.

Have you actually measured the thread pitch of the lead screw with a thread gauge?

Without hands on the hardware, it sounds a lot like skipped steps.
Power supply, stepper load, or stepping rate too fast.

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