What the Fork: Own Your Fork

by canadasushi in Circuits > Arduino

145 Views, 4 Favorites, 0 Comments

What the Fork: Own Your Fork

IMG_62821.JPG
video

This project was conducted as part of the Computational Design and Digital Fabrication seminar in the ITECH masters program.

Authors : Chris & Zahra


Do you have one of those things that you want to use as yours ONLY?


We played with the core element that gives an object functionality. In such cases, it could be a plastic membrane of a water bottle or a padding area of a ping-pong racket.

What about everyday object such as pencils, chairs, or forks?

The common element of these objects is that their functions are only fulfilled when elements are rigid. We furthered that idea of manipulating the core functional element, then subverting it in order to remove its usefulness. By actuating and sensing, the object actively chooses whose hand to be used.

Our fork comes with a manipulatable joint that is limp under an anonymous user, then straightens back to rigid state to be useful when the main user gets their hands on it.

Supplies

3D printing machine (Prusa i3 MK3S+ is used)

PLA filament

Nylon string 0.4mm

SG90 Micro servo x 2

9V battery

Arduino Nano 33 BLE

Voltage regulator power module

10k resistor

TACT Switch Push Button

Jumper wires

Super glue

Soldering iron

Heat shrink wrap

CAD

pic_5.png
gif_1.gif
3.png
4.png

The goal of this fork is to maintain its compact and relatively in-scale final product. Therefore, a complete 3D model is carefully designed with millimeter-precise models of all parts.

To achieve both limping and straightening, you need a mechanism that can freely bend and easily lock back to straight. In this model, print-in-place ball joint chains are iteratively designed.

In comparison to the universal joints that are widely used in those 3D printed dragons, ball joints achieve larger degree of freedom, and larger radius of curvature.

First, try out the print-in-place ball joint test with a tolerance of 0.2mm. The settings that I have experimented with were print speed and flow rate, support or without support. At the end, 100% with 95 flow rate(which varies between printers and filament type) and no support with brim setting gave the most promising results. I recommend furthermore tweaks in your printer such as the layer height and print speed, as well as printing chain model to get consistent working parts.

In the chain model, there are more features added to achieve our goal.

  1. linear joint to also have sliding mechanism, such that when relaxed, it elongates even more, and contraction pulls them tighter
  2. Coupled spherical profile between joints such that at contraction, they match to achieve the original linear state

These settings allowed to actuate the mechanism with relatively low torque.

Then, the body design takes advantage of precisely measured parts to fit everything compact. The full assembly instruction is found below.


The full library used in this project can be found and downloaded under these links

Full model

SG90 Servo

Power module

Fork

Button

Arduino Nano 33 BLE

9V battery

Printing

5.jpg
2.jpg

3D printing is always a constant fight with digital model and physical matter. Try lowering speed for crisp first layer adhesion, bed leveling calibration. Increasing flow rate has been demonstrated to work against the constant tolerance. Remove all overhang by filleting.

Necessary prints consist of 4 parts: the fork, ball joint chain, front and back casing.

Assembly Part 1

pic_1.jpg
Exploded.gif

Assembly sequence follows below.

  1. Thread the nylon string through the 4 holes of ball joint chain.
  2. Tie a knot on the top area of the joint - towards the fork.
  3. Add a dap of super glue to fix in place.
  4. Leave about 8 inches of strings and repeat for all holes.
  5. Join fork part to ball joint chain. These two parts come with press fit detail. Fix with a dap of superglue.
  6. Join joint part to back casing part with super glue. These two parts come with snug fit coupled detail.
  7. Check if servo fits into the detail without any friction.
  8. Wind each end of nylon to two opposite side of servo wings. Don't tighten yet
  9. Place the servo in place, pull the pair of wires equally to straighten the mechanism, then tie a knot.

At the end you will have top and bottom strings attached to a one servo, left and right string attached to another.

Wiring + Assembly Part 2

pic_2.png
pic_3.png
useless Machine_bb.png

The circuit is pretty simple as all parts make discrete connections.

For all connections, I recommend stripping, soldering and shrink wrapping to preventing any shorts happening. Also, I connected all the 5V together and ground together to make it simple.

Servo connections:

brown/black : GND

yellow : PWM

red : 5V

Button: //adding resistor makes button to signal LOW when not pressed.

Top left: signal

Bottom left: 5V

Bottom right: GND + 10K resistor


Once the wiring is done, you are ready for final assembly! Take a break and take a haribo :)

Final assembly sequence:

  1. Insert two servo motor each on bottom and top case
  2. Press fit arduino nano into bottom case detail
  3. Glue the user button on the side
  4. Add power supply board
  5. Add 9V battery
  6. Pack everything nice and close the lid!

Trying Out

Actuation test 1
Actuation test 2

It is important to check each step in hardware to not have last minute panick! Check if everything is working with a simple sweep code.

Coding

IMG_8618__1__MOV_AdobeExpress (1).gif
Untitled Diagram.drawio.png

The logic is simple, once it detects motion, the fork will go limp. If the button is pressed, stay stiff.

The code below syncs inbuilt IMU on arduino Nano with servo movement. The machine remembers its initial position and rotation when it initiates, then if the movement is significant, the servo makes the joint bend towards to gravity.


#include <Servo.h>
#include <Arduino_LSM9DS1.h>


const int upDownServoPin = 8;
const int leftRightServoPin = 7;
const int buttonPin = 2;


Servo upDownServo;
Servo leftRightServo;


float x, y, z;


int threshold = 0.04;


int buttonState = 0;


int middleUD = 90;
int middleLR = 90;
float xInitPos, yInitPos, zInitPos = 0;


int offset = 30;
int currentPosUD;
int currentPosLR;


int d = 3;
void setup() {
  // put your setup code here, to run once:
  
  SerialBegin();
  IMUSetup();
  ServoSetup();
  pinMode(buttonPin, INPUT);


  getInitialPos(400);


}


void loop() {


  readAccel();

}


bool GetButtonState(){
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {

    return true;


  } else {


    return false;
    
  }


}


void readAccel(){


  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);

    delay(100);


    if (checkIfNotMoving()){
      GoStraight();
      //Serial.println("not moving");
    }


    else{
      if (!GetButtonState()){
        getDominantAxis(x,y,z);
      }
      
    }
    
  }


}


bool checkIfNotMoving(){

  if (abs(zInitPos - z) < 0.08 && abs(yInitPos - y) < 0.08){
    
    return true;
  }else{
    return false;
  }


}


void getDominantAxis(float x, float y, float z){


  
  if (abs(z) > abs(y)){
  // fork is up or backwards
    if (z > 0){
    //Serial.println("Up");
    GoLimp(0,1);
    }
    else if (z < 0){
    //Serial.println("Down");
    GoLimp(0,-1);
    }
  }
  else if (abs(y) > abs(z)){
  // fork is tilted right or left
    if (y < 0){
      //Serial.println("Right");
      GoLimp(1,1);
    }
    else if (y > 0){
      //Serial.println("Left");
      GoLimp(1,-1);
    }
  }
  


}


void GoLimp(int servo, int dir){


  if (servo == 0 && dir == 1){
    Rotate(0, middleUD + offset);
    Rotate(1, middleLR);
  }
  else if(servo == 0 && dir == -1){
    Rotate(0, middleUD - offset);
    Rotate(1, middleLR);
  }
  else if(servo == 1 && dir == 1){
    Rotate(1, middleLR - offset);
    Rotate(0, middleUD);
    
  }
  else if(servo == 1 && dir == -1){


    Rotate(1, middleLR + offset);
    Rotate(0, middleUD);


  }


}


void Rotate(int index, int angle){
  if (index == 0){ //UD moving
    if (currentPosUD < angle){ //pos 45, targetAngle 90


      for (int i = currentPosUD; i < angle; i++){
        upDownServo.write(i);


        delay(d);
      }
      currentPosUD = angle;


    }
    else{ //pos 90, targetAngle 45


      for (int i = currentPosUD; i > angle; i--){
        upDownServo.write(i);


      delay(d);
      }
      currentPosUD = angle;
    }
    
  }else{


    if (currentPosLR < angle){ //pos 45, targetAngle 90


      for (int i = currentPosLR; i < angle; i++){
        leftRightServo.write(i);


        delay(d);
      }
      currentPosLR = angle;


    }
    else{ //pos 90, targetAngle 45


      for (int i = currentPosLR; i > angle; i--){
        leftRightServo.write(i);


      delay(d);
      }
      currentPosLR = angle;
    }

  }

}


void GoStraight(){
  
  upDownServo.write(middleUD);
  leftRightServo.write(middleLR);
  currentPosUD = middleUD;
  currentPosLR = middleLR;
}


//------------setup------------
void SerialBegin(){


  Serial.begin(9600);


  while (!Serial);
  //Serial.println("Serial Port Initiated");
}


void ServoSetup(){
  upDownServo.attach(upDownServoPin);
  leftRightServo.attach(leftRightServoPin);
  GoStraight();
}


void IMUSetup(){


  if (!IMU.begin()) {


    //Serial.println("Failed to initialize IMU!");


    while (1);


  }


  //Serial.print("Accelerometer sample rate = ");
  //Serial.print(IMU.accelerationSampleRate());
  //Serial.println("Hz");


}


void getInitialPos(int sampleSize){
  
  float x1,y1,z1;
  


  for(int i = 0; i < sampleSize; i++){
  IMU.readAcceleration(x1, y1, z1);
  xInitPos += x1;
  yInitPos += y1;
  zInitPos += z1;
  }


  xInitPos = xInitPos / sampleSize;
  yInitPos = yInitPos / sampleSize;
  zInitPos = zInitPos / sampleSize;

}


Downloads

Final Remarks

You finally have your OWN fork that only YOU can use. In other's hands, it is totally useless ㋡

Have fun with it!