Version 11
    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 NameManufacturerQuantity
    Buy KitBuy Kit

    Stepper Motor Bipolar 1 A Two Phase 3.4 ohm 6.5 mH

    SANYO DENKI - SANMOTION1Buy NowBuy Now

    Stepper Motor Power Step High Torque Bipolar 294 in-oz 2.8 A Two Phase 1.1 ohm 3.8 mH

    LIN ENGINEERING1Buy NowBuy Now
    TMCM-1070 -  Stepper Motor Driver, 2-Phase, Single Axis, 2.8A, 24V DC Output, USB, RS485, CANTRINAMIC1Buy NowBuy Now
    Motor Driver R701 Microstepping Two Phase 12 to 80 Vdc 7 A 560 W 200 kHz LIN ENGINEERING1Buy NowBuy Now
    A100067 -  Development Board, Arduino Mega 2560 Rev3 RETAIL, ATmega2560 MCU, 54 3.3V I/O, 16 Analogue InputsARDUINO1Buy NowBuy Now
    1141 -  Assembled Data Logging Shield For ArduinoADAFRUIT1Buy NowBuy Now
    24-15112 -  Wire, PVC, Red, 22 AWG, 100 ft, 30.5 mSTELLAR LABS1Buy NowBuy Now
    OLED Character DisplayADAFRUIT1Buy NowBuy Now
    Pushbutton Switch Off(On SPST 125 V 50 V 400 mA Solder APEM1Buy NowBuy Now
    Incremental Encoder 5 VDC 2 Channels 60 rpm 24 Detents 24 Pulses PEC11R Series BOURNS1Buy NowBuy Now
    Hall Effect Proximity Sensor Flange Mount 55100 Series Analogue 4.5 to 5.5 Vdc HAMLIN1Buy NowBuy Now
    AC/DC Enclosed Power Supply(PSU ITE 1 Outputs 200 W 24 V 8.4 A TDK-LAMBDA1Buy NowBuy Now

     

    Additional Parts:

     

    Product NameQuantity

    SCHLEUNIGER CS 9100 “V” STYLE CUTTING AND STRIPPING BLADES

    1