Похоже, Edward Carlson устал отмерять и нарезать кабель и он решил сделать автоматизированный станок для нарезки кабеля.
Для этого, ему понадобились:
— контроллер Arduino Mega,
— LCD-шилд с кнопками — для организации меню,
— шаговый двигатель — для перемещения кабеля между роликами на нужную длину,
— мощная сервомашинка — для приведения в действие ручные кусачки.
Скетч для Arduino
#include <Servo.h> #include <Stepper.h> #include <LiquidCrystal.h> ////////////////////////////////////// // LCD buttons ////////////////////////////////////// int lcd_key = 0; int adc_key_in = 0; #define btnRIGHT 0 #define btnUP 1 #define btnDOWN 2 #define btnLEFT 3 #define btnSELECT 4 #define btnNONE 5 int pinSwitch = 52; int pinServo = 53; const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution const int stepsPerFoot = 1209; // steps per stepsPerFoot of cable int calSteps; // steps counted during calibration unsigned long startTime; unsigned long endTime; unsigned long calTime; int switchLastState; // switch change state int cutPos = 0; // servo cutter closed position int openPos = 180; // servo cutter open position int servoDelay = 1000; // servo movement time int baseDelay = 6100; // time to measure one stepsPerFoot of cable int speed1 = 150; // stepper speed in RPMs int cutDelay; // how long it takes to measure entire length int setLen; // requested length int setQty; // requested quantity int currQty = 0; // current quantity int totalSteps; // how many steps we need to measure the requested length int measureLen = 0; // measured length (float for decimals!) int measureInch; int measureFeet; int cutLen; // Measured length during cutting operation unsigned long lastDelayTime = 0; unsigned long delayTime = 300; unsigned long lastInteraction = 0; unsigned long lastUpdate = 0; //int buttonState = 0; int cursorPos = 0; int menuState = 0; // Menu position, starts at Menu 0 Stepper myStepper(stepsPerRevolution, 22, 24, 26, 28); Servo myservo; // Set up lcd global variable LiquidCrystal lcd(8, 9, 4, 5, 6, 7); ///////////////////////////////////////////// // New way to read buttons //////////////////////////////////////////// int read_LCD_buttons() { adc_key_in = analogRead(0); // read the value from the buttons if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result if (adc_key_in < 50) return btnRIGHT; if (adc_key_in < 195) return btnUP; if (adc_key_in < 380) return btnDOWN; if (adc_key_in < 555) return btnLEFT; if (adc_key_in < 790) return btnSELECT; return btnNONE; // when all others fail, return this... } void setup() { Serial.begin(9600); Serial.println("======== Automated Cable Cutter Online ========="); pinMode(10, OUTPUT); // LCD backlight control digitalWrite(10, 255); pinMode(pinSwitch, INPUT_PULLUP); lcd.begin(16, 2); // Begin 16 x 2 LCD myservo.attach(pinServo); myStepper.setSpeed(speed1); myservo.write(openPos); // make sure we start with cutter open showMenus(); } void loop() { lcd_key = read_LCD_buttons(); // read the buttons processButtons(); // do the thing if (digitalRead(pinSwitch) != switchLastState) { showMenus(); switchLastState = digitalRead(pinSwitch); // checks to see if the wire sensor switch has changed } } void processButtons () { // Reads the buttons and exectues the proper actions based on the menu currently open if ((millis() - lastDelayTime) > delayTime) { // Only read buttons every 0.3 second switch (menuState) { case 0: /////////////////////////////////////////////////// // Menu 0: Cut mode /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: // Select if (digitalRead(pinSwitch) == HIGH) { // if we haven't loaded a cable releaseStepper(); } menuState = 1; cursorPos = 1; showMenus(); break; case btnRIGHT: // Right if (digitalRead(pinSwitch) == HIGH) { // if we haven't loaded a cable releaseStepper(); } menuState = 1; cursorPos = 1; showMenus(); break; case btnUP: //Up menuState = 7; showMenus(); break; case btnDOWN: // Down menuState = 2; showMenus(); break; case btnLEFT: // ESC menuState = 0; showMenus(); break; } break; case 1: /////////////////////////////////////////////////// // Menu 0 Sub 1: Set cuts /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: // Select if (setQty > 0) { // only if we've set Qty and if there's a cable loaded cutCables(); } break; case btnRIGHT: // Right if (cursorPos == 1) { cursorPos = 2; } else if (cursorPos == 2) { cursorPos = 1; } showMenus(); break; case btnUP: //Up if (cursorPos == 1) { setLen ++; } else if (cursorPos == 2) { setQty ++; } showMenus(); break; case btnDOWN: // Down if (cursorPos == 1 && setLen > 0) { setLen --; } else if (cursorPos == 2 && setQty > 0) { setQty --; } showMenus(); break; case btnLEFT: // Left menuState = 0; showMenus(); break; } break; case 2: /////////////////////////////////////////////////// // Menu 1: Measure Mode /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: menuState = 5; // measure menu showMenus(); break; case btnRIGHT: // Right menuState = 5; // measure menu showMenus(); break; case btnUP: //Up menuState = 0; // Go back to Top menu showMenus(); break; case btnDOWN: // Down menuState = 7; // Go to calibrate menu showMenus(); break; case btnLEFT: // ESC break; } break; case 4: /////////////////////////////////////////////////// // Cut summary /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: menuState = 1; // Go back to Cut menu showMenus(); break; case btnRIGHT: // Right menuState = 1; // Go back to Cut menu showMenus(); break; case btnUP: //Up menuState = 1; // Go back to Cut menu showMenus(); break; case btnDOWN: // Down menuState = 1; // Go back to Cut menu showMenus(); break; case btnLEFT: // ESC menuState = 0; // Go back to Top menu showMenus(); break; } break; case 5: /////////////////////////////////////////////////// // Measurement mode /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: measureCable(); break; case btnRIGHT: // Right // do nothing break; case btnUP: //Up // do nothing break; case btnDOWN: // Down // do nothing break; case btnLEFT: // ESC menuState = 2; // Go back to Measure top menu showMenus(); break; } break; case 6: /////////////////////////////////////////////////// // Cut summary /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: menuState = 5; // Go back to Measure menu showMenus(); break; case btnRIGHT: // Right menuState = 5; // Go back to Measure menu showMenus(); break; case btnUP: //Up menuState = 5; // Go back to Measure menu showMenus(); break; case btnDOWN: // Down menuState = 5; // Go back to Measure menu showMenus(); break; case btnLEFT: // ESC menuState = 5; // Go back to Measure menu showMenus(); break; } break; case 7: /////////////////////////////////////////////////// // Calibrate /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: menuState = 8; // calibrate menu showMenus(); releaseStepper(); break; case btnRIGHT: // Right menuState = 0; // showMenus(); break; case btnUP: //Up menuState = 2; // showMenus(); break; case btnDOWN: // Down menuState = 0; // showMenus(); break; case btnLEFT: // ESC menuState = 0; // showMenus(); break; } break; case 8: /////////////////////////////////////////////////// // Calibrate /////////////////////////////////////////////////// switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: //menuState = 8; // calibrate(); showMenus(); break; case btnRIGHT: // Right menuState = 0; // showMenus(); break; case btnUP: //Up menuState = 2; // showMenus(); break; case btnDOWN: // Down menuState = 0; // showMenus(); break; case btnLEFT: // ESC menuState = 0; // showMenus(); break; } break; default: switch (lcd_key) { case btnNONE: // No buttons // Do nothing break; case btnSELECT: menuState = 0; // showMenus(); break; case btnRIGHT: // Right menuState = 0; // showMenus(); break; case btnUP: //Up menuState = 0; // showMenus(); break; case btnDOWN: // Down menuState = 0; // showMenus(); break; case btnLEFT: // ESC menuState = 0; // showMenus(); break; } break; } lastDelayTime = millis(); } } void showMenus() { // This function holds all the menu designs. Each case is a different menu/submenu. Cases are set by the Enter button incrementing the menuState variable. switch (menuState) { case 0: /////////////////////////////////////////////////// // Menu 0: Cut Mode /////////////////////////////////////////////////// lcd.noCursor(); // Don't show the cursor lcd.setCursor(0, 0); lcd.write(" Cut Mode "); lcd.setCursor(0, 1); lcd.write(" Press Select "); break; case 1: /////////////////////////////////////////////////// // Menu 0, Submenu 1: Cut Setup /////////////////////////////////////////////////// lcd.clear(); lcd.cursor(); // Show the cursor lcd.setCursor(0, 0); lcd.write("Length (ft): "); lcd.setCursor(13, 0); lcd.print(setLen); lcd.setCursor(0, 1); lcd.write("Qty: "); lcd.print(setQty); if (digitalRead(pinSwitch) == HIGH) { // if we've not loaded a cable lcd.setCursor(10, 1); lcd.print("Load"); } else { lcd.setCursor(10, 1); lcd.print("Ready"); } if (cursorPos == 1) { lcd.setCursor(13, 0); } else if (cursorPos == 2) { lcd.setCursor(5, 1); } break; case 2: /////////////////////////////////////////////////// // Menu 1: Measure Mode /////////////////////////////////////////////////// lcd.noCursor(); // Don't show the cursor lcd.setCursor(0, 0); lcd.write(" Measure Mode "); lcd.setCursor(0, 1); lcd.write(" Press Select "); break; case 3: ////////////////////////////////////////////////// // Cutting in Progress ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 1); lcd.print("Qty cut:"); lcd.setCursor(8, 1); lcd.print(currQty); break; case 4: ////////////////////////////////////////////////// // Cut summary ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print("Complete"); lcd.setCursor(0, 1); lcd.print("Cut "); lcd.setCursor(4, 1); lcd.print(currQty); lcd.print(" @ "); lcd.print(setLen); lcd.print(" ft."); break; case 5: ////////////////////////////////////////////////// // Measure mode ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); if (digitalRead(pinSwitch) == HIGH) { lcd.print(" Load cable now "); } else { lcd.print(" Ready "); } lcd.setCursor(0, 1); lcd.print(" Press Select "); break; case 6: ////////////////////////////////////////////////// // Measure summary ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print("Measurement Done"); lcd.setCursor(0, 1); lcd.print("Len: "); lcd.print(measureFeet); lcd.print("' "); lcd.print(measureInch); lcd.print("\""); break; case 7: ////////////////////////////////////////////////// // Calibrate ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print("Calibration Mode"); lcd.setCursor(0, 1); lcd.print(" Press Select "); break; case 8: ////////////////////////////////////////////////// // Calibrate ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print("Load exactly 1'"); lcd.setCursor(0, 1); lcd.print("of cable."); break; case 9: ////////////////////////////////////////////////// // Calibrate ////////////////////////////////////////////////// lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print("Cal. Complete!"); lcd.setCursor(0, 1); lcd.print(calSteps); lcd.print(" steps/ft"); break; } } void calibrate() { calTime = 0; calSteps = 0; // reset lcd.clear(); lcd.setCursor(0, 0); lcd.print("Calibrating..."); while (digitalRead(pinSwitch) == LOW) { myStepper.step(1); calSteps ++; lcd.setCursor(0, 1); lcd.print(calSteps); } menuState = 9; // Calibrate summary menu showMenus(); releaseStepper(); } void cutCables() { cutLen = 0; // reset measured length currQty = 0; // reset current quantity if (digitalRead(pinSwitch) == HIGH) { // switch reads HIGH if we haven't loaded a wire lcd.setCursor(0, 0); lcd.print("Load Wire! "); } else { Serial.println("-_-_-_ Cutting subroutine activated _-_-_-"); Serial.print("~ Cutting "); Serial.print(setQty); Serial.print(" pieces with length "); Serial.print(setLen); Serial.println(" feet."); Serial.print("~ Current quantity cut: "); Serial.println(currQty); //totalSteps = (setLen * stepsPerFoot); // total steps per cut menuState = 3; // Cutting in progress menu showMenus(); while (currQty < setQty) { myStepper.step(-20); delay(100); myStepper.step(20); // unstick the wire from the cutter cutLen = 0; // reset measured length Serial.println("~~~ Measuring... ~~~"); lcd.setCursor(0, 0); lcd.print("Measuring... "); while (cutLen < setLen) { myStepper.step(stepsPerFoot); cutLen ++; lcd.setCursor(13, 0); lcd.print(cutLen); } Serial.println("~~~ Cutter Closed ~~~"); lcd.setCursor(0, 0); lcd.print("Cutter closed "); myservo.write(cutPos); delay(servoDelay); Serial.println("~~~ Cutter Open ~~~"); lcd.setCursor(0, 0); lcd.print("Cutter open "); myservo.write(openPos); delay(servoDelay); Serial.println("~~~ Cut made ~~~"); currQty ++; showMenus(); } menuState = 4; // Cut summary showMenus(); } } void measureCable() { int stepsPerInch = (stepsPerFoot / 12); measureLen = 0; lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print(" Measuring... "); lcd.setCursor(0, 1); lcd.print("Len: "); lcd.print(measureLen); lcd.print(" in."); while (digitalRead(pinSwitch) == LOW) { myStepper.step(stepsPerInch); measureLen = measureLen + 1; lcd.setCursor(4, 1); lcd.print(measureLen); } //some math measureInch = measureLen % 12; measureFeet = measureLen / 12; menuState = 6; // Summary menu showMenus(); releaseStepper(); } void releaseStepper() { digitalWrite(22, LOW); digitalWrite(24, LOW); digitalWrite(26, LOW); digitalWrite(28, LOW); }
По теме
Автомат для нарезания провода
Робот-бендер для проволоки
RopeBot - робот для перерезания верёвки
Arduino-механизм для нарезки пенки
Простой ЧПУ под управлением Arduino
Arduino
Ардуино что это и зачем?
Arduino, термины, начало работы
КМБ для начинающих ардуинщиков
Состав стартера (точка входа для начинающих ардуинщиков)