Skip to content

10. Machine Week - Collin, Landon, and Ryan

Members: Collin Kanofsky, Landon Broadwell, and Ryan Zhou.

File for 3D design was too large, so it can be found here. Files for code are spaced throughout the documentation.

Assignment

Group Assignment:

  • Design a machine that includes mechanism+actuation+automation+application

  • Build the mechanical parts and operate it manually

  • Document the group project and individual contributions

Machine Presentation for Neil

Machine Concept

We started the week with a few ideas for our machine, but we eventually settled on a machine specifically made to autonomously modify wires called the Cable Crafter. This includes cutting and stripping. A basic diagram we drew is shown below.

Essentially, the process begins with a wire on a spool, which is located at the beginning of our machine’s wire channel. It is pushed forwards on the machine by a series of double wheels located on either side of the channel the wire travels on. Once it reaches a certain position, a tool will strip the front of it before having a soldering iron tin it. Once the wire has traveled far enough past that position, the wire will be cut, stripped, and tinned, again, separating it into two. This process will be repeated for as long as the user wants, creating many individual wires. The second whiteboard in the above images represents the wire mechanism that will use the motor to push the wire from the spool into the channel.

Design Intent

We decided to do our cading with a bottom up approach. This means that we will build a frame or starting point and add on to it rather than building all the parts separate and making it at the end.

So we started with a lasercut frame and decided to add 3D printed corner parts to hold the plates together.

Next, we got to work on the mechanism to draw the wire through our 3D printed channels we designed. In order to only use only one motor per 2 wheels, we used 3D printed gears and metal bearings. We also used TPU as the material for the 3D printed wheels due to its flexibility. The only issue that we had was that printing TPU is difficult and the result came out stringy.

CAD: Final Designs

Full design of the machine. Top is intentionally hidden.

The linear movement sub-assembly. The linear slide is pre-manufactured so we just roughly CADed the design in order to create 3D printed mounts on top of them.

Wheel assembly with 3D printed gears that pulls the wire through the machine. Uses heat set inserts inside shaft, TPU for flexible 3D printed wheels, and metal ball bearings.

The laser cut frame with finger joints. Also has hole patterns and areas for 3d printed parts to attach to.

3D printed corner pieces to ensure structural integrity within the frame. uses heat set inserts in place of lock nuts.

Case made for the OLED and potentiometer. Parts lie at a 45 degree angle for ease of use and tunnels have been added under the electronics to make wiring easier.

3D Printing

After CADing these parts, we proceeded to 3D print them on Prusa Mini printers. We also added threads to each of the holes.

We also had to learn how to print using TPU. TPU is similar to PLA but gets very stringy if it absorbs moisture and it loves to do so. It also doesn’t print well at regular speeds so we would slow down the print next time. Below is the finished wheel print.

Laser Cutting/Assembly

The main pieces we laser cut were the frame and the holders for the rails. We used 3 sheets of 1/8th inch plywood to cut out the parts. We then proceeded to put it partially together as can be seen below. We decided to leave off the sides and the bottom at this time because we needed easy access to the areas and inside so we attached the frame all together at the end. A picture of the machine has been added below (to show the laser cut top frame which is assembled on top). The top frame is essentially the same as the bottom frame, just without the mounting holes used for the motors on the bottom.

Gantry

The gantry or as we call it, the linear slide is mainly a pre-manufactured part. We created a CAD model of it and created a plate that we would layer on top of the pre-made slider. Then, we used that plate as a baseplate for motor mounts, the wire cutter/stripper holder, and belt holder. The gantry is driven by a stationary belt holder that runs along a stepper motor with a belt pulley on one side and a bearing on the other side.

Programming

The first thing we did before even opening the arduino IDE was create a pseudo code. We also created some visual pseudo code to better understand how the code should work. This code initially had a soldering aspect integrating into it, but when we were worried about time concerns and safety concerns, we decided no to go for it.

  1. Motor 1 grabs the wire into the v-channel (wire in zero position)

  2. Motor 1 move wire into position (consistent amount)

  3. Motor 2 moves the wire cutter/stripper from the cutting position (position zero) to the stripping position

  4. Motor 3 closes the wire cutters to strip the wire

  5. Motor 1 moves the wire back to strip

  6. Motor 3 opens the wire cutters

  7. Motor 1 moves the wire until Motor 4 grabs it

  8. Motor 4 moves the wire to the length designated by the user

  9. Motor 2 moves the wire cutter to the cutting position.

  10. Motor 3 closes the wire cutter to cut

  11. Motor 2 moves wire cutter/stripper from cutting position to stripping position

  12. Motor 3 closes the wire cutters to strip the wire

  13. Motor 4 moves the wire forward to strip until it successfully strips

  14. Motor 3 opens the wire cutters

  15. Motor 4 spits out the finished wire into tray area

  16. Entire process repeats except for the initial movement.

Motor Movement

Moving the motor was probably one of the most fustrating things throughout the whole programming. We spent probably around 7 hours trying to get a motor to spin how we wanted. We tried many codes, functions, tutorials, data sheets, ect. And guess what! The problem wasn’t a software issue, it was a problem with the motor! As soon as Collin tried a different motor, our code worked. We won’t show all our past codes due to the amount but we created a function to easily use this code as shown below. How the stepper motors work is that they take a direction to spin based on a pin being HIGH or LOW, a speed to spin at, determined by a delay in microseconds, and a distance to spin. In order to greatly simplify the process of using the motors, we used a CNC shield and several motor drivers. Collin created a simple connection between EN and GND to make sure it worked properly.

To figure out the distance that the motor would spin, we first calculated the number of steps, or tiny increments of movement, were in a 1 inch. Knowing from some sample code found on this YouTube channel by Collin, we ran an initial test to get the motor to turn on, and, as previously stated, it worked. In this code, 200 steps were a full rotation, so we did (200 steps)/2π (circumference of our gear), which equaled roughly 31.831. From this starting point, we used our limited knowledge of coding in C++ to try and get the rest of the program to work. Our function for the motors consisted of a boolean value to determine the rotation, a speed value for the speed of the motor, with a larger value being a slower motor, and a distance value that would determine how far the motor would rotate. We did a simple for loop to get the steps, with the variable for distance being incorporated into the loop. After getting all this programming done, we were now able to rotate the motor a custom amount along the circumference of the gear, which was a positive start.

  // CNC Shield Stepper  Control Demo
  // Superb Tech
  // www.youtube.com/superbtech

  const int StepX = 2;
  const int DirX = 5;

  /*const int StepY = 3;
  const int DirY = 6;
  const int StepZ = 4;
  const int DirZ = 7;*/


  void setup() {
    pinMode(StepX,OUTPUT);
    pinMode(DirX,OUTPUT);
    /* pinMode(StepY,OUTPUT);
    pinMode(DirY,OUTPUT);
    pinMode(StepZ,OUTPUT);
    pinMode( DirZ,OUTPUT);*/
  }

  void XstepperMove (float distance, int speed, bool direction) {
    if (direction == true){ // Clockwise
      digitalWrite(DirX, HIGH);
    } else{ // Counter Clockwise
      digitalWrite(DirX, LOW);
    }
  //digitalWrite(DirY, HIGH);
  //digitalWrite(DirZ, HIGH);

  for(float x = 0; x<(distance*31.83098892); x++) { // moves in inches along the circumference 
      digitalWrite(StepX,HIGH);
      delayMicroseconds(speed);
      digitalWrite(StepX,LOW);
      delayMicroseconds(speed);
    } // delay for 1 second
  }

  void loop() {
    XstepperMove(6.283185, 500, true); // 6.283185 ~= 2π
    delay(500);
  }

Now that we had the basic code set up and the programming working for one motor, we extending this functionality to the two other motors that Landon had at the time. The only modifications included creating more functions for the other two motors and replicating the same wiring as the first one.

With these connections created by some specific wires we had around the lab, we uploaded the slightly modified code and ran it across three motors.

Since all three of the current motors worked, we began to program the input methods.

Input Device

After the peusdo code shown above was complete. We faced the challenge of storing multiple values using only 1 potentiometer and 1 button. At first, we took the path of using a typical analogRead(). However, there was now way to take a variable of the function and lock it in place so the next value didn’t change the previous one. We tried many things over a period of 3-4 hours until we used ChatGPT to help us. We then proceeded to use it to store values. We would ask it for a way to store values and have it change and adapt the code when we found issues or features we wanted to add.

Eventually, we ended up switching from a button and potentionmeter to a rotary encoder, and because of this, the attempts to program using the previous two items, as well as those ChatGPT prompts involved, were all recycled. This was due to the rotary encoder encapsulating the ability of both the button and and the potentionmeter in a singular component. To do this, we followed this link by How to Mechatronics in order to figure it out. Landon was responsible for this section of the project, and additional details for this section can be found on his page. The first step involved analyzing the output diagrams of the rotary encoder to know which compute which direction the encoder spins.

Also, the encoder we were using looked like this:

To wire this encoder, the GND and + pins are obviously for ground and power, respectively, the SW pin is for programming the button, the CLK pin is for output A and clockwise rotation, and the DT pin is for output B and the counter clockwise rotation. To measure the rotation of the encoder, we can check if they are equal when output A goes to 1, and the rotation is counterclockwise when so. Vice versa, the rotation is clockwise when output A and output B are not equal.

As we learned from the above tutorial, and alongsdie some help from ChatGPT, we knew that the method for making the encoder work would involve programming it to store a value determined by the amount of rotation of the encoder and stashing that value in a list each time the button is pressed. To decide the pins that would be used, we found on the website that the pins the encoder was connected to didn’t entirely matter, so we hooked them up to some available analog pins to be used a digital pins, which is a function built into the board. We chose pin A0 for the CLK, pin A3 for DT, and pin A1 for SW. Once again, there were several iterations of this code, so for the sake of conciseness, the final result of the testing will only be shown here.

  // Define the pins for the rotary encoder
  #define CLK_PIN A0
  #define DT_PIN A3
  #define SW_PIN A1

  // Variables to store the current and previous state of the encoder
  // volatile int lastEncoded = 0;
  // volatile long encoderValue = 0;

  int counter = 0;
  int CLK_state;
  int CLK_laststate;


  void setup() {
    // Set encoder pins as inputs
    pinMode(CLK_PIN, INPUT);
    pinMode(DT_PIN, INPUT);
    pinMode(SW_PIN, INPUT_PULLUP); // Internal pull-up resistor for the push button


    // Initialize serial communication
    Serial.begin(9600);
    CLK_laststate = digitalRead(CLK_PIN);   
  } 

  void loop() { 
    CLK_state = digitalRead(CLK_PIN); // Reads the "current" state of the outputA
    // If the previous and the current state of the outputA are different, that means a Pulse has occured

    if (digitalRead(SW_PIN) == LOW) {
      Serial.println("Button Pressed!");
      // Your button action code here
      // For example: toggle a LED
      // digitalWrite(LED_PIN, !digitalRead(LED_PIN));
      delay(250); // Debouncing delay   
    }


    if (CLK_state != CLK_laststate){     
      // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
      if (digitalRead(DT_PIN) != CLK_state) { 
        counter ++;
      } else {
        counter --;
      }
      Serial.print("");
      Serial.println(counter);
    } 
    CLK_laststate = CLK_state; // Updates the previous state of the outputA with the current state

    if (counter > 40 || counter <-40){
      counter = 0;
    }

  }

This code was created for the purpose of just communicating between the encoder and the computer, with no major interaction happening with the motors yet. The way that this code works is very simple and has two main sections - the button part, which is just like any other push button, and the encoder part, which, as previously explained, checks the rotation and adjusts the value, or “counter”, accordingly. All that this code did for now was that it successfully displayed the correct inputs and the correct times the button is pressed in the Serial monitor. However, we still needed to integrate the motor code into this and store the values at different iterations, so that was the next step.

Combining Encoder and Motors

Firstly, we tried to store several values using a case structure in C++ based on the knowledge Collin got from ChatGPT, but we ended up opting for a design that used a simple list to store the current value of the potentiometer to the same index as the current button press. After three presses, the program would display all of the inputted values. A step that was not yet incorporated was translating these readings into actual, usable values for the motors, so for now they were a bit arbitrary and we simply put random numbers into the functions at the bottom of the loop.

Once this program was fully set up, we experienced a few repeated difficulties with the program not outputting anything onto the Serial monitor. We discovered this to be due to how the functions for the motors had initially been placed above the loop and causing the entire program to not progress, but that was corrected by placing them at the bottom of the program, making it fully functional (save for a few panic attacks relating to the serial monitor needing to just be closed an re-opened).

This video is shortened and sped up due to storage concerns, but the general gist of this program is that it waits for the various encoder inputs to be determined, displays them, and then calls the motor functions to operate. One other finicky error that we encountered was that the program would only take the inputs of 0 or -1, which similar to the previous error in how the way the functions were being called intefered with the loop and the rest of the code.

Since our final product would not include the Serial monitor to displays information, we had work to dispaly this data on the OLED.

OLED

To create this code, we copied some information from an example in the Adafruit SSD1306 OLED library. We used the sample code presented to modify our existing code, with the following being the main changes that we made.

The addition of the required libraries and # definitions, as well as the declaration of the OLED object.

  #include <SPI.h>
  #include <Wire.h>
  #include <Adafruit_GFX.h>
  #include <Adafruit_SSD1306.h>

  #define SCREEN_WIDTH 128 // OLED display width, in pixels
  #define SCREEN_HEIGHT 64 // OLED display height, in pixels

  #define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
  #define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
  Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

Putting the lines to initialize and start the OLED at the beginning of the setup function.

    Serial.begin(9600);

    // initialize OLED display with address 0x3C for 128x64
    if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
      Serial.println(F("SSD1306 allocation failed"));
      while (true);
    }

    delay(2000);         // wait for initializing
    oled.clearDisplay(); // clear display

    oled.setTextSize(2);          // text size
    oled.setTextColor(WHITE);     // text color
    oled.setCursor(0, 0);        // position to display
    oled.println("Test."); // text to display
    oled.display();
    delay(1000);         // show on OLED
    oled.clearDisplay();
  ```

  Integrating the OLED programming into the loop function and changing the displaying aspect of the encoder readings.

  ```
    oled.setTextSize(1);          // text size
    oled.setTextColor(WHITE);     // text color


    CLK_state = digitalRead(CLK_PIN);

    if (digitalRead(SW_PIN) == LOW) {

      Serial.println("Value Stored!");
      oled.display();
      storedValues[buttonPressCounter] = counter; // Store the current value
      buttonPressCounter++; // Increment button press counter
      if (buttonPressCounter >= 3) { // If pressed three times
        // Print all stored values
          oled.clearDisplay();
          oled.setCursor(5, 10);        // position to display
          oled.print("Length: ");
          oled.println(abs(storedValues[0]));
          length = abs(storedValues[0]);

          oled.setCursor(5, 20);
          oled.print("End Length: ");
          oled.println(abs(storedValues[1]));
          end_length = abs(storedValues[1]);

          oled.setCursor(5,30);
          oled.print("Amount: ");
          oled.println(abs(storedValues[2]));
          oled.display();
          valstored = true;
        }
        // Reset button press counter and clear stored values

      delay(250); // Debouncing delay
    } 

After these changes were made and some other minor wiring troubleshooting, we were able to make the code fully work. There was still some math left to do in order to convert these values into actual working amounts for the program to run on, but this was good progress for now. The current status of the OLED was that it would display a test message at the start to confirm that the OLED is properly communicating over I2C, and then each time the button on the encoder is pressed, the screen will display which input the code is on.

Since all these devices and the motors were set up, we starting assembling the entire machine.

Laser Cutting/Assembly

For the beginning part of the assembly, Collin and Landon used the OnShape plugin Kiri:Moto, which could convert each of the necessary pieces into DXFs to be laser cut on cardboard for a test cut. However, when we imported these DXFs into CorelDraw, we recieved an error saying “Unrecoverable Error,” but Collin told me to export them as a SVG instead of DXF, which worked. We then able to laser cut the file to see roughly how the design would turn out.

From here, we simply cut out the same cuts on wood this time. Unfortunately, before we could remember to take photos of the entire cut alone, we assembled part of the design using heat-set inserts to attach the 3D printed corner joints to the wood, thereby connecting the front, back, top, and inner channel holders together. Additionally, they placed the v-channels into the assembly using more heat-set inserts.

Now that we had the basic pieces, we began to assemble the gantry. The first step was to attach the bar for the gantry to the bottom wood piece.

Then, Collin designed the mechanism for what would be on the gantry through screwing a 3D holder for one of the motors, as well as a piece for the wire cutters onto another 3D piece that holds the belt, all of which would be put onto the bearing plate.

This part of the assembly was attached to the main body, the wire cutters were fit neatly into the slot, and an elastic string was looped around some different holes to serve as the pulley mechanism for the wire cutters.

Alongside this gantry system and the previously displayed top section, we screwed in the remaining motors with their corresponding 3D cases, and assembled it all together! Fortunately, after a bit of finagling, we got everything in place and fitting nicely together.

Since everything was in place, we got to the final steps.

Final Product

For the final product, we first had to ensure our code was entirely working. Shown below is the final working code, and at the start of the documentation is the display for our machine partially working.

  #include <SPI.h>
  #include <Wire.h>
  #include <Adafruit_GFX.h>
  #include <Adafruit_SSD1306.h>

  #define SCREEN_WIDTH 128 // OLED display width, in pixels
  #define SCREEN_HEIGHT 64 // OLED display height, in pixels

  #define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
  #define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
  Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

  #define CLK_PIN A0
  #define DT_PIN A3
  #define SW_PIN A1 

  int counter = 0;
  int CLK_state;
  int CLK_laststate;
  int storedValues[3]; // Array to store the values
  int buttonPressCounter = 0; // Counter for button presses


  const int StepX = 2;
  const int DirX = 5;
  const int StepY = 3;
  const int DirY = 6;
  const int StepZ = 4;
  const int DirZ = 7;

  const int StepA = 12;
  const int DirA = 13;

  int distance = 9;
  int length=1;
  int amount=0;
  int end_length=0;


  bool valstored = false;

  void setup() {

    Serial.begin(9600);

    // initialize OLED display with address 0x3C for 128x64
    if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
      Serial.println(F("SSD1306 allocation failed"));
      while (true);
    }

    delay(2000);         // wait for initializing
    oled.clearDisplay(); // clear display

    oled.setTextSize(2);          // text size
    oled.setTextColor(WHITE);     // text color
    oled.setCursor(0, 0);        // position to display
    oled.println("Test."); // text to display
    oled.display();
    delay(1000);         // show on OLED
    oled.clearDisplay();



    pinMode(StepX,OUTPUT);
    pinMode(DirX,OUTPUT);
    pinMode(StepY,OUTPUT);
    pinMode(DirY,OUTPUT);
    pinMode(StepZ,OUTPUT);
    pinMode(DirZ,OUTPUT);

    pinMode(CLK_PIN, INPUT);
    pinMode(DT_PIN, INPUT);
    pinMode(SW_PIN, INPUT_PULLUP);

    pinMode(StepA, OUTPUT);
    pinMode(DirA, OUTPUT);

    CLK_laststate = digitalRead(CLK_PIN);   
  } 


  void loop() { 
    oled.setTextSize(1);          // text size
    oled.setTextColor(WHITE);     // text color


    CLK_state = digitalRead(CLK_PIN);

    if (digitalRead(SW_PIN) == LOW) {

      Serial.println("Value Stored!");
      oled.display();
      storedValues[buttonPressCounter] = counter; // Store the current value
      buttonPressCounter++; // Increment button press counter
      if (buttonPressCounter >= 3) { // If pressed three times
        // Print all stored values
          oled.clearDisplay();
          oled.setCursor(5, 10);        // position to display
          oled.print("Length: ");
          length = (abs(storedValues[0]) * .375 + 10);
          oled.println(length);
          oled.println(" in.");

          oled.setCursor(5, 20);
          oled.print("End Length: ");
          end_length = (abs(storedValues[1]) * 0.009375 + 0.125);
          oled.println(abs(storedValues[1]));
          oled.println(" in.");

          oled.setCursor(5,30);
          oled.print("Amount: ");
          amount = (abs(storedValues[2]) * .225 + 1);
          oled.println(amount);
          oled.display();
          valstored = true;
        }
        // Reset button press counter and clear stored values

      delay(250); // Debouncing delay
    } 

    if (CLK_state != CLK_laststate){     
      if (digitalRead(DT_PIN) != CLK_state) { 
        counter ++;
      } else {
        counter --;
      }
    CLK_laststate = CLK_state;

      if (buttonPressCounter == 0){
        oled.clearDisplay();
        oled.setCursor(20,30);
        oled.print("Length = ");
        oled.println(abs(counter) * 0.375 + 10);
        oled.display();
      } else if (buttonPressCounter == 1){
        oled.clearDisplay();
        oled.setCursor(20,30);
        oled.print("End Length = ");
        oled.print(abs(counter) * 0.009375 + 0.125);
        oled.display();
      } else if (buttonPressCounter = 2){
        oled.clearDisplay();
        oled.setCursor(20,30);
        oled.print("Amount = ");
        oled.println(abs(counter) * .225 + 1);
        oled.display();
      }
      Serial.print("Counter: ");
      Serial.println(counter);
    } 

    if (counter >= 40 || counter <=-40){
      counter = 0;
    }


    if (valstored == true){
      for(int i = 0; i < amount; i++){
    delay(3000);
    XstepperMove(9, 8000, false); // initial movement
    delay(2000);
    XstepperMove(end_length, 7000, false); // endlength
    delay(2000);
    ZstepperMove(1.8, 4000, false);  // cutter moving
    delay(1500);
    YstepperMove(22.5, 5000, false); // clamps wire cutter
    delay(1000);
    XstepperMove(5, 8000, true); // strips wire
    delay(2050);
    YstepperMove(22.5, 5000, true); // unclamps wire cutter
    delay(3000);
    ZstepperMove(1.8, 4000, true); // moves cutter back
    delay(3000);
    XstepperMove(17, 7000, false); // moves wire to other end - LENGTH
    AstepperMove(5, 5000, true);
    delay(1000);
    ZstepperMove(2 ,4000, false);
    delay(1000);
      }
    }

  }



  void XstepperMove_start(float dist, int speed, bool direction) {
    if (direction == true) {  // Clockwise
      digitalWrite(DirX, HIGH);
    } 
    else {  // Counter Clockwise
      digitalWrite(DirX, LOW);
    }

    for (float x = 0; x < ((dist * 31.83098892) + 30); x++) {  // moves in inches along the circumference
      digitalWrite(StepX, HIGH);
      delayMicroseconds(speed);
      digitalWrite(StepX, LOW);
      delayMicroseconds(speed);
    }  
  }

  void XstepperMove(float dist, int speed, bool direction) {
    if (direction == true) {  // Clockwise
      digitalWrite(DirX, HIGH);
    } 
    else {  // Counter Clockwise
      digitalWrite(DirX, LOW);
    }

    for (float x = 0; x < ((dist * 31.83098892) + 30); x++) {  // moves in inches along the circumference
      digitalWrite(StepX, HIGH);
      delayMicroseconds(speed);
      digitalWrite(StepX, LOW);
      delayMicroseconds(speed);
    }  
  }

  void YstepperMove(float distance, int speed, bool direction) {
    if (direction == true) {  // Clockwise
      digitalWrite(DirY, HIGH);
    } 
    else {  // Counter Clockwise
      digitalWrite(DirY, LOW);
    }

    for (float x = 0; x < (distance * 31.83098892); x++) {  // moves in inches along the circumference
      digitalWrite(StepY, HIGH);
      delayMicroseconds(speed);
      digitalWrite(StepY, LOW);
      delayMicroseconds(speed);
    }  
  }

  void ZstepperMove(float distance, int speed, bool direction) {
    if (direction == true) {  // Clockwise
      digitalWrite(DirZ, HIGH);
    } 
    else {  // Counter Clockwise
      digitalWrite(DirZ, LOW);
    }

    for (float x = 0; x < (distance * 31.83098892); x++) {  // moves in inches along the circumference
      digitalWrite(StepZ, HIGH);
      delayMicroseconds(speed);
      digitalWrite(StepZ, LOW);
      delayMicroseconds(speed);
    }  
  }

  void AstepperMove(float distance, int speed, bool direction) {
    if (direction == true) {  // Clockwise
      digitalWrite(DirA, HIGH);
    } 
    else {  // Counter Clockwise
      digitalWrite(DirA, LOW);
    }

    for (float x = 0; x < (distance * 31.83098892); x++) {  // moves in inches along the circumference
      digitalWrite(StepA, HIGH);
      delayMicroseconds(speed);
      digitalWrite(StepA, LOW);
      delayMicroseconds(speed);
    }  
  }

Once this program was fully set up, we experienced a few repeated difficulties with the program not outputting anything onto the Serial monitor. We discovered this to be due to how the functions for the motors had initially been placed above the loop and causing the entire program to not progress, but that was corrected by placing them at the bottom of the program, making it fully functional (save for a few panic attacks relating to the serial monitor needing to just be closed an re-opened).

This video is shortened and sped up due to storage concerns, but the general gist of this program is that it waits for the various encoder inputs to be determined, displays them, and then calls the motor functions to operate. One other finicky error that we encountered was that the program would only take the inputs of 0 or -1, which similar to the previous error in how the way the functions were being called intefered with the loop and the rest of the code.

Another issue was that the first motor wasn’t spinning properly, so we looked at the TPU wheels and saw that they were grinding against the holes in the v-channel.

To fix this, Ryan widenned the gap on the 3D model and re-printed the file. While the belt worked fine, there were difficulties with the motor on the gantry meant to close the wire cutters. This, we believe, was due to the motor not having a flat edge on one side and instead being fully circular, as well as the string being under too much testing.

A second major issue that we encountered was how the wire, after being fed through those yellow TPU wheels, would sometimes bend upwards and force us to reset the program after pushing the wire back into place. The solution for this issue was the inclusion of 3D pieces that fit into the channel which would prevent the wire from coming up, so several of these were printed out.

A third issue that arose was various problems with the clamping motor and spool/gear. The first part of this was that the 3D print had one messy and one clean side, leading to it being caught on the messy 3D print many times, the second part was the aforementioned issue of the spool/gear coming off, and the final issue is that the motor simply would not rotate the gear fully and properly to clamp the wire cutters. We tried changing to stronger wire, but recieved no results.

Problems Encountered

When we first began testing our machine after assembling it, we encountered the issue of bending wires. We had anticipated this issue previously, and so we had already designed and printed angled covers that were supposed to keep the wires down. However, these would sometimes not be enough, as the wires would go too high before even entering the covers, getting stuck on them instead.

Another issue we encountered was with wiring our OLED and potentiometer. Because of how small we made the holes (which allowed our wires to get in/out of the case) on the case, we couldn’t tell which wire was aligned to which pin.

The fourth and largest issue that we had to deal with was the realization that, after running the program many times and recieving the same result, the motor did not have enough power to strip the wire after it is clamped. This meant that all we could truly do was cut wires with the machine, which was very disappointing after all the effort.

Below is a video of part of the final process, subject to being updated.

Final Product Updated and Working

After not working on the machine for a while, we came back to it and replaced the motor that was not working properly. Then, we rescrewed everything back into place and ran the code once more, just attempting to get it to work at least once.

At the end of the process, we helped pull the wire out so it wouldn’t fall down and get messed up. The first part of the video shows the wire being pulled through the spot with the wire cutter, the second part shows the wire cutting, and the last part shows the wire being pushed out the end.

A Few Clarifications

Clarifications: We did manage to get the encoder and OLED screen working (yay!), and a video has been added below to show the basics of this electronics setup. Please keep in mind that this was recorded before our final video, so we had not yet gotten the wire cutter to work at this point.

An additional clarification: the board/microcontroller that we used to control our machine was an Arduino Uno with a CNC motor shield mounted on top of it. When it comes to how we integrated it with the rotary encoder + OLED screen, you can see that in the beginning few frames of the video, and a simplified explanation of this integration is as follows. We essentially just connected the OLED screen and rotary encoder to their corresponding pins on the CNC motor shield by referencing the motor shield’s pinout (you can find one linked here). As the pinout shows, the OLED screen’s pins are connected to the I2C pins of the CNC motor shield, and the rotary encoder is connected to separate pins of the motor shield that go to programmable pins of the Arduino Uno. Furthermore, an electronics diagram has been included below as well to help you understand how everything was wired.

As the legend at the top states, blue rectangles are where the motors were placed, green is for the OLED screen’s pins, and yellow is for the rotary encoder. Additionally, I would like to add one small correction, which is that the rotary encoder’s PWR pin should be connected to the “5V” pin directly next to where the OLED’s GND pin is connected, and the encoder’s GND pin can be connected to any of the black pins on the rightmost side of the CNC motor shield (highlighted with an orange rectangle).

Hero Shots

Side View

Front View

Future Plans

Future developments of this design include making the stripper actually work, adding a solder iron functionality to tin each wire, customizing the wire cutter functionality to be something we design rather than a premade part, and overall making the design more efficient.


Last update: July 8, 2024