/*
Forum: https://forum.arduino.cc/t/creating-a-sketch-to-control-a-stepper-motor-with-limit-switches-to-drive-a-prototype-seesaw-piston-vessel/1227569/4
Wokwi: https://wokwi.com/projects/390626969872951297
Motor Control Sketch for SeeSaw Vessel Cradle Control using AccelStepper Library
Created by James Goddings
Combining the improvements of MicroBahner
from https://wokwi.com/projects/390537977584839681
and ec2021
from https://wokwi.com/projects/390537630494628865
In addition
Removed unused variables
Removed unnecessary function
Added stepperX.stop() in case of limit switch activated in loop()
Debounced the limit switches using a simple class
Added printing whether the left of right limit switch was activated
Added lots of comments ...
Changes done 2024/02/24
ec2021
*/
#include "AccelStepper.h";
//Library created by Mike McCauley at http://www.airspayce.com/mikem/arduino/AccelStepper
//Used for programming stepper motors using Arduino microprocessors
//Setup Control Variables
AccelStepper stepperX(1, 6, 7); //AccelStepper Setup
//1=Easy Driver Interface
//Arduino Pin 6 Connected to PUL- Pin => Pulse width controls speed of motor
//Arduino Pin 7 Connected to DIR- Pin => Controls motor direction
//Define Limit Switch Pins
const int limit_switch_l = 2;//Left Limit Switch Connected to Pin 2
const int limit_switch_r = 3;//Left Limit Switch Connected to Pin 3
//Define Variables
long max_position; // Used to set the Maximum Position of the SeeSaw
long left_position; // Used to set the left most position where the SeeSaw
// may be moved to before touching the left limit switch
long right_position; // Used to set the right most position where the SeeSaw
// may be moved to before touching the right limit switch
int variable_speed; // Used to store the variable speed of SeeSaw using a potentiometer
boolean goLeft = true; // Used to define the direction the vessel shall be moved to
// Starts with going to the left position
boolean run = true; //
// Set to true here so that loop() starts "running"
// Simple class to handle switches/buttons and read their debounced status
class switchType { // Class name
private: // private variables/functions can only be used inside the class
byte pin; // Holds the pin number
byte state = HIGH; // Holds the "official" state of digital pin "pin"
byte lastState = HIGH; // Holds the last state of pin read in class function "activated()"
unsigned long lastChange = 0; // Holds the time in ms when the last status change of pin took place
public: // public variables/functions are available from outside the class
void init(byte pinNo) { // Usually called once in setup()) to initialize "pin"
pin = pinNo; // Sets internal "pin" to the value of "pinNo"
pinMode(pin, INPUT_PULLUP); // Initializes the digital pin as INPUT_PULLUP
}
boolean activated() { // Returns true if the pin state is LOW else returns false
byte actState = digitalRead(pin); // Reads the actual digital state of "pin"
if (actState != lastState) { // If this state is different from lastState
lastChange = millis(); // we store the time of this change as "lastChange" in ms
lastState = actState; // and set lastState to actState
}
if (actState != state && millis() - lastChange > 20) { // if "state" is different from actState
// and the last change has been performed more than 20 ms before
// we accept the state change as stable
state = actState; // and set our official "state" to actState
}
return (state == LOW); // if state is LOW the function returns true else false
}
};
switchType limitSwitchLeft; // We declare the left switch based on the class switchType
switchType limitSwitchRight; // We declare the right switch based on the class switchType
void setup() {
//Start the Serial Monitor at 115200 Baud Rate
Serial.begin(115200);
//Initialize the limit switches
limitSwitchLeft.init(limit_switch_l); // Left switch initialized with the pin limit_switch_l
limitSwitchRight.init(limit_switch_r); // Right switch initialized with the pin limit_switch_r
//Wait for Easy Driver to Wake
delay(5);
//Start the Homing Procedure of the Stepper Motor on Startup
stepperX.setMaxSpeed(100.0);//Set MaxSpeed of Stepper Low for Homing
stepperX.setAcceleration(500.0);//Set Acceleration of Stepper Low for Homing
Serial.print("Vessel is finding home position");
stepperX.moveTo(-10000);//Set the Stepper Motor to Move CCW
while (!limitSwitchLeft.activated()) { //Make the Stepper Move CCW Until the Left Limit Switch is Activated
stepperX.run();//Start Moving the Stepper Motor
}
stepperX.stop();
stepperX.move(200);
while (limitSwitchLeft.activated()) { //Make the Stepper Move CW Until the Left Limit Switch is Deactivated
stepperX.run();//Start Moving the Stepper Motor
}
stepperX.stop();
stepperX.setCurrentPosition(0); // this is the new reference point
Serial.println("Homing Complete");
Serial.println("");
Serial.println("Vessel now Seeking Max Position");
//Start the Max Seeking Procedure of the Stepper Motor
stepperX.moveTo(10000);//more than possible max_position
while (!limitSwitchRight.activated()) { //Make the Stepper Move CW Until the Right Limit Switch is Activated
stepperX.run();//Start Moving the Stepper Motor
}
stepperX.stop();
stepperX.move(-200);//Set the Stepper Motor to Move CCW
while (limitSwitchRight.activated()) { //Make the Stepper Move CCW Until the Right Limit Switch is Deactivated
stepperX.run();//Start Moving the Stepper Motor
}
stepperX.stop();
max_position = stepperX.currentPosition();
Serial.print("Max Seeking Complete, "); Serial.println(max_position);
Serial.println("");
Serial.println("Vessel Will Now Start Cycling");
left_position = 2; //Add a new left position variable just before left limit switch
right_position = max_position - 2; //Add a new right position variable just before left limit switch
stepperX.setMaxSpeed(3000);//Set Max Speed High for SeeSaw
stepperX.setAcceleration(300.0);//Set Acceleration High for SeeSaw
delay(2000);
}
void loop() {
variable_speed = map(analogRead(A1), 0, 1023, 300, 3000); // Speed Variable mapped to Potentiometer Position
if (goLeft) { // If "go to the left" then
stepperX.moveTo(left_position); // command stepper to go to the left position
stepperX.setSpeed(-variable_speed); // set speed (negative for turning left)
} else { // else -> "go to the right"
stepperX.moveTo(right_position); // command stepper to go to the right position
stepperX.setSpeed(variable_speed); // set speed (positive for turning right)
}
if (limitSwitchLeft.activated() ||
limitSwitchRight.activated()) { // Check whether one of the limit switches is activated
if (run) { // If yes and run is true ...
Serial.print(limitSwitchLeft.activated() ? "Left " : "Right "); // Print either Left or Right
// assuming that it's unlikely to have both activated at the same time
Serial.println("Limit Switch triggered!");
stepperX.stop(); // Stop the stepper
run = false; // Set run to false so that stepperx.Run() is not executed in loop()
// and to avoid printing the message over and over again ;-)
}
}
if (run) { // While run is true
stepperX.run(); // execute this line to step forward/backwards
if (stepperX.currentPosition() <= left_position) { // if the left position has been reached
goLeft = false; // switch the direction
}
if (stepperX.currentPosition() >= right_position) { // if the right position has been reached
goLeft = true; // switch the direction
}
}
}