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!