In today's tech-driven world, the Arduino platform continues to empower enthusiasts and professionals alike to explore the realms of electronics and programming. One fascinating avenue within this domain is color sensing using Arduino boards. With the integration of RGB sensors, Arduino opens up a world of possibilities for projects ranging from color sorting machines to ambient light displays. Let's delve into the exciting world of color sensing with Arduino and discover its applications, principles, and how you can embark on your own creative endeavors.
Understanding Color Sensing
Principles of Color Sensing with Arduino
Implementing color sensing with Arduino involves several key principles:
RGB Sensor Integration: Choose an RGB sensor compatible with Arduino, such as the TCS3200 or TCS34725. These sensors typically communicate with Arduino via protocols like I2C or SPI.
Calibration: Calibrating the RGB sensor ensures accurate color detection. This involves adjusting sensor parameters to account for ambient light conditions and optimize color accuracy.
Data Processing: Arduino collects data from the RGB sensor and processes it to determine the color of the detected object. Algorithms for color recognition can range from simple thresholding to more advanced techniques like machine learning.
Feedback or Output: Depending on the application, Arduino provides feedback or output based on the detected color. This could involve activating actuators, displaying information on an LCD screen, or transmitting data to a connected device.
Getting Started with Color Sensing Projects
Embarking on a color sensing project with Arduino is an exciting journey accessible to beginners and experienced makers alike. Here's a basic roadmap to get started:
Components Requirement :
- Arduino UNO
- RGB Sensor (TSC230 chip)
- Jumper Wire
Basic logic of RBG Sensor works on :
The TCS230 color detector measures
three primary colors Red, Green and Blue and also has a separate white
light detector. Since any color can be created from different levels of
these primary colors, you can find out the color composition of a light
source.
TCS230 Specification
Parameter |
Value |
Voltage Supply (VDD) |
2V7 ~ 5V5 |
Abs.Max VDD |
-0.3V ~ 6V3 |
Measurement range |
Approx. 300nm to 980nm [3] |
Output interface type |
Frequency pin o/p single pin [2] |
Logic Levels |
CMOS or TTL |
Logic input voltage (L,H) |
0V0 ~ 0V8, 2V0 ~ VDD |
Logic output voltage (L,H) |
0V4, 4.5 (for VDD=5V) |
Output frequency Scale 100% |
600kHz (typ) [1][2] |
Output frequency Scale 20% |
120kHz (typ) [1][2] |
Output frequency Scale 2% |
12kHz (typ) [1][2] |
Active current |
2mA (typ), 3mA (max) |
Power down current |
7uA (typ), 15uA (max) |
Operating temperature |
-40°C ~ 70°C |
The output from TC230 is from a single square wave output that changes
frequency with the amount of light sensed. The specific sensor R,G,B or
W is selected using two digital control inputs (S0 and S1).
The frequency of the square wave is proportional to the amount of light
falling on a set of light detecting diodes. Since there are four
different sources of information red, green, blue and clear photodiodes
- each of these is selected in-turn using (S0 and S1). So only one set
of photodiodes is connected at a time to generate the output.
The chip inputs, S2 and S3, control the output frequency divider logic
which you an use to get a different output frequency proportional to the
colour level. You can select a longer output pulse to accommodate slow
processor measurement capability - but the reading averages to the same
output value regardless of frequency output.
In fact several photodiodes for each color are connected in parallel
and these are spread evenly over the sensor surface - you can see this
in the photo above. This layout obtains an overall reading for each
color not just from an individual photodiode. For the TCS230 there are
a total of 64 photodiodes. 16 have a red filter above them, 16 have a
green filter, 16 have a blue filter and 16 have a clear filter.
Block Diagram showing how the Chip works
Note: There is also an output enable that tristates the output
when high (OEn). This would allow you to attach several different
TCS230 chips to detect colors from different parts of a machine
using only one input. When using only one device set it low
permanently.
Signal output
The signal output by the TCS230 is obtained by a current to
frequency converter that takes as its input the average current from
the selected set of photodiodes. The idea is that you switch one set
on, take a reading and then switch to the next set until all four
measurements are done. The output signal is a square wave with even
mark to space ratio: 50% high, 50% low.
Frequency Dividers
The square wave output by the device can also be divided down
(internally in the TCS230) and this allows slower processors to to
make measurements more easily. There is no measurement penalty as
the divided down output is simply an average of the original. The
only disadvantage is that because the signal is of a lower frequency
you can not make measurements as quickly.
If it was important to make a light reading very fast then you would
want to use a high speed processor and not divide down the output
signal. You can imagine that this might become important in an
industrial process measurement e.g. for measuring the state of a
product e.g. you would want to quickly measure the color of an item
on a conveyor belt, and reject it if it as the wrong color.
Frequency outputs
The maximum full scale frequency output from the TCS230 are shown
below for the scaling factors controlled by S0 and S1. Scaling is
really just using an internal clock chip that counts the input
signal (the primary clock output from the photodiode current to
frequency converter) and generates divided down clocks.
Control Scaling |
|||
S0 |
S1 |
Max output frequency kHz |
%scale |
H |
H |
600kHz |
100% |
H |
L |
120kHz |
20% |
L |
H |
12kHz |
2% |
L |
S1 = L |
Power down |
Power down |
Control Photodiodes |
||
S2 |
S3 |
Selected Photodiodes |
L |
L |
Red |
L |
H |
Blue |
H |
L |
Clear |
H |
H |
Green |
Circuit and schematic :
Schematic
The following schematic shows connections from a TCS230 breakout
board to an Arduino Uno, with output on pin 4 and the two photodiode
selector muxes on S0 and S1 (attached to pins 10 & 11).
The output frequency divider controls are on S2 and S3 (
attached to pins 1 & 2). The output enable is on pin 7, and the
digital output from the TCS230 is connected to the Uno as an input on
pin 4.
Example Sketch for Arduino UNO
The sensor is very sensitive to any changes in light and in
practice that means any slight distance changes from the sensor to
the object will cause a different reading. Additionally any ambient
light changes will also cause a different reading.
So to make accurate (repeatable) readings you need to control two elements:
-
Distance to object.
-
Ambient light.
To calibrate the sensor, push the sensor down onto colored paper
as even a small adjustment fails since the sensor is extremely
sensitive.
Set the serial monitor to 115200 Baud and push the sensor down
and hit the 'Enter' key in the serial monitor input field. This
will then show you the current RGB values. Copy these values into
the RBG array and set the equivalent colname text. Recompile (or
add some different colored objects). Recompile and check that the
'color' is found.
Now you can test the 'objects' with the code now reporting the
color of the object.
As for "real" calibration- Its difficult and the only way you
will achieve it is to place the sensor in a closed environment
where you can control the lighting levels - this will give
repeatable reliable measurements.
//
// Detect colors using TCS230.
//
// Arduino uno pins for control of TCS230
#define TCS320_OE 7
#define TCS320_S0 10
#define TCS320_S1 11
#define TCS320_S2 2
#define TCS320_S3 3
#define TCS320_OUT 4
#define variance 50 // Acceptable detection error 2%.
#define SEL_RED \
digitalWrite(TCS320_S2,LOW);digitalWrite(TCS320_S3,LOW)
#define SEL_GREEN \
digitalWrite(TCS320_S2,HIGH);digitalWrite(TCS320_S3,HIGH)
#define SEL_BLUE \
digitalWrite(TCS320_S2,LOW);digitalWrite(TCS320_S3,HIGH)
#define SEL_CLEAR \
digitalWrite(TCS320_S2,HIGH);digitalWrite(TCS320_S3,LOW)
#define TWO_PER \
digitalWrite(TCS320_S0,LOW);digitalWrite(TCS320_S1,HIGH);
#define debug(a) Serial.println((a));
#define NUMCOL 5
// int RGB[NUMCOL][3]; // Five colors with 3 elements.
// Array of NUMCOL strings len 10. 11 for null.
// char colname[NUMCOL][11];
// Typical values for 2% dividers (set variance to 50).
int RGB[NUMCOL][3]={
{248,647,393},
{188,261,265},
{404,710,546},
{506,493,304},
{930,1199,837},
};
char colname[NUMCOL][11]={
"red",
"yellow",
"brown",
"blue",
"black",
};
////////////////////////////////////////////////////////////////
void setup() {
pinMode(TCS320_OE,OUTPUT);
pinMode(TCS320_S0,OUTPUT);
pinMode(TCS320_S1,OUTPUT);
pinMode(TCS320_S2,OUTPUT);
pinMode(TCS320_S3,OUTPUT);
pinMode(TCS320_OUT,INPUT);
TWO_PER;
digitalWrite(TCS320_OE,LOW); // On always.
Serial.begin(115200);
Serial.println("TCS230 color detector");
}
////////////////////////////////////////////////////////////////
unsigned long get_TCS230_reading(void) {
unsigned long val;
noInterrupts();
val = pulseIn(TCS320_OUT,HIGH,20000); // 2000us=2ms 2Hz min.
interrupts();
return val;
}
static int clr,red,green,blue;
////////////////////////////////////////////////////////////////
uint16_t detect(void) {
unsigned long val;
SEL_RED;
red = val = get_TCS230_reading();
Serial.print("RED: "); Serial.print(val);
SEL_GREEN;
green = val = get_TCS230_reading();
Serial.print(" GREEN: "); Serial.print(val);
SEL_BLUE;
blue = val = get_TCS230_reading();
Serial.print(" BLUE: "); Serial.print(val);
Serial.print(" \n");
}
////////////////////////////////////////////////////////////////
int withinEQ(int c, int xl, int xh) {
if (c>=xl && c<=xh) return 1;
return 0;
}
////////////////////////////////////////////////////////////////
// Compare a value to a value and variance.
int compare(int c, int v, int err) {
int xh=v+err, xl=v-err;
if (withinEQ(c,xl,xh)) return 1;
return 0;
}
////////////////////////////////////////////////////////////////
void loop() {
uint8_t chr,i,fnd;
if (Serial.available()>0) {
chr = Serial.read(); // Consume.
// Find color match.
detect();
fnd=0;
for (i=0;i
Conclusion :
For the 20% dividers you are getting close to the measurement capability
of pulseIn which is 4us i.e the minimum period measured was 18us and that is
only -5 counts of pulseIn data. So that measurement is getting close to being
too small and therefore less accurate i.e. the difference between colors will
need to be larger to register a difference in the chip output = less sensitive.
The resolution here is 22% of the minimum period which is fairly bad.
The periods for 100% output will be even smaller (1.0/600e3 = 1.6us) and
that would not be measurable using pulseIn - you may be able to do it using the
asynchronous input in Timer 2.
When the 2% dividers are used the program can make the most accurate
period measurement since the periods output by the chip are long compared to
the pulseIn accuracy of 4us. i.e the lowest period measured was 188us for these
dividers ( ~48 periods of 4us ) compared to 18us ( ~5 periods of 4us ) for the
20% dividers.
The resolution here is 2.13% of the minimum period which is quite good.
Therefore the 2% divider output is the better option for measurement
accuracy.
Warning: The
light detector is extremely sensitive so although you can get maximum accuracy
the periods measured will change a lot depending on the lighting conditions and
object distance. That is why the variable 'variance' allows you to specify an
error value around each RBG center point for reliable color detection.