Color sorter on an Arduino Uno
A TCS34725 color sensor looks at each candy and a servo swings the chute to its bin: six colors, and an empty chute it waits on. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
IntermediateRuns in your browser. Free, and no account needed.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Color sorter: a TCS34725 looks at the candy in front of it and a servo
// swings the chute to that color's bin, as in the candy and bead sorters
// people build.
//
// TCS34725 SDA -> A4 SCL -> A5 VIN -> 5 V GND -> GND (LED left high: lit)
// servo signal -> 9 red -> 5 V brown -> GND
//
// The sensor gives four counts: red, green, blue and clear. Their shares of
// the total say what color it is whatever the brightness, so the sketch
// compares them with a table of the six colors it knows, measured once with
// the LED on, and picks the nearest. A low clear count is an empty chute.
//
// Click a card on the sensor to put a candy in front of it, and watch the
// chute move.
#include <Wire.h>
#include <Servo.h>
#include "Adafruit_TCS34725.h"
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
Servo chute;
const int SERVO_PIN = 9;
const uint16_t EMPTY_BELOW = 1500; // clear count of the empty chute
struct Reference {
const char *name;
uint16_t red, green, blue; // shares of the total, in thousandths
uint8_t angle; // where the chute points for this bin
};
const Reference COLORS[] = {
{"red", 647, 203, 148, 15},
{"orange", 566, 342, 90, 45},
{"yellow", 475, 431, 92, 75},
{"green", 192, 524, 283, 105},
{"blue", 137, 313, 549, 135},
{"purple", 324, 243, 431, 165},
};
const uint8_t COUNT = sizeof(COLORS) / sizeof(COLORS[0]);
int8_t last = -2;
void setup() {
Serial.begin(9600);
chute.attach(SERVO_PIN);
chute.write(90);
if (!tcs.begin()) {
Serial.println("No TCS34725 found ... check your connections");
while (1) delay(10);
}
Serial.println("Color sorter ready");
}
// The nearest color in the table, or -1 for an empty chute.
int8_t classify(uint16_t r, uint16_t g, uint16_t b, uint16_t c) {
if (c < EMPTY_BELOW) return -1;
uint32_t total = (uint32_t)r + g + b;
int32_t rs = (uint32_t)r * 1000 / total;
int32_t gs = (uint32_t)g * 1000 / total;
int32_t bs = (uint32_t)b * 1000 / total;
int8_t best = 0;
int32_t bestDistance = 0x7fffffff;
for (uint8_t i = 0; i < COUNT; i++) {
int32_t dr = rs - COLORS[i].red;
int32_t dg = gs - COLORS[i].green;
int32_t db = bs - COLORS[i].blue;
int32_t d = dr * dr + dg * dg + db * db;
if (d < bestDistance) {
bestDistance = d;
best = i;
}
}
return best;
}
void loop() {
uint16_t r, g, b, c;
tcs.getRawData(&r, &g, &b, &c);
int8_t color = classify(r, g, b, c);
if (color == last) return;
last = color;
if (color < 0) {
Serial.println("chute empty");
return;
}
Serial.print(COLORS[color].name);
Serial.print(" -> bin ");
Serial.print(color + 1);
Serial.print(" (R ");
Serial.print(r);
Serial.print(" G ");
Serial.print(g);
Serial.print(" B ");
Serial.print(b);
Serial.print(" C ");
Serial.print(c);
Serial.println(")");
chute.write(COLORS[color].angle);
delay(300);
}
Parts list
4 parts, plus the jumper wires. Every one is in the editor's parts bin.
- 1 × Arduino Uno R3
- 1 × Half breadboard
- 1 × Color sensor, TCS34725
- 1 × Hobby servo
How it is wired
5 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- Arduino Uno R3 pin 9; Hobby servo pin PWM
- Arduino Uno R3 pin 5V; Color sensor, TCS34725 pin VIN; Hobby servo pin VCC
- Ground: Arduino Uno R3 pin GND; Color sensor, TCS34725 pin GND; Hobby servo pin GND
- Arduino Uno R3 pin A4; Color sensor, TCS34725 pin SDA
- Arduino Uno R3 pin A5; Color sensor, TCS34725 pin SCL
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.