Updates for the stepper motor control panel
In this video I show some new features of my stepper motor control box and I also show some different implementations of an oscillating motion. Furthermore, I share a nice little gadget which can turn your stepper motor salvaged from a DVD drive into a nice linear actuator. The oscillation is either done by predefined steps or by the triggering of the limit switches. I also explain the parts of the whole code which take care of the oscillating motions. The idea behind the whole control box is to create a universal control panel for the most popular stepper motor drivers for hobbyists.
Schematics
Source code
//The LCD-related code was based on the following library: //https://github.com/cbm80amiga/N5110_GUI_encoder_demo_STM32 //Defining the pins for the Nokia 5110 LCD #define N5110_RST PA0 #define N5110_CS PA4 #define N5110_DC PA1 #define N5110_BACKLIGHT PA2 //Nokia pins: //RST: PA0 //CS: PA4 //DC: PA1 //BL: PA2 (optional) //DIN: PA7 //CLK: PA5 #include "N5110_SPI.h" #if USESPI==1 #include <SPI.h> #endif N5110_SPI lcd(N5110_RST, N5110_CS, N5110_DC); // RST,CS,DC #include "c64enh_font.h" //smaller font #include "term9x14_font.h" //larger font //make sure that the font files are in the same folder as the project file! //AccelStepper #include <AccelStepper.h> AccelStepper stepper(1, PA9, PA8);// pulses/steps 9; Direction 8 //Defining pins const int RotaryCLK = PB9; //CLK pin on the rotary encoder const int RotaryDT = PB8; //DT pin on the rotary encoder const int RotarySW = PB7; //SW pin on the rotary encoder (Button function) const int UpButton = PB12; //Up button which is also a start button const int DownButton = PB13; //Down button which is also a stop button const int LimitSwitch_1 = PB11; //Input for the limit switch const int LimitSwitch_2 = PB10; //Input for the limit switch const int enablePin = PB1; //enable pin for the stepper drivers - not yet implemented! //Statuses of the DT and CLK pins on the encoder int CLKNow; int CLKPrevious; int DTNow; int DTPrevious; //Timing related variables, act mainly as debouncing float RotaryTime1 = 0; //Rotary encoder timing float RotaryTime2 = 0; unsigned long previousInterrupt; //Button timing float LCDRefreshTimer = 0; //Menu-related variables //Values int RotaryButtonValue; //Pressed or not pressed rotary switch volatile int menuCounter = 0; //this is for counting the main menu (menu item number) volatile int stepperMaxSpeed = 400; //for setMaxSpeed volatile int stepperSpeed = 400; //for setSpeed volatile int stepperAcceleration = 800; //for setAcceleration volatile int stepperAbsoluteSteps; //moveTo() volatile int stepperRelativeSteps; //move() volatile int stepperRotarySteps; // This keeps track of the steps done with the rotary encoder volatile int stepperButtonSteps; // This keeps track of the steps done with the buttons volatile int stepperGoToLocation; //Go to steps volatile int stepperPingPongSteps; //amount of steps for Ping-pong demo volatile int stepperStepsize = 1; //Step size for changing the variable. One click on the encoder will in/decrease with this amount int stepperPosition = 0; //position of the stepper motor, measured in steps int previousStepperPosition = 0; //This helps us to update the display int pingpongInitialPosition = 0; //initial position for the step-based ping-pong int pingpongFinalPosition = 0; //final position for the step-based ping-pong int limitSwitchTempPosition = 0; //temporary position for remembering the position when the limit switch was triggered //booleans bool stepperMaxSpeed_Selected = false; //for setMaxSpeed bool stepperSpeed_Selected = false; //for setSpeed bool stepperSpeedRun = false; //for "indefinite" running bool stepperAcceleration_Selected = false; //for setAcceleration bool stepperAbsoluteSteps_Selected = false; //moveTo() bool stepperRelativeSteps_Selected = false; //move() bool rotaryStepping_Selected = false; //precisely step the motor with the rotary encoder bool buttonStepping_Selected = false; //precisely step the motor with the buttons (UpButton/DownButton) bool stepperStepsize_Selected = false; //Step size menu bool stepperSetZero_Selected = false; //Reset to 0 menu bool stepperGoTo_Selected = false; //Go To function bool pingpongStep_Selected = false; //ping-pong demo function - based on steps bool pingpongStep_Enabled = false; //step-based ping pong demo enable/disable swtich bool pingpongLimit_Selected = false; //ping pong demo function - based on limit switch bool pingpongLimit_Enabled = false; //limitswitch based pingpongdemo bool stepperhoming_Selected = false; //Homing with limit switch bool menuChanged = false; //Switched between menus bool valueChanged = false; //changed the value of a menu item bool updateValueSelection = false; //if we want to change the value of a variable, it becomes true bool pingpong_CW = false; //keeps track of the direction inside the limit switch-based pingpong bool pingpong_CCW = false; //keeps track of the direction inside the limit switch-based pingpong char buf[25]; //buffer for printing on the LCD void setup() { //Definition of the pins, remember where you need pinMode(PB9, INPUT); //CLK pinMode(PB8, INPUT); //DT pinMode(PB7, INPUT_PULLUP); //SW pinMode(PB12, INPUT); //UP pinMode(PB13, INPUT); //DOWN pinMode(PB11, INPUT); //LimitSwitch_1 (default is 1 for me) pinMode(PB10, INPUT); //LimitSwitch_2 (default is 1 for me) pinMode(enablePin, OUTPUT); digitalWrite(enablePin, LOW); //Store states CLKPrevious = digitalRead(RotaryCLK); DTPrevious = digitalRead(RotaryDT); //Rotary encoder interrupts attachInterrupt(digitalPinToInterrupt(RotaryCLK), RotaryEncoder, CHANGE); //Stepper setup stepper.setSpeed(stepperSpeed); //SPEED = Steps / second stepper.setMaxSpeed(stepperMaxSpeed); //SPEED = Steps / second stepper.setAcceleration(stepperAcceleration); //ACCELERATION = Steps /(second)^2 lcd.init(); //initialize LCD lcd.clrScr(); //clear the whole display printLCD(); //print the welcome message //digitalRead() UP and DOWN = 0, Limit 1 and 2 = 1 - my default pin readings updateMenuPosition(); updateValue(); } void loop() { if (menuChanged == true) { updateMenuPosition(); } if (valueChanged == true ) { updateValue(); } if (updateValueSelection == true) { updateSelection(); } if (pingpongStep_Enabled == true) { PingPongStep(); } if (pingpongLimit_Enabled == true) { PingPongLimit(); } stepper.run(); //If a step is due, this function will do a step in each loop() iteration //Looping buttons CheckRotaryButton(); UpButtonPressed(); DownButtonPressed(); LimitSwitchPressed(); /* //The below part takes care of the position stepperPosition = stepper.currentPosition(); if (stepperPosition != previousStepperPosition) { updatePosition(); //Pos. on the bottom of the LCD updateValue(); //Pos or value in the middle of the screen previousStepperPosition = stepper.currentPosition(); //^if the motor does not move in the next loop() iteration, the code skips this part of the code } */ //I removed this on 2021-05-09 because the currentPosition() is very slow! I just use a timer if (millis() - LCDRefreshTimer > 500) { stepperPosition = stepper.currentPosition(); updatePosition(); //Pos. on the bottom of the LCD //updateValue(); //Pos or value in the middle of the screen LCDRefreshTimer = millis(); } } void RotaryEncoder() { if (stepperMaxSpeed_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperMaxSpeed = stepperMaxSpeed + stepperStepsize; //1 step size increment } else { if (stepperMaxSpeed < 2) { //Don't decrease further, it should be at least 1 } else { stepperMaxSpeed = stepperMaxSpeed - stepperStepsize; //1 step size decrement } } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state } //Stepper acceleration else if (stepperAcceleration_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperAcceleration = stepperAcceleration + stepperStepsize; //1 step size increment } else { stepperAcceleration = stepperAcceleration - stepperStepsize; //1 step size decrement } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state } //Absolute rotation else if (stepperAbsoluteSteps_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperAbsoluteSteps = stepperAbsoluteSteps + stepperStepsize; //1 step size increment } else { stepperAbsoluteSteps = stepperAbsoluteSteps - stepperStepsize; //1 step size decrement } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state } //Relative rotation else if (stepperRelativeSteps_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperRelativeSteps = stepperRelativeSteps + stepperStepsize; //1 step size increment } else { stepperRelativeSteps = stepperRelativeSteps - stepperStepsize; //1 step size decrement } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state } //Rotary movement else if (rotaryStepping_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperRotarySteps = stepper.currentPosition() + stepperStepsize; //1 step size increment relative to the current position } else { stepperRotarySteps = stepper.currentPosition() - stepperStepsize; //1 step size decrement relative to the current position } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state stepper.moveTo(stepperRotarySteps); } else if (buttonStepping_Selected == true) { //do nothing } //Stepper step size else if (stepperStepsize_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperStepsize++; //1 step increment of the step size } else { if (stepperStepsize < 2) { //If it goes below 2 (=1), it won't be decreased anymore further } else { stepperStepsize--; //1 step decrement of the step size } } } CLKPrevious = CLKNow; // Store last CLK state valueChanged = true; } //------------------------------------------------------------------------------- //GOTO else if (stepperGoTo_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { if (stepperGoToLocation < 4) //5 menu items (0, 1, 2....4) { stepperGoToLocation++; } else { stepperGoToLocation = 0; //0 comes after 4, so we move in a "ring" } } else { // Encoder is rotating CW so decrease if (stepperGoToLocation > 0) { stepperGoToLocation--; } else { stepperGoToLocation = 4; //4 comes after 0 when we decrease the numbers } } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state } //------------------------------------------------------------------------------- //Ping-pong based on user input else if (pingpongStep_Selected == true) { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating in A direction, so we increase if (digitalRead(RotaryDT) != CLKNow) { stepperPingPongSteps = stepperPingPongSteps + stepperStepsize; //1 step increment of the step size } else { stepperPingPongSteps = stepperPingPongSteps - stepperStepsize; } valueChanged = true; } CLKPrevious = CLKNow; // Store last CLK state } //------------------------------------------------------------------------------- else if (pingpongLimit_Selected == true) { //do nothing } //------------------------------------------------------------------------------- //Homing else if (stepperhoming_Selected == true) { //do nothing } //Set new zeropoint else if ( stepperSetZero_Selected == true) { //do nothing } else //MENU COUNTER---------------------------------------------------------------------------- { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then // the encoder is rotating CCW so increase if (digitalRead(RotaryDT) != CLKNow) { if (menuCounter < 11) //12 menu items (0, 1, 2....11) { menuCounter++; } else { menuCounter = 0; //0 comes after 11, so we move in a "ring" } menuChanged = true; } else { // Encoder is rotating CW so decrease if (menuCounter > 0) { menuCounter--; } else { menuCounter = 11; //9 comes after 0 when we decrease the numbers } menuChanged = true; } } CLKPrevious = CLKNow; // Store last CLK state } } void printLCD() //Prints a "welcome screen" { lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, "Stepper"); lcd.printStr(ALIGN_CENTER, 1, "Controller"); lcd.printStr(ALIGN_CENTER, 3, "Please"); lcd.printStr(ALIGN_CENTER, 4, "Wait"); lcd.printStr(ALIGN_CENTER, 5, "3 seconds..."); } void CheckRotaryButton() { RotaryButtonValue = digitalRead(RotarySW); //read the button state if (RotaryButtonValue == 0) //0 and 1 can differ based on the wiring { RotaryTime1 = millis(); if (RotaryTime1 - RotaryTime2 > 1000) { switch (menuCounter) { case 0: stepperMaxSpeed_Selected = !stepperMaxSpeed_Selected; //we change the status of the variable to the opposite if (stepperMaxSpeed_Selected == false)//exiting { stepper.stop(); //stop upon exiting the menu } updateValueSelection = true; break; // case 1: stepperAcceleration_Selected = !stepperAcceleration_Selected; updateValueSelection = true; break; // case 2: stepperAbsoluteSteps_Selected = !stepperAbsoluteSteps_Selected; if (stepperAbsoluteSteps_Selected == false)//exiting { stepper.stop(); //stop upon exiting the menu } updateValueSelection = true; break; // case 3: stepperRelativeSteps_Selected = !stepperRelativeSteps_Selected; if (stepperRelativeSteps_Selected == false)//exiting { stepper.stop(); //stop upon exiting the menu } updateValueSelection = true; break; // case 4: rotaryStepping_Selected = !rotaryStepping_Selected; updateValueSelection = true; valueChanged = true; break; // case 5: buttonStepping_Selected = !buttonStepping_Selected; updateValueSelection = true; valueChanged = true; break; // case 6: stepperStepsize_Selected = !stepperStepsize_Selected; updateValueSelection = true; break; // case 7: stepperhoming_Selected = !stepperhoming_Selected; updateValueSelection = true; break; // case 8: stepperGoTo_Selected = !stepperGoTo_Selected; updateValueSelection = true; break; // case 9: pingpongStep_Selected = !pingpongStep_Selected; updateValueSelection = true; break; // case 10: pingpongLimit_Selected = !pingpongLimit_Selected; updateValueSelection = true; break; // case 11: stepperSetZero_Selected = true; //this always has to be set to true and we set it to false somewhere else updateValueSelection = true; break; } RotaryTime2 = millis(); menuChanged = true; //Refresh LCD after changing the value of the menu } } } void updateMenuPosition() { lcd.clrScr();//delete the entire screen switch (menuCounter) //this checks the value of the counter (0, 1, 2 or 3) { //MAX SPEED case 0: lcd.setFont(c64enh); //set the font (small one) lcd.printStr(ALIGN_CENTER, 0, " "); //erase previous text lcd.printStr(ALIGN_CENTER, 0, "Max speed"); //print new text lcd.setFont(Term9x14); //Set another (larger) font snprintf(buf, 8, "%d", stepperMaxSpeed); //the decimal value of the variable is in the buf lcd.printStr(10, 2, buf); //set the cursor to 2nd line 10th pixel and print the buffer break; //------------------------------- //ACCELERATION case 1: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Acceleration"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperAcceleration); lcd.printStr(10, 2, buf); break; //------------------------------- //ABSOLUTE STEPPING case 2: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Absolute"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperAbsoluteSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //RELATIVE STEPS case 3: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Relative"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperRelativeSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //MOVEMENT WITH ROTARY ENCODER case 4: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Rotary-move"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperRotarySteps); lcd.printStr(10, 2, buf); break; //------------------------------- //MOVEMENT WITH BUTTONS case 5: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Button-move"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperRelativeSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //STEPSIZE case 6: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Step size"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperStepsize); lcd.printStr(10, 2, buf); break;//------------------------------- //HOMING case 7: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Homing"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepper.currentPosition()); lcd.printStr(10, 2, buf); break; //------------------------------- //GOTO case 8: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Go To..."); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperGoToLocation); lcd.printStr(10, 2, buf); break; //------------------------------- //PINGPONG - STEP case 9: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Ping-Pong-s"); lcd.setFont(Term9x14); snprintf(buf, 8, "%d", stepperPingPongSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //PINGPONG - LIMIT case 10: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Ping-Pong-l"); //lcd.setFont(Term9x14); //snprintf(buf, 8, "%d", stepperGoToLocation); //lcd.printStr(10, 2, buf); break; //------------------------------- //RESET case 11: lcd.setFont(c64enh); lcd.printStr(ALIGN_CENTER, 0, " "); lcd.printStr(ALIGN_CENTER, 0, "Set zero"); break; } //"Global" value lcd.setFont(c64enh); snprintf(buf, 8, "%s", "Pos: "); lcd.printStr(0, 5, buf); snprintf(buf, 8, "%d", stepperPosition); lcd.printStr(30, 5, buf); // menuChanged = false; //next loop() iteration will not enter again } void updateValue() { switch (menuCounter) //this checks the value of the counter (0, 1, 2 or 3) { //Max speed menu case 0: stepper.setMaxSpeed(stepperMaxSpeed); lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperMaxSpeed); lcd.printStr(10, 2, buf); break; //------------------------------- //Acceleration menu case 1: stepper.setAcceleration(stepperAcceleration); lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperAcceleration); lcd.printStr(10, 2, buf); break; //------------------------------- //Absolute movement - moveTo() case 2: lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperAbsoluteSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //Relative movement - move() case 3: lcd.setFont(Term9x14); //Command values lcd.printStr(10, 2, " "); //block 8 in line 2 snprintf(buf, 8, "%d", stepperRelativeSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //Rotary encode movement - step by step case 4: lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperPosition); //location lcd.printStr(10, 2, buf); break; //------------------------------- //Button movement - step by step case 5: lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperPosition); //location lcd.printStr(10, 2, buf); break; //------------------------------- //Step size menu - increment-decrement case 6: lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperStepsize); lcd.printStr(10, 2, buf); break; //------------------------------- //GoTo menu - increment-decrement location ID case 8: lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperGoToLocation); lcd.printStr(10, 2, buf); break; //------------------------------- //Ping-Pong - Step-based case 9: lcd.setFont(Term9x14); lcd.printStr(10, 2, " "); snprintf(buf, 8, "%d", stepperPingPongSteps); lcd.printStr(10, 2, buf); break; //------------------------------- //Ping-Pong - LimitSwitch-based case 10: //empty break; //------------------------------- } //"Global" values //this is always shown on the bottom of the display lcd.setFont(c64enh); lcd.printStr(30, 5, " "); snprintf(buf, 8, "%d", stepperPosition); lcd.printStr(30, 5, buf); // valueChanged = false; //next loop() iteration will not enter again } void updatePosition() { lcd.setFont(c64enh); lcd.printStr(30, 5, " "); snprintf(buf, 8, "%d", stepperPosition); lcd.printStr(30, 5, buf); } void updateSelection() { lcd.setFont(Term9x14); //Large font size for the cursor (same as of the values) if (stepperMaxSpeed_Selected == true) { snprintf(buf, 8, "%s", ">"); //print the ">" as the cursor, the ">" indicates the selection/activation lcd.printStr(0, 2, buf); //put it on the display: 2nd line 0 pixel } else if (stepperAcceleration_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (stepperAbsoluteSteps_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (stepperRelativeSteps_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (rotaryStepping_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (buttonStepping_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (stepperStepsize_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (stepperhoming_Selected == true) { snprintf(buf, 8, "%s", "Homing"); lcd.printStr(0, 2, buf); } else if (stepperGoTo_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (pingpongStep_Selected == true) { snprintf(buf, 8, "%s", ">"); lcd.printStr(0, 2, buf); } else if (pingpongLimit_Selected == true) { snprintf(buf, 8, "%s", "Start!"); lcd.printStr(0, 2, buf); } else if (stepperSetZero_Selected == true) { snprintf(buf, 8, "%s", "Reset!"); //we indicate that the position was reset to 0 by printing a message lcd.printStr(0, 2, buf); stepper.setCurrentPosition(0); //set the current position to zero stepperSetZero_Selected = false; //we reset this here } else { snprintf(buf, 8, "%s", " "); lcd.printStr(0, 2, buf); } updateValueSelection = false; //next loop() iteration will not enter } void UpButtonPressed() { if (digitalRead(UpButton) == 1) //1 or 0, depends on your wiring also! { if (millis() - previousInterrupt > 300) //debounce, sort of. If another click comes within 300 ms, we don't care about it { if (stepperMaxSpeed_Selected == true) //runSpeed() { //Runs the motor "indefinitely", until it stopped by the user stepper.move(999999999); //some really large value, for demonstration } else if (stepperRelativeSteps_Selected == true) //move() { stepper.move(stepperRelativeSteps); //start relative stepping } else if (stepperAbsoluteSteps_Selected == true) //moveTo() { stepper.moveTo(stepperAbsoluteSteps); //start absolute stepping } else if (stepperhoming_Selected == true) { //homing part - negative direction while (digitalRead(LimitSwitch_1) == 1) //0 or 1, depends on the wiring! { stepper.setSpeed(-400); stepper.runSpeed(); } //parking part - positive direction while (digitalRead(LimitSwitch_1) == 0) //0 or 1, depends on the wiring! { stepper.setSpeed(200); stepper.runSpeed(); } stepper.setCurrentPosition(0); //reset the position to 0 //Message to the user about the completion of the homing process lcd.setFont(Term9x14); snprintf(buf, 8, "%s", "Parked!"); lcd.printStr(0, 2, buf); //Note: Homing is only implemented for one limit switch because it does not make sense to have 2 home positions } else if (stepperGoTo_Selected == true) { //List of programatically predefined positions //The positions are always measured from the limit switch-defined home position switch (stepperGoToLocation) { case 0: stepper.moveTo(4300); //~ 4.3 cm from home break; case 1: stepper.moveTo(7500); //~ 7.5 cm from home break; case 2: stepper.moveTo(15400); //~ 15.4 cm from home break; case 3: stepper.moveTo(22300); //~ 22.3 cm from home break; case 4: stepper.moveTo(25400); //~ 25.4 cm from home break; default: // break; } //Note: with the ball-screw+linear rail, 1 turn results in 4 mm linear displacement //1 turn = 400 steps (with my MS setting), so 1 mm = 100 steps. } else if (pingpongStep_Selected == true) { pingpongStep_Enabled = true; //Enable stepping based ping-pong demo pingpongInitialPosition = stepper.currentPosition(); pingpongFinalPosition = pingpongInitialPosition + stepperPingPongSteps; } else if (pingpongLimit_Selected == true) { stepper.move(999999999); //some really large value, for demonstration pingpongLimit_Enabled = true; } previousInterrupt = millis(); //update the value so the counting from 300 ms is started over from 0 } else if (buttonStepping_Selected == true) { //buttonstepping does not care about the 300 ms time limit //a little more explanation in the DownButtonPressed() function stepperButtonSteps = stepper.currentPosition() + stepperStepsize; //increase the target position by 1 stepsize stepper.moveTo(stepperButtonSteps); } } } void DownButtonPressed() { if (digitalRead(DownButton) == 1) //1 or 0, depends on your wiring also! { if (millis() - previousInterrupt > 300) { if (stepperMaxSpeed_Selected == true) //runSpeed() { stepper.stop(); //stop and note down the position (next line) stepperPosition = stepper.currentPosition(); } else if (stepperRelativeSteps_Selected == true) //move() { stepper.stop(); stepperPosition = stepper.currentPosition(); } else if (stepperAbsoluteSteps_Selected == true) //moveTo() { stepper.stop(); stepperPosition = stepper.currentPosition(); } else if (stepperhoming_Selected == true) //Homing (interrupted) { stepper.stop(); stepperPosition = stepper.currentPosition(); } else if (pingpongStep_Selected == true) { pingpongStep_Enabled = false; stepper.stop(); stepperPosition = stepper.currentPosition(); } else if (pingpongLimit_Selected == true) { pingpongLimit_Enabled = false; stepper.stop(); stepperPosition = stepper.currentPosition(); } else if (stepperGoTo_Selected == true) { stepper.stop(); stepperPosition = stepper.currentPosition(); } previousInterrupt = millis(); //update the value so the counting from 300 ms is started over from 0 } else if (buttonStepping_Selected == true) { //Optionally, this part should also be in a timing part, but then the time between two steps is limited. //On the other hand, that can be good if you just want one step per buttonclick //Otherwise, pressing the button continuously will still move the motor slowly, but even 1 click will cause several steps //We always want to move 1 stepsize away from the current position stepperButtonSteps = stepper.currentPosition() - stepperStepsize; //decrease the target position by 1 stepsize stepper.moveTo(stepperButtonSteps); } } } void LimitSwitchPressed() { if (pingpongLimit_Enabled == false) { //--- Limit switch 1 if (digitalRead(LimitSwitch_1) == 0) //0 or 1, depends on the wiring! { if (millis() - previousInterrupt > 300) { limitSwitchTempPosition = stepper.currentPosition(); //we save the position where the limit switch was hit stepper.stop(); //"soft" stop - decelerates to 0. stepper.runToPosition(); previousInterrupt = millis(); //Alternatively we can make it to go to a specific place: //stepper.moveTo(0); //This goes back to absolute 0, which is technically the homing while (digitalRead(LimitSwitch_1) == 0) //0 or 1, depends on the wiring! { stepper.setSpeed(-200); stepper.runSpeed(); } stepper.setCurrentPosition(limitSwitchTempPosition); //we set the position where the limit switch was hit } } //--- Limit switch 2 if (digitalRead(LimitSwitch_2) == 0) //0 or 1, depends on the wiring! { if (millis() - previousInterrupt > 300) { limitSwitchTempPosition = stepper.currentPosition(); //we save the position where the limit switch was hit stepper.stop(); //"soft" stop - decelerates to 0. stepper.runToPosition(); previousInterrupt = millis(); //Alternatively we can make it to go to a specific place: //stepper.moveTo(0); //This goes back to absolute 0, which is technically the homing while (digitalRead(LimitSwitch_2) == 0) //0 or 1, depends on the wiring! { stepper.setSpeed(200); stepper.runSpeed(); } stepper.setCurrentPosition(limitSwitchTempPosition); //we set the position where the limit switch was hit } } } else { //do nothing } } void PingPongStep() { if (pingpong_CW == false) //CW rotation is not yet done { stepper.moveTo(pingpongFinalPosition); //set a target position, it should be an absolute. relative (move()) leads to "infinite loop" if (stepper.distanceToGo() == 0) //When the above number of steps are completed, we manipulate the variables { pingpong_CW = true; //CW rotation is now done pingpong_CCW = false; //CCW rotation is not yet done - this allows the code to enter the next ifs } } if (pingpong_CW == true && pingpong_CCW == false) //CW is completed and CCW is not yet done { stepper.moveTo(pingpongInitialPosition); //Absolute position if (stepper.distanceToGo() == 0) //When the number of steps are completed { pingpong_CCW = true; //CCW is now done pingpong_CW = false; //CW is not yet done. This allows the code to enter the first if again! } } } void PingPongLimit() { if (digitalRead(LimitSwitch_1) == 0) { stepper.move(-99999999999); } if (digitalRead(LimitSwitch_2) == 0) { stepper.move(99999999999); } }
Printable models for the linear carriage
Notice: There is a chance that the stepper motor and other parts you salvaged from the DVD rom differs from the one I used.