Evan Rust
Published © GPL3+

Make Candy Sorting Easy with Machine Learning

Automatically go through your stash of candy and have it sorted into piles with the power of machine learning.

IntermediateFull instructions provided6 hours1,835
Make Candy Sorting Easy with Machine Learning

Things used in this project

Hardware components

Raspberry Pi 4 Model B
Raspberry Pi 4 Model B
×1
Camera Module V2
Raspberry Pi Camera Module V2
×1
Arduino Mega 2560
Arduino Mega 2560
×1
Stepper Motor, Mini Step
Stepper Motor, Mini Step
×1
Driver DRV8825 for Stepper Motors for Theremino System
Driver DRV8825 for Stepper Motors for Theremino System
×1
Power MOSFET N-Channel
Power MOSFET N-Channel
×1

Software apps and online services

Arduino IDE
Arduino IDE
VS Code
Microsoft VS Code
Fusion 360
Autodesk Fusion 360

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Roller Side 1

Roller Side 2

Candy Base

Schematics

Shield

Code

imageToBin

Python
from time import sleep
from picamera import PiCamera
from gpiozero import Button
from io import BytesIO
from PIL import Image
from signal import pause
import json
import subprocess
import serial

#one for each label
binList = {
    "kitkat": 0,
    "twizzler": 1,
    "reeses": 2,
    "sour patch": 3,
    "none": 4
}

ser = serial.Serial(port="/dev/ttyACM0", baudrate=115200)
camera = PiCamera()
stream = BytesIO()
resolution = (2592, 1944)

button = Button(2)

def tupleToValue(rgbValues: tuple):
    newValue = rgbValues[0] * 65536 + rgbValues[1] * 256 + rgbValues[2]
    print(f"Hex representation of the tuple {rgbValues} is: {hex(newValue)}")
    return hex(newValue)

def classifyAndSendValue(dataString: str):
    result = subprocess.run(['nodejs', 'run-impulse.js', dataString], stdout=subprocess.PIPE).stdout.decode('utf-8')
    print(result)
    result = json.loads(result)["results"]
    print(f"Result is {result}")
    maxIndex = -1.0
    currentLabel = ""
    for item in result:
        print(f'checking item {item["label"]}, value={item["value"]}')
        if item["value"] > maxIndex: 
            maxIndex = item["value"]
            currentLabel = item["label"]
    correspondingBin = binList[currentLabel]
    print(f"Bin is ", correspondingBin)
    toSend = (str(correspondingBin)+'\n').encode('utf-8')
    ser.write(toSend)
    print(f"Sent {toSend} over serial")

def processCamera():
    camera.capture(stream, resize=(96, 96), format='jpeg')
    stream.seek(0)
    image = Image.open(stream)
    image.convert("RGB")
    rgbData = list()
    numberList = list(image.getdata())
    for number in numberList:
        rgbData.append(tupleToValue(number))
    rgbDataString = ','.join(rgbData)
    #print("Raw features result is: ", rgbDataString)
    classifyAndSendValue(rgbDataString)
    sleep(2)

button.when_pressed = processCamera

camera.resolution = resolution
camera.framerate = 15
camera.start_preview()

sleep(2)

pause()

gantryMover

C/C++
#include "BasicStepperDriver.h"

// X axis STEP, DIR, EN, LIMIT_SW, SOLENOID
const uint8_t pins[] = {6, 7, 8, 26, 11};

#define MICROSTEPS 16
#define RPM 120
#define STEPS_PER_MM 200    // 200 steps (including microsteps) per mm moved
#define TOTAL_LENGTH_MM 700
#define TOWARDS_0_DIR -1
#define AWAY_FROM_0_DIR -1 * TOWARDS_0_DIR

BasicStepperDriver stepper(200, pins[1], pins[0], pins[2]);

void setup()
{
    Serial.begin(115200);
    initPins();
    stepper.begin(RPM, MICROSTEPS);
    stepper.disable();

    homePosition();
    stepper.disable();
}

void loop()
{
    
}

void serialEvent()
{
    long binToPlace = Serial.parseInt();

    long targetSteps = binToPlace * STEPS_PER_MM * 100;     // 100 mm between bins

    stepper.enable();
    stepper.move(AWAY_FROM_0_DIR * targetSteps);    // get to target
    
    digitalWrite(pins[4], HIGH);
    delay(500);     // push item off
    digitalWrite(pins[4], LOW);

    stepper.move(TOWARDS_0_DIR * targetSteps);  // return to home
    stepper.disable();
}

void initPins()
{
    pinMode(pins[3], INPUT_PULLUP);
    pinMode(pins[4], OUTPUT);

    digitalWrite(pins[4], LOW);
}

void homePosition()
{
    stepper.enable();
    if(!digitalRead(pins[3]))
        stepper.rotate(AWAY_FROM_0_DIR * 720.0); // rotate away from home

    while(digitalRead(pins[3]))
        stepper.move(TOWARDS_0_DIR * 5);
}

Credits

Evan Rust

Evan Rust

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

Comments