#include <AccelStepper.h> // Include the AccelStepper library for stepper motor control
#include <Encoder.h> // Include the Encoder library for rotary encoder
#include <SD.h> // Include the SD library
// Define stepper motor connections
#define STEP_PIN 5 // Step pin for stepper motor
#define DIR_PIN 6 // Direction pin for stepper motor
#define ENABLE_PIN 7 // Enable pin for stepper motor
// Define rotary encoder pins
#define ENCODER_PIN1 2 // Encoder pin 1
#define ENCODER_PIN2 3 // Encoder pin 2
// Define SD card chip select pin
#define SD_CHIP_SELECT 10
// Define button pins
#define STOP_BUTTON_PIN 9 // Pin for stop button
#define START_BUTTON_PIN 8 // Pin for start button
// Initialize stepper motor object
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
// Initialize rotary encoder object
Encoder encoder(ENCODER_PIN1, ENCODER_PIN2);
// Variables for rotary encoder
int previousPosition = 0;
int currentPosition = 0;
bool encoderActive = false; // Flag to check if the encoder is active
// File to store encoder data
File dataFile;
// Variables to store stepper and encoder data
long storedStepperPosition = 0;
long storedEncoderPosition = 0;
// Variables for button states
bool motorRunning = true; // Flag to check if the motor is running
bool repeatActionActive = false; // Flag to check if repeat action is active
long lastStoppedPosition = 0; // Last position where the motor was stopped
long resumePosition = 0; // Position to resume from
long targetPosition = 0; // Target position for the stepper motor
// Flags for data storage control
bool dataStorageActive = false; // Flag to check if data storage is active
void setup() {
// Initialize Serial communication
Serial.begin(9600);
// Print the header for the columns
Serial.println("Encoder Position\tStepper Position");
// Set up stepper motor properties
stepper.setMaxSpeed(1000); // Adjust this value as needed
stepper.setAcceleration(100); // Adjust this value as needed
// Set up stepper motor pins
pinMode(ENABLE_PIN, OUTPUT);
digitalWrite(ENABLE_PIN, LOW); // Enable the stepper motor driver
// Set initial position of the stepper motor
stepper.setCurrentPosition(0);
// Initialize SD card
if (!SD.begin(SD_CHIP_SELECT)) {
Serial.println("SD card initialization failed!");
return;
}
Serial.println("SD card initialized.");
// Open file in append mode
dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile) {
dataFile.println("Encoder Position\tStepper Position");
dataFile.close();
} else {
Serial.println("Error opening file.");
}
// Set up button pins
pinMode(STOP_BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor
pinMode(START_BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor
}
void loop() {
// Check button states
if (digitalRead(STOP_BUTTON_PIN) == LOW) {
if (motorRunning) {
motorRunning = false; // Stop the motor
repeatActionActive = false; // Stop repeat actions if active
lastStoppedPosition = stepper.currentPosition(); // Save the current position
stepper.stop(); // Immediately stop the stepper motor
Serial.print("Machine stopped at position: ");
Serial.println(lastStoppedPosition);
// Store stop position data to SD card
if (dataStorageActive) {
dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile) {
dataFile.print("Stopped at Encoder Position: ");
dataFile.print(currentPosition);
dataFile.print("\tStepper Position: ");
dataFile.println(lastStoppedPosition);
dataFile.close(); // Close the file
} else {
Serial.println("Error opening file.");
}
}
}
delay(200); // Debounce delay to avoid multiple reads
}
if (digitalRead(START_BUTTON_PIN) == LOW) {
if (!motorRunning) {
motorRunning = true; // Start the motor
resumePosition = lastStoppedPosition; // Resume from the last stopped position
Serial.print("Machine started. Resuming from position ");
Serial.println(resumePosition);
stepper.setCurrentPosition(resumePosition); // Set the current position to resume from
stepper.moveTo(targetPosition); // Move to the original target position
}
delay(200); // Debounce delay to avoid multiple reads
}
if (motorRunning) {
// Read rotary encoder position
currentPosition = encoder.read();
// Check if encoder position has changed significantly
if (abs(currentPosition - previousPosition) >= 4) { // Adjust this threshold as needed
encoderActive = true; // Encoder is active
previousPosition = currentPosition; // Update previous position
// Map encoder position to stepper motor steps
long steps = map(currentPosition, 0, 80, 0, 200); // Adjust 0-80 to your encoder's range and 0-200 to steps range
// Move stepper motor to desired position
stepper.moveTo(steps);
targetPosition = steps; // Update the target position
// Print encoder and stepper motor position to Serial monitor in columns
Serial.print(currentPosition);
Serial.print("\t\t");
Serial.println(steps);
// Write encoder position to SD card in columns
if (dataStorageActive) {
dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile) {
dataFile.print(currentPosition);
dataFile.print("\t\t");
dataFile.println(steps);
dataFile.flush(); // Ensure data is written to the SD card
dataFile.close(); // Close the file
} else {
Serial.println("Error opening file.");
}
}
} else {
encoderActive = false; // Encoder is not active
}
// Run the stepper motor
stepper.run();
} else {
// If motor is stopped, ensure it is not moving
stepper.stop();
}
// Check for Serial input commands
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n'); // Read the entire line
// Split the command into individual commands
int startIndex = 0;
int spaceIndex;
while ((spaceIndex = command.indexOf(' ', startIndex)) != -1) {
processCommand(command.substring(startIndex, spaceIndex));
startIndex = spaceIndex + 1;
}
// Process the last command (or only command if no spaces were found)
processCommand(command.substring(startIndex));
}
delay(10); // Small delay to avoid excessive CPU usage
}
void processCommand(String cmd) {
if (cmd.startsWith("a")) {
// Extract the number of steps from the command
int steps = cmd.substring(1).toInt();
if (steps > 0) {
Serial.print("Moving stepper motor to ");
Serial.print(steps);
Serial.println(" steps.");
stepper.moveTo(steps);
targetPosition = steps; // Update the target position
} else {
Serial.println("Invalid step value.");
}
} else if (cmd == "S1") {
// Start storing data
dataStorageActive = true;
Serial.println("Data storage started.");
} else if (cmd == "S2") {
// Stop storing data
dataStorageActive = false;
Serial.println("Data storage stopped.");
} else if (cmd == "S") {
// Store current stepper and encoder positions to SD card
if (dataStorageActive) {
dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile) {
dataFile.print("Stored Encoder Position: ");
dataFile.print(currentPosition);
dataFile.print("\t\tStored Stepper Position: ");
dataFile.println(stepper.currentPosition());
dataFile.close(); // Close the file
Serial.println("Data stored successfully.");
} else {
Serial.println("Error opening file.");
}
} else {
Serial.println("Data storage is not active. Use S1 to start storing data.");
}
} else if (cmd == "O") {
// Open file and read its contents
File readFile = SD.open("data.txt");
if (readFile) {
Serial.println("Reading data from file:");
while (readFile.available()) {
Serial.write(readFile.read());
}
readFile.close();
} else {
Serial.println("Error opening file.");
}
} else if (cmd == "r") {
// Begin repeat action
repeatActionActive = true;
Serial.println("Repeating actions from stored data:");
File readFile = SD.open("data.txt");
if (readFile) {
while (readFile.available() && repeatActionActive) {
String line = readFile.readStringUntil('\n');
// Skip the header line
if (line.startsWith("Encoder Position") || line.startsWith("Stopped at Encoder Position")) continue;
// Extract encoder and stepper positions from the line
int tabPos = line.indexOf('\t');
if (tabPos > 0) {
long encoderPos = line.substring(0, tabPos).toInt();
long stepperPos = line.substring(tabPos + 2).toInt(); // +2 to skip the tab character
// Move stepper motor to the stored position
stepper.moveTo(stepperPos);
while (stepper.distanceToGo() != 0 && repeatActionActive) {
stepper.run();
// Check for stop button state during repeat action
if (digitalRead(STOP_BUTTON_PIN) == LOW) {
repeatActionActive = false;
lastStoppedPosition = stepper.currentPosition(); // Save the current position
stepper.stop();
Serial.println("Machine stopped during repeat action.");
// Store stop position data to SD card
dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile) {
dataFile.print("Stopped at Encoder Position: ");
dataFile.print(encoderPos);
dataFile.print("\tStepper Position: ");
dataFile.println(lastStoppedPosition);
dataFile.close(); // Close the file
} else {
Serial.println("Error opening file.");
}
break;
}
}
// Print the positions to the Serial Monitor
Serial.print(encoderPos);
Serial.print("\t\t");
Serial.println(stepperPos);
}
}
readFile.close();
} else {
Serial.println("Error opening file.");
}
}
}