Evan Rust
Published © GPL3+

CNC Part Picking Machine

Use PHP and MySQL to control a machine that will retrieve parts so you no longer have to dig for that 330 ohm resistor!

AdvancedFull instructions provided20 hours12,250

Things used in this project

Hardware components

DFRobot Raspberry Pi 3
×1
Arduino UNO
Arduino UNO
×1
Driver DRV8825 for Stepper Motors for Theremino System
Driver DRV8825 for Stepper Motors for Theremino System
×2
Capacitor 100 µF
Capacitor 100 µF
×2
DFRobot Servo Gripper
×1
DFRobot Timing Belt
×2
DFRobot 5MM Timing Pulley
×2
DFRobot Linear Bearing 6mmx12mm
×4
DFRobot Ball Bearing 8mmx12mm
×1
Machine Screws: 8mm,3mm,4mm
×1
25x20mm 5V Electromagnet
×1
MOSFET N-channel
×1
Rectifier Diode 1N4001
×1
NEMA 17 Stepper Motor
OpenBuilds NEMA 17 Stepper Motor
×2

Software apps and online services

Arduino IDE
Arduino IDE
Fusion
Autodesk Fusion
Brackets IDE
MySQL Server
Apache24 Webserver

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
CNC Router
Cordless Drill
A real lifesaver

Story

Read more

Custom parts and enclosures

Thingiverse Link

A link to the thingiverse repo

Code

Arduino Uno Code

C/C++
#include <Arduino.h>
#include <Servo.h>
#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200
#define RPM 60

//1:32 step ratio
#define MICROSTEPS 32

#define MM_REV_RATIO 44.5 //MM moved per one rotation
#define GRID_COEFFICIENT 40 //for x,y grid location to be converted into mm

#define X_OFFSET 20
#define Y_OFFSET 10

#define Y_LIM 2
#define X_LIM 3

//y axis stepper DIR, y axis stepper STEP, x axis stepper DIR, x axis stepper STEP, magnet, z axis servo
int8_t pins[6] = {8,9,10,11,6,5};

//X axis pos, Y axis pos
float current_positions[2] = {0.0, 0.0};
int servo_limits[2] = {60,30}; //z axis up, z axis down

BasicStepperDriver stepperY(MOTOR_STEPS, pins[0], pins[1]);
BasicStepperDriver stepperX(MOTOR_STEPS, pins[2], pins[3]);
Servo z_axis_servo;

void moveDistance(float distance, BasicStepperDriver& stepper){
  float stepsPerRev = MOTOR_STEPS * MICROSTEPS;
  float distancePerStep = MM_REV_RATIO / stepsPerRev;
  int steps_needed = round(distance / distancePerStep);
  Serial.print("Moving: ");
  Serial.println(steps_needed);
  stepper.move(-steps_needed);
}

void homeAxes(){
  if(!digitalRead(Y_LIM)){
    moveDistance(10, stepperY);
  }
  if(!digitalRead(X_LIM)){
    moveDistance(10, stepperX);
  }
  bool Y_lim_state = digitalRead(Y_LIM);
  bool X_lim_state = digitalRead(X_LIM);
  while(Y_lim_state){
    stepperY.move(1);
    delay(2);
    Y_lim_state = digitalRead(Y_LIM);
  }
  while(X_lim_state){
    stepperX.move(1);
    delay(2);
    X_lim_state = digitalRead(X_LIM);
  }

  moveDistance(X_OFFSET,stepperX);
  moveDistance(Y_OFFSET,stepperY);
  
  current_positions[0] = 0.0;
  current_positions[1] = 0.0;
  raise_gripper();
  delay(1000);
  magnet(false);
}

void raise_gripper(){
  z_axis_servo.write(servo_limits[0]);
}

void lower_gripper(){
  z_axis_servo.write(servo_limits[1]);
}

void magnet(bool state){
  digitalWrite(pins[4],state);
}

void init_servos(){
  z_axis_servo.attach(pins[5]);
  raise_gripper();
  magnet(false);
}

void move_machine(float x, float y){
  float distanceToMove = (x * GRID_COEFFICIENT) - current_positions[0];
  moveDistance(distanceToMove, stepperX);
  current_positions[0] = x * GRID_COEFFICIENT;
  distanceToMove = (y * GRID_COEFFICIENT) - current_positions[1];
  moveDistance(distanceToMove, stepperY);
  current_positions[1] = y * GRID_COEFFICIENT;
}

void setup() {
  Serial.begin(115200);
  stepperY.begin(RPM, MICROSTEPS);
  stepperX.begin(RPM, MICROSTEPS);
  pinMode(Y_LIM, INPUT_PULLUP);
  pinMode(X_LIM, INPUT_PULLUP);
  pinMode(pins[4], OUTPUT);
  magnet(false);
  init_servos();
  homeAxes();
}

void loop() {
  if(Serial.available()>0){
    String command = Serial.readStringUntil(',');
    if(command=="MOVE"){
      float locationX = Serial.parseFloat();
      float locationY = Serial.parseFloat();
      locationX --;
      locationY --;
      magnet(true);
      delay(1000);
      raise_gripper();
      delay(1000);
      move_machine(locationX, locationY);
      magnet(false);
      delay(1000);
      lower_gripper();
      delay(1000);
      magnet(true);
      delay(1000);
      raise_gripper();
      move_machine(0, 0);
      lower_gripper();
      delay(1000);
      magnet(false);
      delay(10000);
      magnet(true);
      delay(1000);
      raise_gripper();
      move_machine(locationX, locationY);
      lower_gripper();
      delay(1000);
      magnet(false);
      delay(1000);
      raise_gripper();
      delay(1000);
      move_machine(0, 0);
    }
    else if(command=="HOME"){
      homeAxes();
    }
  }

}

Python Code

Python
import MySQLdb
from flask import Flask, abort, request
from serial import Serial

app = Flask(__name__)

ser = Serial("COM3",baudrate=115200)

name = ""
category = ""
locationX, locationY = 0, 0

@app.route('/',methods=['GET','POST'])
def retrieve():
    name = str(request.args.get('name'))
    if "%20" in name:
        name = name.replace("%20"," ")
    category = str(request.args.get('category'))
    if "%20" in category:
        category = category.replace("%20"," ")
    print(name+category)
    cur.execute("SELECT * FROM parts WHERE name LIKE '"+name+"' AND category LIKE '"+category+"'")

    for row in cur.fetchall():
        locationX = int(row[5])
        locationY = int(row[6])
        print("id=%d, category=%s, name=%s, quantity=%d, x=%d, y=%d" % (row[0], row[1], row[2], row[3], row[5], row[6]))
        
    ser.write(str.encode("MOVE,"+str(locationX)+","+str(locationY)+"\n"))
    return "done"

db = MySQLdb.connect(host="IP of mysql server",user="username",passwd="password",db="components")

cur = db.cursor()
    
if __name__=='__main__':
    try:
        app.run(host='0.0.0.0',port=5000)
    except:
        db.close()
        ser.close()

Webpage Repo

Credits

Evan Rust

Evan Rust

122 projects • 1080 followers
IoT, web, and embedded systems enthusiast. Contact me for product reviews or custom project requests.

Comments