Похоже, 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, термины, начало работы
КМБ для начинающих ардуинщиков
Состав стартера (точка входа для начинающих ардуинщиков)
