Color sensors provide more reliable solutions to complex automation challenges. They are used in various industries including the food and beverage, automotive and manufacturing industries for purposes such as detecting material, detecting color marks on parts, verifying steps in the manufacturing process and so on.

While expensive color sensors are used in industrial applications, inexpensive sensors such as TCS230 color sensor can be used for less stringent applications.

The TCS230 color sensor (also branded as the TCS3200) is quite popular, inexpensive and easy to use. Before we use this color sensor in our Arduino project, it would be good to see how a color sensor actually works.

How Color Sensors Work

White light is made up of three primary colors (Red, green and blue), which have different wavelengths. These colors combine with each other to form different shades of colors.

When white light falls on any surface, some wavelengths of light are absorbed and some are reflected, depending on the properties of the surface material. The color we see is a result of which wavelengths are reflected back into our eyes.

how we see colors

Now coming back to the sensor, a typical color sensor includes a high-intensity white LED that projects a modulated light onto the object. To detect the color of reflected light, almost all the color sensors consists of a grid of color-sensitive filter, also known as ‘Bayer Filter‘ and an array of photodiodes underneath, as shown in the picture below.

color sensor bayer filter and photodiodes arrangement

A single pixel is made up of 4 filters, one red, one blue, one green and one clear filter (no filter). This pattern is also known as the ‘Bayer Pattern‘. Each filter passes light of just a single color to the photodiode beneath, while the clear filter passes light as it is, as shown below. This extra light passed through the clear filter is a major advantage in low light conditions.

color sensor bayer filter working light passing through filters

The processing chip then addresses each photodiode (one color at a time), and measures the intensity of the light. As there is an array of photodiodes, the results are first averaged and then sent out for processing. By measuring the relative level of red, green and blue light, the color of the object is determined.

TCS230 Color Sensor Module

At the heart of the module is an inexpensive RGB sensor chip from Texas Advanced Optoelectronic Solutions – TCS230. The TCS230 Color Sensor is a complete color detector that can detect and measure an almost infinite range of visible colors.

tcs230 tcs3200 module hardware overview

The sensor itself can be seen at the center of the module, surrounded by the four white LEDs. The LEDs light up when the module is powered up and are used to illuminate the object being sensed. Thanks to these LEDs, the sensor can also work in complete darkness to determine the color or brightness of the object.

The TCS230 operates on a supply voltage of 2.7 to 5.5 volts and provides TTL logic-level outputs.

TCS230 Operation

The TCS230 detects color with the help of an 8 x 8 array of photodiodes, of which sixteen photodiodes have red filters, 16 photodiodes have green filters, 16 photodiodes have blue filters, and remaining 16 photodiodes are clear with no filters.

If you look closely at the sensor, you can actually see these filters.

tcs230 tcs3200 color sensor close up

Each 16 photodiodes are connected in parallel, so using two control pins S2 and S3 you can choose which of them to read. So for example, if you want to detect only red color, you can select 16 red-filtered photodiodes by setting the two pins to LOW according to the table.

Similarly, you can choose different types of photodiodes by different combinations of S2 and S3.

S2S3Photodiode type
LOWLOWRed
LOWHIGHBlue
HIGHLOWClear (No filter)
HIGHHIGHGreen

An internal current-to-frequency converter converts readings from photodiodes into a square wave whose frequency is proportional to the intensity of the chosen color. The range of the typical output frequency is 2HZ~500KHZ.

The sensor has two more control pins, S0 and S1, which are used for scaling the output frequency. The frequency can be scaled to three different preset values of 2%, 20% or 100%. This frequency-scaling function allows the sensor to be used with a variety of microcontrollers and other devices.

S0S1Output frequency scaling
LOWLOWPower down
LOWHIGH2%
HIGHLOW20%
HIGHHIGH100%

You can get different scaling factor by different combinations of S0 and S1. For the Arduino most applications use the 20% scaling.

TCS230 Color Sensor Module Pinout

The following diagram shows the pinout of a common TCS230 module.

tcs230 tcs3200 color sensor module pinout

GND is a ground pin.

OE is the Output Enable pin. This pin is rarely used and on most modules is permanently enabled. If not already enabled then pull it LOW.

S0 & S1 pins are used to select the frequency scaling.

S2 & S3 pins are used to select the color array.

OUT pin is a TTL level square wave.

VCC pin supplies power to the module. Connect it to the 2.7V to 5.5V power supply.

Wiring TCS230 Color Sensor to Arduino UNO

Hooking up the TCS 230 to an Arduino is very simple. Every pin is used except the Output Enable pin, and the module is powered safely from the 5-volt output of the Arduino.

Below is the hookup for the experiments with the TCS230:

wiring tcs230 tcs3200 color sensor module with arduino

None of the pins used on the Arduino are critical because the module does not require any pin-specific features, so if you want to use different pins you can do so safely. Just be sure to change the pin numbers in the code to reflect any changes to the wiring.

Once your sensor is connected to the Arduino it’s time to write some code!

Calibrating the Sensor

We will actually use two sketches to work with the TCS230 color sensor.

  1. The first sketch (calibration sketch) will help us to obtain the raw data from the sensor.
  2. The second sketch (main Arduino sketch) will use the raw data previously received to display RGB values for the color being sensed.

Note that both sketches will use the same hardware hookup.

Following is the calibration sketch. This sketch addresses the TCS230 sensor color-by-color and reads the pulse width of the output pin. The output is then displayed on the serial monitor.

Load the sketch to your Arduino and mount the sensor so that it is facing the objects. Start by finding a reference object for white and black color. These reference objects will produce readings at both maximum and minimum values for all three colors.

// 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 Pulse Width scaling to 20%
	digitalWrite(S0,HIGH);
	digitalWrite(S1,LOW);

	// Set Sensor output as input
	pinMode(sensorOut, INPUT);

	// 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;
}

Once you upload the sketch you will get such readings. Record the readings you get at both extremes.

tcs230 color sensor calibration output

Code Explanation:

The sketch begins with defining the pins used to connect the TCS230. Some variables are also defined to represent the pulse widths of the red, green and blue color array.

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

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

In the setup, we define the S0-S3 pins as outputs. These pins will be used to select the frequency scaling and the color we wish to address. The S0 and S1 pins are used to set the frequency scaling to 20%, which is a common value when using this color sensor with an Arduino. Next, The sensors Output pin is defined as an input to the Arduino, this is where we will receive the square wave. Finally, we set up the serial monitor.

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

	// Set Pulse Width scaling to 20%
	digitalWrite(S0,HIGH);
	digitalWrite(S1,LOW);

	// Set Sensor output as input
	pinMode(sensorOut, INPUT);

	// Setup Serial Monitor
	Serial.begin(9600);
}

In the loop section, we call three functions getRedPW(), getGreenPW() and getBluePW() to obtain the pulse width. Let’s examine getRedPW() as an example.

The getRedPW() function gets the red pulse width. It starts by setting the S2 and S3 pins to select the red filter. This is the only step where this function differs from its green and blue counterparts.

Next, an integer is defined to store the pulse width. The pulse width is then determined using the Arduino pulseIn() function. This function measures the pulse width, note that we have configured it to measure the width of the LOW part of the pulse. The result is time in milliseconds. This value is then returned and the function terminates.

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;
}

Back in the loop, we call three functions to read the color pulse widths, adding a delay of 200ms between them to allow the sensor to stabilize. We then print the values on the serial monitor and repeat the loop.

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);
}

Arduino Code – Reading RGB Values from the TCS230

Once you have taken your readings you can upload the next sketch where we will read RGB values from the TCS230 color sensor.

Before uploading the sketch, enter the six calibration values you obtained from the calibration sketch in the top of the sketch. replace the “0” with your actual values.

// Define color sensor pins
#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8

// Calibration Values
// *Get these from Calibration Sketch
int redMin = 0; // Red minimum value
int redMax = 0; // Red maximum value
int greenMin = 0; // Green minimum value
int greenMax = 0; // Green maximum value
int blueMin = 0; // Blue minimum value
int blueMax = 0; // Blue maximum value

// Variables for Color Pulse Width Measurements
int redPW = 0;
int greenPW = 0;
int bluePW = 0;

// Variables for final Color values
int redValue;
int greenValue;
int blueValue;

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 Frequency scaling to 20%
	digitalWrite(S0,HIGH);
	digitalWrite(S1,LOW);

	// Setup Serial Monitor
	Serial.begin(9600);
}

void loop() {
	// Read Red value
	redPW = getRedPW();
	// Map to value from 0-255
	redValue = map(redPW, redMin,redMax,255,0);
	// Delay to stabilize sensor
	delay(200);

	// Read Green value
	greenPW = getGreenPW();
	// Map to value from 0-255
	greenValue = map(greenPW, greenMin,greenMax,255,0);
	// Delay to stabilize sensor
	delay(200);

	// Read Blue value
	bluePW = getBluePW();
	// Map to value from 0-255
	blueValue = map(bluePW, blueMin,blueMax,255,0);
	// Delay to stabilize sensor
	delay(200);

	// Print output to Serial Monitor
	Serial.print("Red = ");
	Serial.print(redValue);
	Serial.print(" - Green = ");
	Serial.print(greenValue);
	Serial.print(" - Blue = ");
	Serial.println(blueValue);
}


// 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;
}

Load the sketch and observe the results with samples of different colors. You can make minor adjustments to calibration values if necessary.

Code Explanation

You will notice that the majority of this sketch is exactly the same as the previous sketch, except:

The six calibration values you obtained from the calibration sketch are entered in the top of the sketch.

// Calibration Values
int redMin = 0; // Red minimum value
int redMax = 0; // Red maximum value
int greenMin = 0; // Green minimum value
int greenMax = 0; // Green maximum value
int blueMin = 0; // Blue minimum value
int blueMax = 0; // Blue maximum value

Three new variables are defined for the RGB values we want to output.

int redValue;
int greenValue;
int blueValue;

In the loop section, we read each of the values ​​using the same function used in the previous sketch. Then we use the Arduino map() function to convert these values ​​into RGB values, ​​using our calibration values ​​as a reference.

Note that we have reversed the range (Min value is mapped to 255 amd Max value is mapped to 0) because our functions return pulse width, not frequency.

// Read Red value
redPW = getRedPW();
// Map to value from 0-255
redValue = map(redPW, redMin,redMax,255,0);
// Delay to stabilize sensor
delay(200);

Finally, we output the values on the serial monitor. These final readings will correspond to the RGB values of the item being scanned.


Login
ADS CODE