arduino-clasificador-colores-tcs3200

How to Build a Color Sorter with Arduino

  • 7 min

If you’ve ever seen those mesmerizing factory videos where thousands of tomatoes or plastic parts are sorted at high speed by quality or color, you’ve seen machine vision in action.

Today we’re bringing that technology to our desktop. We’re going to build a color sorting machine.

The goal is simple: we pour a handful of mixed colored candies (like M&Ms, Skittles, or Smarties) into a funnel, and the machine must dispense them one by one, analyze their color, and move a ramp to deposit them into their corresponding cup.

This project is the “Hello World” of Mechatronics, as it requires perfectly synchronizing physical movement (servos) with data acquisition (sensor).

How the TCS3200 Measures Color

For this project we will use the TCS3200 sensor. Unlike a camera that processes pixels, this sensor is much more primitive (and faster).

The TCS3200 is a Light-to-Frequency converter. It has an array of filtered photodiodes:

  • Some have a Red filter.
  • Others have a Green filter.
  • Others have a Blue filter.
  • Others have no filter (Clear).

The operation is sequential:

We tell the sensor: “Read only the Red photodiodes.”

The sensor emits pulses (square wave). The more red intensity it detects, the higher the frequency of those pulses.

We repeat for Green and Blue.

In the end, we get three frequency values. If the red frequency is very high compared to the other two, the object is red. Simple, right?

Mechanical Design

Before programming, we need “hardware”. The biggest challenge of this project is not the code, it’s preventing the candies from jamming.

We need two mechanisms:

  1. The Feeder: A disk with a hole connected to a servo (Top Servo). It takes a candy from the funnel and drags it to place it under the sensor.
  2. The Sorter: A tube or channel connected to another servo (Bottom Servo) that points to the correct cup.

It is very important to cover the sensor and the candy with an opaque housing while reading. Sunlight or room lamps will drastically change the read values and confuse the robot.

Components

  • [1x|blue] Arduino Uno | The project’s brain
  • [1x|orange] TCS3200 Color Sensor | Module with 4 built-in white LEDs
  • [1x|green] Top Servo (SG90) | Feeder (disk with hole)
  • [1x|green] Bottom Servo (SG90) | Sorting ramp
  • [1x|red] External power supply (5V 2A) | For servos
  • [Various|gray] Structure | Cardboard, wood, or 3D print

Connection Diagram

The TCS3200 has quite a few pins, so pay attention to the wiring!

TCS3200 Sensor

The sensor needs pins to select the filter, configure the frequency scaling, and read the output.

[ { “from”: “TCS3200 VCC”, “to”: “Arduino 5V”, “color”: “red” }, { “from”: “TCS3200 GND”, “to”: “Arduino GND”, “color”: “black” }, { “from”: “TCS3200 S0”, “to”: “Pin 2”, “color”: “yellow”, “note”: “Frequency scaling” }, { “from”: “TCS3200 S1”, “to”: “Pin 3”, “color”: “yellow”, “note”: “Frequency scaling” }, { “from”: “TCS3200 S2”, “to”: “Pin 4”, “color”: “orange”, “note”: “Filter selection” }, { “from”: “TCS3200 S3”, “to”: “Pin 5”, “color”: “orange”, “note”: “Filter selection” }, { “from”: “TCS3200 OUT”, “to”: “Pin 6”, “color”: “green”, “note”: “Frequency output” } ]

Mechanism Servos

One servo doses the candies and the other orients the output ramp.

[ { “from”: “Feeder Servo signal”, “to”: “Pin 9”, “color”: “purple” }, { “from”: “Ramp Servo signal”, “to”: “Pin 10”, “color”: “purple” }, { “from”: “Servos VCC”, “to”: “External regulated 5V supply”, “color”: “red” }, { “from”: “Servos GND”, “to”: “Power GND + Arduino GND”, “color”: “black” } ]

The Code

We will divide the code into logical blocks. We need to calibrate first, because “Red” doesn’t mean the same thing in your house as in mine (it depends on the light).

Definitions and setup

#include <Servo.h>

// TCS3200 Pins
#define S0 2
#define S1 3
#define S2 4
#define S3 5
#define sensorOut 6

// Servo Objects
Servo feederServo;
Servo rampServo;

// Variables to store read frequencies
unsigned long redFreq = 0;
unsigned long greenFreq = 0;
unsigned long blueFreq = 0;

void setup() {
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(sensorOut, INPUT);
  
  // Configure frequency scaling to 20%
  // (Datasheet truth table: S0=High, S1=Low)
  digitalWrite(S0, HIGH);
  digitalWrite(S1, LOW);
  
  feederServo.attach(9);
  rampServo.attach(10);
  
  Serial.begin(9600);
  
  // Initial position
  moveRamp(90); // Center
}
Copied!

Color Reading Function

This function interrogates the sensor sequentially. We use pulseIn(pin, LOW) to measure the pulse duration. Note: On the TCS3200, higher light intensity means shorter pulse duration (higher frequency).

void readSensor() {
  // 1. RED Filter (S2=LOW, S3=LOW)
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);
  delay(10); // Allow output to stabilize
  redFreq = pulseIn(sensorOut, LOW, 100000UL);
  
  // 2. GREEN Filter (S2=HIGH, S3=HIGH)
  digitalWrite(S2, HIGH);
  digitalWrite(S3, HIGH);
  delay(10);
  greenFreq = pulseIn(sensorOut, LOW, 100000UL);
  
  // 3. BLUE Filter (S2=LOW, S3=HIGH)
  digitalWrite(S2, LOW);
  digitalWrite(S3, HIGH);
  delay(10);
  blueFreq = pulseIn(sensorOut, LOW, 100000UL);

  // Debug: Print values for calibration
  Serial.print("R="); Serial.print(redFreq);
  Serial.print(" G="); Serial.print(greenFreq);
  Serial.print(" B="); Serial.println(blueFreq);
}
Copied!

Classification

Now it’s time to calibrate. Place a red sample and note the values from the serial monitor. Repeat several times with each color and also without an object; a single reading is not enough.

With that data, we write the conditionals.

void loop() {
  // 1. Load candy (Move top servo)
  loadCandy();
  delay(500); 
  
  // 2. Read
  readSensor();
  
  // 3. Decide (These values ARE AN EXAMPLE, use yours)
  // pulseIn returns duration. LOWER value usually indicates HIGHER intensity.
  
  if (redFreq == 0 || greenFreq == 0 || blueFreq == 0) {
    Serial.println("-> Invalid reading / no signal");
  }
  else if (redFreq < greenFreq && redFreq < blueFreq && redFreq < 80) {
    Serial.println("-> Detected RED");
    moveRamp(45); // Left Cup
  }
  else if (blueFreq < redFreq && blueFreq < greenFreq && blueFreq < 80) {
    Serial.println("-> Detected BLUE");
    moveRamp(135); // Right Cup
  }
  else if (greenFreq < redFreq && greenFreq < blueFreq) {
    Serial.println("-> Detected GREEN");
    moveRamp(90); // Center Cup
  }
  else {
    Serial.println("-> Unknown color / Empty");
    // Don't move the ramp, or send it to "rejects"
  }
  
  delay(500);
  
  // 4. Release candy
  unloadCandy();
}

// Auxiliary movement functions
void moveRamp(int angle) {
  rampServo.write(angle);
  delay(300); // Allow time to reach
}

void loadCandy() {
  feederServo.write(0); // Pickup position
  delay(500);
  feederServo.write(90); // Position under sensor
}

void unloadCandy() {
  feederServo.write(180); // Drop position
  delay(500);
  feederServo.write(90); // Return to rest
}
Copied!

Distinguishing Similar Colors

The great enemy of this project is distinguishing similar colors, like Brown M&Ms from Red or Orange ones. The TCS3200 sensor is RGB. Brown, technically, is a “dark orange”.

  • Red: High R, low G, low B.
  • Brown: Medium R, medium-low G, low B.

To distinguish them, simply looking at which value is the lowest is not enough. It is advisable to use ratios between channels, normalize with reference samples, and consider total intensity. If the sum of the three is very high (high pulseIn values), it means the object is dark -> Brown.

Shiny objects reflect the white LEDs and can create specular highlights that falsify the reading. Do not sand the sensor. Use diffuse lighting, an opaque chamber, and a fixed geometry between sample, LED, and photodiodes.

Next Steps

Did it work for you? Now make it industrial:

  1. Counter: Add an LCD screen that counts how many candies of each color you’ve processed (“Reds: 15, Blues: 12”).
  2. Speed: Optimize the code to make it faster. Can you process 1 candy per second?
  3. Machine Learning: If you use a more powerful Arduino (like the Nano 33 BLE Sense) or connect this to a PC, you could train a small neural network to learn to distinguish complex colors without you having to write a thousand if/else statements.

Let’s get sorting!