top of page

Color Sorter Arduino

  • Writer: Issac Alvarez
    Issac Alvarez
  • Apr 14, 2022
  • 9 min read

Updated: Apr 20, 2022


Overview:


Objective:

For our final project for Microcomputers 1, we were tasked to be creative and utilize all previous knowledge we gathered from our class labs to create a project. With the help of fellow classmates Matt Ludwig and Alex Paez, we decided it would be a great idea to base our project around a TCS3200 Color Recognition Sensor. Due to monetary, practicality, and time constraints, we decided that we should make the sensor be able to identify red and black checker pieces and sort them. Therefore the color sensor would be able to recognize between three different conditions:

  • Red

  • Black

  • None

Although we recognize there may be no highly anticipated use for sorting checker pieces, one could utilize the same approach we did to sort different colored objects such as Legos, or as Online Solutions claims, used for food processing.




Bill of Materials:

If you are attempting this project by yourself, you may go ahead and order these same parts from your preferred vendor, but for the purposes of this project, these are the materials that we personally used.

Although this project can be done without the use of a 3D printer, we found that having 3D printer parts assisted with problems cardboard faces such as deforming under pressure.



3D Printed Parts Process and Explanation:

We began by designing 4 major parts: All can be found on my GitHub Page under "Fusion360 Files" (If you wish to redesign some of the files) or the "STL Files" (if you wish to 3D print it the exact same way). A special thanks to Gabriel Longoria who assisted along the design process.


Funnel - Serving as the entrance for the checkers.

For reference, according to the amazon listing and via our own measurements using calipers the width of the checker pieces we had is 2.75". In order to avoid a tight fit, and avoid that no more than 1 checker piece can flow through, we designed the entrance funnel at 3" width.



Color Sensor Holder - Where the Color sensor module will be held and "scan" the checkers.

Unlike many other Arduino modules I have worked with in the past, I was unable to find a datasheet that showed specified dimensions, therefore I had to measure my own to get the "ideal". In this iteration of the project, I only accounted for the pins themselves to fit precisely , but not the black plastic base of the pins. Therefore once printed, we had to sand the holes with a Needle File Set to be able to fit perfectly against the wall. I will update this page in the future once I update the fusion 360 file and STL file to account for this error.


Iteration 1 of Color Mount Sensor Dimensions:


Color Sensor Direction Guide:



Bottom Rail - Serves as both the piece that moves the checker to the desired position and acts as a buffer while the sensor identifies the color of the checker piece.

The original design called for two rail pieces as you can see in the Fusion File for the color sensor there's two slots, however, due to complications with getting the proper angle for the servo for just one rail to work and due to time constrains as mentioned before, we decided to just stick with the single bottom rail.

In a future scenario if this project were to be expanded on, I would like to revisit the idea of having a top rail acting as a buffer, possibly controlled with a 2nd servo to prevent checkers from flowing through freely while the bottom rail is open.


Directions Guide Bottom Rail:




Ramp - Guide for the checkers to flow

We also decided to add a sort of rail to the ramp to ensure that the checkers wouldn't simply fall out of the path.


For the purpose of "aesthetics", we kept the ramp as almost a whole triangle, however, in the future, I would rather save filament by only keeping the arc angle. Keep a lookout for a different version of the ramp that would save filament and space.


Important modification: We had to shave off from the peak (rail side) of the ramp about 1.5 cm in order to have a more defined fit. The current model does not reflect this change.


Ramp directions guide:




Construction: 3D Parts

Once all the pieces were finally printed, we sanded the 3D printer parts where they would be glued to the cardboard. We started with the ramp first as it was the biggest piece and we also needed to align the center the peak of the ramp with the center of the bottom of the color sensor holder. Once glued, we aligned the funnel with the top entrance of the color sensor module.


EDIT: I have marked a line on the 63.50mm mark on the left side of the rail that will serve as a guide for the ideal spot.




Here is a 3D model of all the pieces put together:


Without bottom rail:


With Bottom Rail:



Construction: Electronic Components

Adding the electrical components is pretty straight forward. However, due to the amount of wires that will be a part of the project, and not being able to access/view the pins of the color sensor once it is hot-glued to the inside of the color sorter, I decided to make a wiring diagram for the project in order to keep track of the wires.


As you can see in the picture below, the design originally called for using an Arduino Nano, however, we were unable to get access to one, so we ended up using a Arduino Uno. This change does not change the wiring diagram, although it is just important for me to note changes made to the project.


Wiring Diagram via Fritzing:


Once all the jumper wires were on it was just a matter of cable managing and placing the electrical components where I felt they were best fitted, with the exception of the color sensor module that had to be mounted inside the color sensor mount; The LCD display was mounted on the top right corner of the cardboard as shown here:


All cables were to be routed to the breadboard we installed in the back stand. The most difficult part for us ended up being the placement of the servo motor. To be truthful about what we did, it was mostly trial an error to see the best angle that the servo motor should be at. Because of this, I have included an additional file of the servo motor mounted to the overall 3D model to show more or less the angle, and position we placed the servo motor at. Although you should note that while this worked for us, if you decide to replicate this project, I would consider using our placement as the initial-reference position, and trying out very slightly different angles and placements to get the proper angle. Here is a picture of the rough angle we positioned the servo:


Servo Motor Placement:

Wiring Route Behind:

Wiring Route Front:






Arduino Code

Thankfully, the Arduino code was pretty straight forward thanks to some labs we have done in the past to setup the servo motors and the LCD display. An important thing I learned as an engineer is to consider different factors when writing out code, in this case we had a few hypothetical scenarios to consider:

  • Ambient Lighting

  • Multiple Checkers

  • A Non-Red and Non-Black Checker added

  • Multiple Checkers going through the same slot even if they are not the same color

Another thing I learned as an engineer is that it would nearly be impossible to account for consider each and every single factor that could happen in our project. For the sake of simplicity, we assumed that the project would not be fed multiple checkers, only Red and Black checkers will be fed, we purposefully placed the color sensor in an almost enclosed environment to avoid rerunning the calibration sketch with each new environment the sensor was in. In the future I would love to add more modules to this project in order to account for said possibilities such as an additional slot that non Red or Black objects could go through.


The .ino file can be found on my Github page with proper formatting, and up to date changes. As a quick reference here it is below where I have included comments for instructions on my part of the code from lines #115 - #279 :

/*
Color Sensor Calibration from DroneBotWorkshop (Lines #7 - #122)
To Calibrate the color sensor, comment out lines #115 - #279 ; Uncomment Lines #7 - #122
To Get Readings as outputs from the color sensor comment out lines #7 - #122 ; Uncomment Lines #115 - #279
*/

/*

  Color Sensor Calibration
  color-sensor-calib.ino
  Calibrate RGB Color Sensor output Pulse Widths
  Uses values obtained for RGB Sensor Demo sketch 

  DroneBot Workshop 2020
  https://dronebotworkshop.com


// Define color sensor pins

#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8

// Variables for Color Pulse Width Measurements

int redPW = 0;
int greenPW = 0;
int bluePW = 0;

void setup() {

  // Set S0 - S3 as outputs
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  
  // Set Sensor output as input
  pinMode(sensorOut, INPUT);
  
  // Set Pulse Width scaling to 20%
  digitalWrite(S0,HIGH);
  digitalWrite(S1,LOW);
  
  // Setup Serial Monitor
  Serial.begin(9600);
}

void loop() {
  
  // Read Red Pulse Width
  redPW = getRedPW();
  // Delay to stabilize sensor
  delay(200);
  
  // Read Green Pulse Width
  greenPW = getGreenPW();
  // Delay to stabilize sensor
  delay(200);
  
  // Read Blue Pulse Width
  bluePW = getBluePW();
  // Delay to stabilize sensor
  delay(200);
  
  // Print output to Serial Monitor
  Serial.print("Red PW = ");
  Serial.print(redPW);
  Serial.print(" - Green PW = ");
  Serial.print(greenPW);
  Serial.print(" - Blue PW = ");
  Serial.println(bluePW);
  
}


// Function to read Red Pulse Widths
int getRedPW() {

  // Set sensor to read Red only
  digitalWrite(S2,LOW);
  digitalWrite(S3,LOW);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;

}

// Function to read Green Pulse Widths
int getGreenPW() {

  // Set sensor to read Green only
  digitalWrite(S2,HIGH);
  digitalWrite(S3,HIGH);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;

}

// Function to read Blue Pulse Widths
int getBluePW() {

  // Set sensor to read Blue only
  digitalWrite(S2,LOW);
  digitalWrite(S3,HIGH);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;

}
 */

#include <Wire.h>
#include <LiquidCrystal_I2C.h> // Library from https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <Servo.h>
// Define color sensor pins
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo myservo; // Servo object

#define S0 4 //
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8

/* Calalibration Values
 *  Goto line # - # to see calibration sketch
 */
int redMin = 33; // Red minimum value
int redMax = 230; // Red maximum value
int greenMin = 28; // Green minimum value
int greenMax = 261; // Green maximum value
int blueMin = 24; // Blue minimum value
int blueMax = 181; // Blue maximum value
int pos = 130; // Variable to store the servo position, the "middle" point for us was an angle of 130, therefore it is set as default

// Color Pulse Width Measurements

int redPW = 0;
int greenPW = 0;
int bluePW = 0;

// Final Stored Values

int redValue;
int greenValue;
int blueValue;

void setup() {
  pinMode(S0, OUTPUT); // S pins as outputs
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);

  pinMode(sensorOut, INPUT); //sensorOut as input
  
  digitalWrite(S0,HIGH); // 20% Frequency)
  digitalWrite(S1,LOW);
  
  Serial.begin(9600);

  myservo.attach(9); // Servo is attached to digitalPin 9 on Arduino
}

void loop() {
  
  redPW = getRedPW(); // Read Red value
  redValue = map(redPW, redMin,redMax,255,0); // Map to value from 0-255
  delay(200);// Delay to stabilize sensor
  
  greenPW = getGreenPW();// Read Green value
  greenValue = map(greenPW, greenMin,greenMax,255,0);
  delay(200);
  
  bluePW = getBluePW();// Read Blue value
  blueValue = map(bluePW, blueMin,blueMax,255,0);
  delay(200);
  
  /*
   * Prints out RGB value, in my case, I used these values to debug when I would insert a red checker and it would not read as red, finding the threshhold for the red. 
   * Same process for a black checker
   */
  Serial.print("Red = ");
  Serial.print(redValue);
  Serial.print(" - Green = ");
  Serial.print(greenValue);
  Serial.print(" - Blue = ");
  Serial.print(blueValue);

 
   if ( (redValue > 200 && redValue < 300) && ( greenValue > 50&& greenValue < 150) && (blueValue > 50 && blueValue < 150) ){ // Values fathered from redValue,greenValue,blueValue
    lcd.begin();
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("RED!");
    myservo.write(60); //Ideal position in our case was to change the servo angle from 130 -> 60 to release the red checker
    delay(100);
    Serial.println(" - The Color is Red! "); 
   }

   else if ( redValue < 100 && greenValue < 100 && blueValue < 100){
     lcd.begin();
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("BLACK!");
    myservo.write(180); //Ideal position in our case was to change the servo angle from 130 -> 180 to release the black checker
    delay(100);
    Serial.println(" - The color is Black! "); 
   }

   else {
    lcd.begin();
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("None");
    myservo.write(pos); //Reset back to default, middle, position
    delay(100);
    Serial.println(" - No color was detected :( " );
   }
  
}


// Function to read Red Pulse Widths
int getRedPW() {

  // Set sensor to read Red only
  digitalWrite(S2,LOW);
  digitalWrite(S3,LOW);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;

}

// Function to read Green Pulse Widths
int getGreenPW() {

  // Set sensor to read Green only
  digitalWrite(S2,HIGH);
  digitalWrite(S3,HIGH);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;

}

// Function to read Blue Pulse Widths
int getBluePW() {

  // Set sensor to read Blue only
  digitalWrite(S2,LOW);
  digitalWrite(S3,HIGH);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;

}

Once all the code is uploaded to the Arduino, here is a quick video of how the project should function:


Video Demo:




Thank you for reading, If you have any questions, concerns or comments about any part, please feel free to comment below or feel free to contact me via any method listed in my contact page.




Sources & References:









Yorumlar


Post: Blog2 Post

©2022 by Issac Alvarez. Proudly created with Wix.com

bottom of page