Automatic Wire Cutter and Stripper
element14 Presents | DJ Harrigan's VCP Profile | Project Videos
Say goodbye to cramped wrists and handheld gadgets for cutting wire and say hello to your new workhorse on the workbench: the A.W.C.S. The “Ox” is an automatic wire cutting and stripping machine meant to take some of the busywork out of building electronic gadgets. Will it succeed? Will it actually save time? Will my wrists be spared from carpal tunnel and tendonitis? Let’s find out! |
Supplemental Content:
#include <Adafruit_CharacterOLED.h> #include <AccelStepper.h> #include <Bounce2.h> #include <Encoder.h> #define ENCODER_DO_NOT_USE_INTERRUPTS #define PIN_ENABLE_FEED 21 #define PIN_ENC_A 2 #define PIN_ENC_B 3 #define PIN_BUTTON_ENC 4 #define PIN_BUTTON_RED 5 #define PIN_LED 13 #define PIN_SENSOR A0 #define WIRE_QUANT_MIN 1 #define WIRE_QUANT_MAX 100 #define WIRE_MIN_LEN 5 #define WIRE_AWG 22 Adafruit_CharacterOLED lcd(OLED_V2, 6, 7, 8, 9, 10, 11, 12); AccelStepper stepCut(1, 19, 18); // (DRIVER, STEP, DIR) AccelStepper stepFeed(1, 15, 14); Encoder encoder(PIN_ENC_A, PIN_ENC_B); Bounce buttonOK = Bounce(); Bounce buttonRED = Bounce(); int curSpool = 0; // in future, give each spool a unique id and track total length cut int curSpoolRemaining = 0; int mainMode = 0; int subMode = 0; int lastSubMode = -99; int scrollPos = 0; int lastScrollPos = -99; long encPos = -999; long lastEncPos = 0; long retractPos = -3600; long stripPos = -1000; // long stripFeedDistance = 0; long lengthFeedDistance = 0; long cutPos = 200; long targetPos = 0; boolean isHomed = false; int bladeCycleState = 0; int sensorVal = 0; uint16_t wireQuantity = 0; uint16_t wireLength = 0; // in milimeters uint16_t wireStripLength = 0; uint16_t wiresCut = 0; float conductor_diam = 0.64516; // 22 AWG float feed_diam = 22.0; // uncalibrated! float feed_circum = PI * feed_diam; // 69.115mm per rev //float feed_res = feed_circum / 200.0; // .346mm per step float feed_res = 0.346; // Z travel is 1/16" (1.5875mm) per revolution // both motors are 1.8deg per step (200 per revolution) // the cut motor driver has a noncofigurable default 10x microstepping rate // so z resolution = 0.00079375mm per "full" step sent // leaving us with ~1260 steps per mm z travel boolean ledState = 0; long curTime = 0; long lastTime = 0; int deltaTime = 100; void setup(){ Serial.begin(115200); lcd.begin(16, 2); lcd.print("AWCS READY!"); stepCut.setPinsInverted(true, true); stepFeed.setPinsInverted(true, true); stepFeed.setMaxSpeed(2000); stepFeed.setAcceleration(6000); stepCut.setMaxSpeed(20000); stepCut.setAcceleration(40000); pinMode(PIN_ENABLE_FEED, OUTPUT); pinMode(PIN_BUTTON_ENC, INPUT_PULLUP); pinMode(PIN_BUTTON_RED, INPUT_PULLUP); pinMode(PIN_LED, OUTPUT); buttonOK.attach(PIN_BUTTON_ENC); buttonRED.attach(PIN_BUTTON_RED); buttonOK.interval(5); buttonRED.interval(5); digitalWrite(PIN_ENABLE_FEED, LOW); delay(200); digitalWrite(PIN_ENABLE_FEED, HIGH); delay(200); digitalWrite(PIN_ENABLE_FEED, LOW); //setZHOME(): setBlade('H'); //lcd.clear(); printMenu(); printCursor(0); subMode = 5; setBlade('R'); } void loop(){ /*curTime = millis(); // VERY BASIC Calibration measurement if (curTime - lastTime > deltaTime){ lastTime = curTime; getInput(); //lcd.clear(); lcd.setCursor(0, 0); lcd.print("POS: "); lcd.setCursor(4, 0); lcd.print(scrollPos); lcd.setCursor(0, 1); lcd.print("SEN: "); lcd.setCursor(4, 1); lcd.print(sensorVal); cutPos = 63 * scrollPos; stepCut.moveTo(cutPos); } stepCut.run();*/ getInput(); switch(mainMode){ case 0: // MAIN MENU switch(subMode){ case 0: // choose quantity if( scrollPos != lastScrollPos){ if (scrollPos > 999)scrollPos = 1; if (scrollPos < 1)scrollPos = 999; lastScrollPos = scrollPos; wireQuantity = scrollPos; lcd.setCursor(5, 0); lcd.print(" "); // clear lcd.setCursor(5, 0); lcd.print(wireQuantity); } if (buttonOK.fell())returnToMenu(); break; case 1: // choose length (resolution of 5mm) if( scrollPos != lastScrollPos){ if (scrollPos > 99)scrollPos = 0; if (scrollPos < 0)scrollPos = 99; lastScrollPos = scrollPos; wireLength = scrollPos * 5; lcd.setCursor(13, 0); lcd.print(" "); // clear lcd.setCursor(13, 0); lcd.print(wireLength); } if (buttonOK.fell())returnToMenu(); break; case 2: // choose strip length (default strip both ends) if( scrollPos != lastScrollPos){ if (scrollPos > 999)scrollPos = 0; if (scrollPos < 0)scrollPos = 999; lastScrollPos = scrollPos; wireStripLength = scrollPos; lcd.setCursor(5, 1); lcd.print(" "); // clear lcd.setCursor(5, 1); lcd.print(wireStripLength); } if (buttonOK.fell())returnToMenu(); break; case 3: // run subMode = 5; mainMode = 1; // RUN! lcd.clear(); lcd.home(); lcd.print("NOW CUTTING:"); printJobStatus(); setBlade('R'); stepFeed.setCurrentPosition(0); stripFeedDistance = 32* round(float(wireStripLength)/feed_res); lengthFeedDistance = 32* round((2.0*float(wireStripLength))/feed_res); Serial.print("FEED STEPS: ");Serial.println(stripFeedDistance); Serial.print("FEED DIST: ");Serial.println(lengthFeedDistance); break; case 4: // clear resetParameters(); printMenu(); returnToMenu(); break; case 5: // scrolling if( scrollPos != lastScrollPos){ if (scrollPos > 4)scrollPos = 0; if (scrollPos < 0)scrollPos = 4; lastScrollPos = scrollPos; printCursor(scrollPos); } if (buttonOK.fell()){ subMode = scrollPos; //delay(200); } break; } break; case 1: // RUN // loop through quantity, allow mid-job canceling switch (bladeCycleState){ case 0: // initial retract, then feed length of strip if (stepCut.distanceToGo() == 0){ // allow the blade to retract printJobStatus(); // show wire X of N wires bladeCycleState++; stepFeed.setCurrentPosition(0); stepFeed.moveTo(stripFeedDistance); // feed length of strip } break; case 1: // feed, then strip if (stepFeed.distanceToGo() == 0){ // allow strip length to fininsh feeding bladeCycleState++; setBlade('S'); } break; case 2: // strip, then retract if (stepCut.distanceToGo() == 0){ // allow time to strip bladeCycleState++; setBlade('R'); } break; case 3: // retract, then feed length of wire if (stepCut.distanceToGo() == 0){ // allow retraction bladeCycleState++; stepFeed.setCurrentPosition(0); stepFeed.moveTo(lengthFeedDistance); } break; case 4: // feed, then strip if (stepFeed.distanceToGo() == 0){ // allow feed movement etc. bladeCycleState++; setBlade('S'); } break; case 5: // strip, then retract if (stepCut.distanceToGo() == 0){ // allow feed movement etc. bladeCycleState++; setBlade('R'); } break; case 6: // retract, then feed if (stepCut.distanceToGo() == 0){ // allow feed movement etc. bladeCycleState++; stepFeed.setCurrentPosition(0); stepFeed.moveTo(stripFeedDistance); } break; case 7: // retract, then feed if (stepFeed.distanceToGo() == 0){ // allow feed movement etc. bladeCycleState++; setBlade('C'); } break; case 8: // cut, then retract and loop if more wires need to run. if (stepCut.distanceToGo() == 0){ // allow feed movement etc. bladeCycleState = 0; wiresCut++; setBlade('R'); } break; } // return to main menu when done or cancel the job if (buttonRED.fell() || wiresCut >= wireQuantity){ mainMode = 0; resetParameters(); subMode = 5; returnToMenu(); printMenu(); printCursor(0); } break; } // the motors only really move if there is a remaning position to travel, // and this needs to be called often enough that nesting it // inside some other function doesn't help much, so we'll just keep the .run() here stepFeed.run(); stepCut.run(); } // END MAIN LOOP void printJobStatus(){ lcd.setCursor(0, 1); lcd.print("WIRE OF "); lcd.setCursor(5, 1); lcd.print(wiresCut+1); lcd.setCursor(11, 1); lcd.print(wireQuantity); } void setBlade(char bladePos){ switch (bladePos){ case 'H': // home while (!isHomed){ curTime = millis(); if (curTime - lastTime > 100){ lastTime = curTime; sensorVal = analogRead(PIN_SENSOR); if (sensorVal < 430){ targetPos += 63; stepCut.moveTo(targetPos); } else { isHomed = true; stepCut.setCurrentPosition(0); } } stepCut.run(); } break; case 'R': // retract stepCut.moveTo(retractPos); break; case 'S': // strip stepCut.moveTo(stripPos); break; case 'C': // cut stepCut.moveTo(cutPos); break; } } void returnToMenu(){ scrollPos = subMode; subMode = 5; } void printCursor(int cursorPos){ //clear old cursor positions lcd.setCursor(0, 0); lcd.print(" "); lcd.setCursor(8, 0); lcd.print(" "); lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(8, 1); lcd.print(" "); lcd.setCursor(12, 1); lcd.print(" "); switch(cursorPos){ case 0: lcd.setCursor(0, 0); lcd.print(">"); break; case 1: lcd.setCursor(8, 0); lcd.print(">"); break; case 2: lcd.setCursor(0, 1); lcd.print(">"); break; case 3: lcd.setCursor(8, 1); lcd.print(">"); break; case 4: lcd.setCursor(12, 1); lcd.print(">"); break; } } void printMenu(){ lcd.setCursor(0, 0); lcd.print(" QTY: WRL: "); lcd.setCursor(0, 1); lcd.print(" STL: RUN CLR"); } void resetParameters(){ wireQuantity = 0; wireLength = 0; wireStripLength = 0; wiresCut = 0; bladeCycleState = 0; stripFeedDistance = 0; lengthFeedDistance = 0; } void getInput(){ buttonOK.update(); buttonRED.update(); if (buttonOK.fell()){ ledState = !ledState; digitalWrite(PIN_LED, ledState); } encPos = encoder.read(); if (abs(encPos - lastEncPos) > 4){ // did the encoder move one detent? if (encPos - lastEncPos > 0){ // positive scrollPos++; } else { // negative scrollPos--; } lastEncPos = encPos; } sensorVal = analogRead(PIN_SENSOR); }
Bill of Material:
Product Name | Manufacturer | Quantity |
Buy Kit |
---|---|---|---|
Stepper Motor Bipolar 1 A Two Phase 3.4 ohm 6.5 mH |
SANYO DENKI - SANMOTION | 1 | Buy Now |
Stepper Motor Power Step High Torque Bipolar 294 in-oz 2.8 A Two Phase 1.1 ohm 3.8 mH |
LIN ENGINEERING | 1 | Buy Now |
TMCM-1070 - Stepper Motor Driver, 2-Phase, Single Axis, 2.8A, 24V DC Output, USB, RS485, CAN | TRINAMIC | 1 | Buy Now |
Motor Driver R701 Microstepping Two Phase 12 to 80 Vdc 7 A 560 W 200 kHz | LIN ENGINEERING | 1 | Buy Now |
A100067 - Development Board, Arduino Mega 2560 Rev3 RETAIL, ATmega2560 MCU, 54 3.3V I/O, 16 Analogue Inputs | ARDUINO | 1 | Buy Now |
1141 - Assembled Data Logging Shield For Arduino | ADAFRUIT | 1 | Buy Now |
24-15112 - Wire, PVC, Red, 22 AWG, 100 ft, 30.5 m | STELLAR LABS | 1 | Buy Now |
OLED Character Display | ADAFRUIT | 1 | Buy Now |
Pushbutton Switch Off(On SPST 125 V 50 V 400 mA Solder | APEM | 1 | Buy Now |
Incremental Encoder 5 VDC 2 Channels 60 rpm 24 Detents 24 Pulses PEC11R Series | BOURNS | 1 | Buy Now |
Hall Effect Proximity Sensor Flange Mount 55100 Series Analogue 4.5 to 5.5 Vdc | HAMLIN | 1 | Buy Now |
AC/DC Enclosed Power Supply(PSU ITE 1 Outputs 200 W 24 V 8.4 A | TDK-LAMBDA | 1 | Buy Now |
Additional Parts:
Product Name | Quantity |
---|---|
SCHLEUNIGER CS 9100 “V” STYLE CUTTING AND STRIPPING BLADES |
1 |
Top Comments