// You can change following variables inside code
// DEBUG line 13 if you want to use Serial monitor set it 1 or else 0 to stop serial pints
// encoderStep line 24 to set the steps to start motor for a cut
// allowedFluctuation line 26 to set the allowed fluctuation in percentage (0.0 to 1.0 for 100 percent)
// relayLogic line 57 to set the working logic of your relay HIGH/LOW
// forwardDistance line 64 to set forward cut steps for motor
// backwardDistance line 65 to set Reverse cut steps for motor it will be negative
// Including Required Libraries
#include <AccelStepper.h> // You need to install this library from Library manager. Writer "AccelStepper" in search
#include <Encoder.h> // You need to install this library from Library manager. Writer "Encoder" in search
#include "Button2.h"
#define DEBUG 1 // Set Debug level 0-1 to prints result on serial monitor (Set it to 0 when you don't need serial prints)
#if DEBUG == 1
#define debug(x) Serial.print(x)
#define debugln(x) Serial.println(x)
#else
#define debug(x)
#define debugln(x)
#endif
// =========== Encoder Adjustment =============
int encoderStep = 40; // Number of encoder pulses to trigger movement this will be base value
float allowedFluctuation = 0.2; // Maximum allowed fluctuation from base value +/- in percentage allowed value 0.0 - 1.0 (0% to 100%)
int totalEncoderSteps = 0; // New value for encoder steps to trigger the motor
// Moving Average Settings
const int numReadings = 10; // Number of readings to take average
int readings[numReadings]; // Array to store readings
int readIndex = 0; // Index of the current reading
int total = 0; // Running total of the readings
int average = 0; // The average of the readings
// Stepper Speed
int maxSpeed = 1000; // Set motor maximum speed here
float speedModifier = 1.0; // Adjust speed modifier with respect to maximum speed (use 0.0 - 1.0)
float homeSpeedModifier = 0.4; // Home speed modifier to take stepper to home (it's btter to keep it low)
// Creating Buttons instance
Button2 resetButton;
Button2 relay1Btn;
Button2 relay2Btn;
Button2 potCheckBtn;
// Pins for Inputs
const int estopPin = 2; // Emergency Stop Button
const int stepperAlarmPin = 3; // Stepper Motor Alarm Pin
const int encoderPinA = 4; // Rotary Encoder Pin A
const int encoderPinB = 5; // Rotary Encoder Pin B
const int limitSwitchPin = 6; // Limit Switch (NPN Proximity)
const int resetPin = 7; // Reset Button
const int potCheckPin = A0; // Potentiometer Check Button
const int linearPot = A1; // Linear Potentiometer for relation with steps
// Create a Rotary Encoder Object
Encoder rotaryEncoder(encoderPinA, encoderPinB);
long newPosition = 0; // variable to keep track of encoder values
// Pins for stepper Driver
const int stepPin = 8; // Step pin for stepper driver
const int dirPin = 9; // Direction pin for stepper driver
const int enPin = 10; // Enable pin for stepper driver
// Stepper Motor Object (Using AccelStepper for smoother control)
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
// Pins for Outputs
const int relay1Pin = 11; // Relay 1
const int relay2Pin = 12; // Relay 2
const int relay1BtnPin = A2; // Relay 1 button
const int relay2BtnPin = A3; // Relay 2 button
bool relayLogic = LOW; // Relay working Logic to operate Relay (Set it as HIGH/LOW based on your relay)
volatile bool emergencyStop = false; // flag to be set on emergency button press
// Constants
const int forwardDistance = 1000; // Pulses to move forward (adjust for your setup)
const int backwardDistance = -1000; // Pulses to move back
// Global Variables
long encoderPosition = 0;
bool forwardCut = false;
void emergencyBtnPressed() {
emergencyStop = true; // set emergency flag true
}
void setup() {
Serial.begin(9600);
// Initialize pins
pinMode(estopPin, INPUT_PULLUP);
pinMode(limitSwitchPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(estopPin), emergencyBtnPressed, FALLING);
// Stepper Driver Alarm Pin
pinMode(stepperAlarmPin, INPUT_PULLUP);
// Falling means interrup when pin goes low from high state
// Rising means interrup when pin goes high from low state
attachInterrupt(digitalPinToInterrupt(stepperAlarmPin), emergencyBtnPressed, FALLING); // You can choose FALLING/RiSING as last argument.
resetButton.begin(resetPin, INPUT_PULLUP, true); // Initialize button for reset
relay1Btn.begin(relay1BtnPin, INPUT_PULLUP, true); // Initialize button for Relay 1
relay2Btn.begin(relay2BtnPin, INPUT_PULLUP, true); // Initialize button for Relay 2
potCheckBtn.begin(potCheckPin, INPUT_PULLUP, true); // Initialize button for Potentiometer Check
// Attaching events to button press
resetButton.setPressedHandler(resetBtnFunc);
relay1Btn.setPressedHandler(relay1BtnFunc);
relay2Btn.setPressedHandler(relay2BtnFunc);
potCheckBtn.setPressedHandler(potCheckBtnFunc);
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(relay1Pin, !relayLogic); // Initially turn off relay
digitalWrite(relay2Pin, !relayLogic); // Initially turn off relay
// Set up stepper motor parameters
stepper.setMaxSpeed(maxSpeed);
stepper.setAcceleration(500);
stopAll(); // Initiall stop everything
// Homing routine on startup
homeStepper();
// Initialize encoder position
encoderPosition = rotaryEncoder.read();
calculateNewEncoderSteps(); // calculate current pot steps
}
void loop() {
// Check for emergency stop
if (emergencyStop) {
// Stop everything and reset homing
stopAll();
// Reset button functionality
while (digitalRead(resetPin) != LOW) {
;
}
homeStepper();
emergencyStop = false; // Reset emergency stop flag
}
newPosition = rotaryEncoder.read(); // Read the rotary encoder position
resetButton.loop(); // Continoutsly check if button is pressed
relay1Btn.loop(); // Continoutsly check if button is pressed
newPosition = rotaryEncoder.read(); // Read the rotary encoder position
relay2Btn.loop(); // Continoutsly check if button is pressed
potCheckBtn.loop(); // Continoutsly check if button is pressed
// Read the rotary encoder position
newPosition = rotaryEncoder.read();
// Check if the encoder has reached the set threshold for movement
if (abs(newPosition - encoderPosition) >= totalEncoderSteps) {
debug("Stepper was Triggered with encoder steps:");
debugln(abs(newPosition - encoderPosition));
debug("Encoder Value:");
debugln(rotaryEncoder.read());
if (forwardCut == false) { // Check if motor has made a backward cut previously then make forward cut now
// Move the stepper motor forward
moveStepper(forwardDistance);
forwardCut = true; // Set the forward cut flag
} else {
// Move the stepper motor back
moveStepper(backwardDistance);
forwardCut = false; // Reset forward cut flag
}
newPosition = rotaryEncoder.read(); // Read the rotary encoder position
// Update encoder position
encoderPosition = newPosition;
}
// Read the rotary encoder position
newPosition = rotaryEncoder.read();
}
void resetBtnFunc(Button2& btn) {
debugln("reset btn pressed");
homeStepper(); // Take stepper to home
}
void relay1BtnFunc(Button2& btn) {
debugln("Relay 1 btn pressed");
digitalWrite(relay1Pin, !digitalRead(relay1Pin)); // Read current state of relay and reverse it
}
void relay2BtnFunc(Button2& btn) {
debugln("Relay 2 btn pressed");
digitalWrite(relay2Pin, !digitalRead(relay2Pin)); // Read current state of relay and reverse it
}
void potCheckBtnFunc(Button2& btn) {
debugln("Pot Check btn pressed");
calculateNewEncoderSteps(); // Calculate Encoder steps value based on potentiometer
}
void calculateNewEncoderSteps() {
allowedFluctuation = constrain(allowedFluctuation, 0.0, 1.0); // Make sure the allowed fluctuation will be in 0.0-1.0 range
int potMap = map(analogRead(linearPot), 0, 1023, encoderStep - (encoderStep * allowedFluctuation), encoderStep + (encoderStep * allowedFluctuation)); // Map the potentiometer value from -100, 100 (Mid value will be 0)
if (potMap != totalEncoderSteps) {
debug("New Encoder Mapped value:");
debugln(potMap);
totalEncoderSteps = potMap; // Get the total steps from mapped values
}
}
void turnOnRelay1() {
digitalWrite(relay1Pin, relayLogic); // Turn on relay 1
}
void turnOffRelay1() {
digitalWrite(relay1Pin, !relayLogic); // Turn off relay 1
}
void turnOnRelay2() {
digitalWrite(relay2Pin, relayLogic); // Turn on relay 2
}
void turnOffRelay2() {
digitalWrite(relay2Pin, !relayLogic); // Turn off relay 2
}
// Function to move the stepper motor
void moveStepper(int distance) {
digitalWrite(enPin, LOW); // Enable stepper driver
speedModifier = constrain(speedModifier, 0.1, 1.0); // Don't allow user to go beyond 0.1 to 1.0 range
int dirValue = 1;
if (distance < 0)
dirValue = -1;
stepper.moveTo(distance);
while (stepper.distanceToGo() != 0) {
if (emergencyStop) { // if emergency button is pressed get out of loop
return;
}
stepper.setSpeed(dirValue * maxSpeed * speedModifier);
stepper.runSpeed();
}
stepper.setCurrentPosition(0);
digitalWrite(enPin, HIGH); // Disable stepper driver
}
// Function to home the stepper motor
void homeStepper() {
// Move the stepper motor backward slowly until the limit switch is triggered
digitalWrite(enPin, LOW); // Enable stepper driver
// stepper.setSpeed(-200 * speedModifier); // Slow speed for homing
homeSpeedModifier = constrain(homeSpeedModifier, 0.1, 1.0); // Don't allow user to go beyond 0.1 to 1.0 range
while (digitalRead(limitSwitchPin) != LOW) {
if (emergencyStop) { // if emergency button is pressed get out of loop
return;
}
stepper.setSpeed(-maxSpeed * homeSpeedModifier); // Slow speed for homing
stepper.runSpeed();
}
// Stop the motor and set position to 0
stepper.setCurrentPosition(0);
digitalWrite(enPin, HIGH); // Disable stepper driver
forwardCut = false; // Reset forward cut flag
}
// Function to stop all actions (emergency stop)
void stopAll() {
stepper.stop();
digitalWrite(enPin, HIGH); // Disable stepper driver
digitalWrite(relay1Pin, !relayLogic); // Turf off relay
digitalWrite(relay2Pin, !relayLogic); // Turn off relay
}
void customDelay(unsigned long waitTime) {
unsigned long cTime = millis(); // Note current time
while ((millis() - cTime) < waitTime) {
newPosition = rotaryEncoder.read(); // Keep reading encoder
}
}