Trying to understand how a color sensor works (TCS 3200)

specifically this one;

i was somewhat confused that the sensor is connected to Arduino pins designated as OUTPUT.

my understanding of a color sensor is that you shine white light towards the object, and then the sensor(s?) reads the reflected light and gives the value in each of the component/amount(?) of R,G and B light.

i read the datasheet and it's quite technical but i can't understand how the sensor works, all talk of frequency & photodiode & square-wave output. :cold_sweat:

from what i can gather, how it actually works is, we set the lights to shine the color we're looking for, and then the sensor says "yes, that is the color" or "no, it is not".

but if we don't know the color before hand, eg. we want the sensor to tell us what color it's looking at, then we have to loop (the outputs) through the spectrum until the sensor says, "yes, that's the one".

have i understood that correctly ?

i think i can also get what the "Photodiode type selection inputs" does, in the table below;

in this case, we read the Arduino pins connected to 's2' & 's3' and their state will tell us that the color being read is (predominantly) red, blue or green ?

i'd like to check if i've got anything fundamentally wrong with the above, before attempting to connect the sensor and then "try" this code;

const int s2=5; // Arduino pin 5
const int s3=6; // Arduino pin 6

void setup()
 {
 Serial.begin(9600);
 pinMode(s2,INPUT);
 pinMode(s3,INPUT);
}

void loop()
{
if ( (digitalRead(s2) == HIGH) && (digitalRead(s3) == HIGH)
{
  Serial.println("Green");
}

if ( (digitalRead(s2) == LOW) && (digitalRead(s3) == HIGH)
{
  Serial.println("Blue");
}

// etc...

}

The chip has one output and four inputs. The inputs select which of the four color sensors is connected to the output. The output is a pulse frequency proportional to the light intensity. The sample code uses a timer and an interrupt input to measure pulses per time interval (frequency).

Test program

/*

Eecher's TCS3200 program
adapted from code found at reibot.org

*/

int S0 = 8;//pinB
int S1 = 9;//pinA
int S2 = 12;//pinE
int S3 = 11;//pinF
int taosOutPin = 10;//pinC
int LED = 13;//pinD 

void setup()
{
  TCS3200setup(); 
  Serial.begin(115200);  
  Serial.print("\n\n\nready\n\n\n");
  delay(100);
}

// primary loop takes color readings from all four channels and displays the raw values once per second.  What you might wish to do with those values is up to you...
void loop() 
{
  detectColor(taosOutPin);
  Serial.print("\n\n\n");
  delay(1000);
}

int detectColor(int taosOutPin)
{
  float white = colorRead(taosOutPin,0,1);
  float red = colorRead(taosOutPin,1,1);
  float blue = colorRead(taosOutPin,2,1);
  float green = colorRead(taosOutPin,3,1);

  Serial.print("white ");
  Serial.println(white);
  
  Serial.print("red ");
  Serial.println(red);
  
  Serial.print("blue ");
  Serial.println(blue);
  
  Serial.print("green ");
  Serial.println(green);
}

/*
This section will return the pulseIn reading of the selected color.  
It will turn on the sensor at the start taosMode(1), and it will power off the sensor at the end taosMode(0)
color codes: 0=white, 1=red, 2=blue, 3=green
if LEDstate is 0, LED will be off. 1 and the LED will be on.
taosOutPin is the ouput pin of the TCS3200.
*/

float colorRead(int taosOutPin, int color, boolean LEDstate)
{ 
//turn on sensor and use highest frequency/sensitivity setting
taosMode(1);

//setting for a delay to let the sensor sit for a moment before taking a reading.
int sensorDelay = 100;

//set the S2 and S3 pins to select the color to be sensed 
if(color == 0)  //white
{
  digitalWrite(S3, LOW); //S3
  digitalWrite(S2, HIGH); //S2
  // Serial.print(" w");
}
else if(color == 1) //rød
{
  digitalWrite(S3, LOW); //S3
  digitalWrite(S2, LOW); //S2
  // Serial.print(" r");
}
else if(color == 2) //blå
{
  digitalWrite(S3, HIGH); //S3
  digitalWrite(S2, LOW); //S2 
  // Serial.print(" b");
}
else if(color == 3) //grønn
{
digitalWrite(S3, HIGH); //S3
digitalWrite(S2, HIGH); //S2 
// Serial.print(" g");
}

// create a var where the pulse reading from sensor will go
float readPulse;

//  turn LEDs on or off, as directed by the LEDstate var (IKKE Frydenlund)
if(LEDstate == 0){
    digitalWrite(LED, LOW);
}
if(LEDstate == 1){
    digitalWrite(LED, HIGH);
}

// wait a bit for LEDs to actually turn on, as directed by sensorDelay var
delay(sensorDelay);

// now take a measurement from the sensor, timing a low pulse on the sensor's "out" pin
readPulse = pulseIn(taosOutPin, LOW, 80000);

//if the pulseIn times out, it returns 0 and that throws off numbers. just cap it at 80k if it happens
if(readPulse < .1){
readPulse = 80000;
}

//turn off color sensor and LEDs to save power 
taosMode(0);

// return the pulse value back to whatever called for it... 
return readPulse;

}

// Operation modes area, controlled by hi/lo settings on S0 and S1 pins.
//setting mode to zero will put taos into low power mode. taosMode(0);

void taosMode(int mode){
    
    if(mode == 0){
    //power OFF mode-  LED off and both channels "low"
    digitalWrite(LED, LOW);
    digitalWrite(S0, LOW); //S0
    digitalWrite(S1, LOW); //S1
    //  Serial.println("mOFFm");
    
    }else if(mode == 1){
    //this will put in 1:1, highest sensitivity
    digitalWrite(S0, HIGH); //S0
    digitalWrite(S1, HIGH); //S1
    // Serial.println("m1:1m");
    
    }else if(mode == 2){
    //this will put in 1:5
    digitalWrite(S0, HIGH); //S0
    digitalWrite(S1, LOW); //S1
    //Serial.println("m1:5m");
    
    }else if(mode == 3){
    //this will put in 1:50
    digitalWrite(S0, LOW); //S0
    digitalWrite(S1, HIGH); //S1 
    //Serial.println("m1:50m");
    }
    
    return;

}

void TCS3200setup(){

    //initialize pins
    pinMode(LED,OUTPUT); //LED pinD
    
    //color mode selection
    pinMode(S2,OUTPUT); //S2 pinE
    pinMode(S3,OUTPUT); //s3 pinF
    
    //color response pin (only actual input from taos)
    pinMode(taosOutPin, INPUT); //taosOutPin pinC
    
    //communication freq (sensitivity) selection
    pinMode(S0,OUTPUT); //S0 pinB
    pinMode(S1,OUTPUT); //S1 pinA 
    
    return;

}

I wrote a small library for this some time ago. You can find it in the code repository (link below). What may be interesting for you is the pdf documentation attached as it describes how to calibrate the sensor, with associated example programs. One of them is to recognise specific colours and print the description.

The colour is read from the sensor OUTPUT as a frequency (square wave 50% duty cycle - simply means on/off wave which is off 50% and on 50%) that is proportional to the intensity of the colour you are measuring. S2 and S3 turn on filters on the sensor that allow you to read the 'redness', 'greeness' and 'blueness' (R G and B) of light emitted by the sample you are measuring. You can then combine the RGB readings to get an RGB colour mapping. So to determine one RGB colour you need to take 3 readings.

Hopefully that explanation is clear and you can see that your code is not correct, as S2 and S3 are outputs from the Arduino to control the filters, not inputs. All datasheets are written from the perspective of the device you are using, so an INPUT to the device is an OUTPUT from the Arduino.

johnwasser:
The chip has one output and four inputs. The inputs select which of the four color sensors is connected to the output. The output is a pulse frequency proportional to the light intensity. The sample code uses a timer and an interrupt input to measure pulses per time interval (frequency).

nice and concise - although not quite confirming all my queries.
at least the conclusion is my understanding of how a color sensor works is backwards !
i'm yet to delve into (hardware?) timers and interrupts so was hoping for a simpler function to "read the sensor output" - i'm guessing this will involve the pulseIn() function ?

marco_c:
I wrote a small library for this some time ago. You can find it in the code repository (link below). What may be interesting for you is the pdf documentation attached as it describes how to calibrate the sensor, with associated example programs. One of them is to recognise specific colours and print the description.

The colour is read from the sensor OUTPUT as a frequency (square wave 50% duty cycle - simply means on/off wave which is off 50% and on 50%) that is proportional to the intensity of the colour you are measuring. S2 and S3 turn on filters on the sensor that allow you to read the 'redness', 'greeness' and 'blueness' (R G and B) of light emitted by the sample you are measuring. You can then combine the RGB readings to get an RGB colour mapping. So to determine one RGB colour you need to take 3 readings.

Hopefully that explanation is clear and you can see that your code is not correct, as S2 and S3 are outputs from the Arduino to control the filters, not inputs. All datasheets are written from the perspective of the device you are using, so an INPUT to the device is and OUTPUT from the Arduino.

yes, it's the "sensor as OUTPUT (FROM the Arduino" that threw me off because i'm used to sensors being "INPUT devices" (to the Arduino).
anyway, you're right about the documentation being a help - much clearer language than the datasheet ! Thanks so much !!
will work through your library and sample and hopefully get a much clearer understanding once i've tried them all.
thanks again, Marco - great libraries you have there !

EDIT:
hello knut_ny,
i just re-read your post having had a little more understanding of how the sensor works, and i think your code is exactly the nice, simple, basic code i was looking for !
Thanks ! :slight_smile:

hello marco, recently I took a color sensor TCS230
and I am trying your codes.
I wanted to ask you a question, because it uses only S2 and S3?
in the code, the pin 2 is defined OE, should not be OUT?

I wanted to ask you a question, because it uses only S2 and S3?
in the code, the pin 2 is defined OE, should not be OUT?

Your question is unclear for me.

Output enable (/OE) places the output from the sensor into the high-impedance state for multiple-unit sharing of a microcontroller input line. This is an output from the MCU and an input to the Sensor.

ok, but I on serial monitor, the four examples when I run, I always get values equal to 0.
I run other codes, to obtain values using pin "OUT" sensor output frequency.
In your examples this pin is not defined.
What should I get with your examples?
pin sensor
S0
S1
S2
S3
OE defined in your examples
OUT defined in other examples, to obtain values
Vcc
GND
Thanks and sorry if I'm missing something simple.

The input pin to connect the senor 'OUT' to is fixed by the FreqCount library and depends on your Arduino board. Please read the documentation that comes with my library, the FreqCount library or at the codeplex location from where you downloaded the library.

I find it quite strange that no of the most popular tutorials on this sensor does not mention calibration one single time at all… isn’t black/white calibration completely crucial in order to get correct colors? Just tried so far without calibration, and it looks very strange… eg, a completely red paper vil have more blue and green in its values…

On another note, I was wondering if any of you know wether using the TCS3200 is more accurate than an RGB/LDR setup? To me it seems like the methods are very similar.

Agree about the calibration. I have not seen much about it either. Probably why my blog article at TCS230/TCS3200 Sensor Calibration – Arduino++ is the most read article.

marco_c:
Agree about the calibration. I have not seen much about it either. Probably why my blog article at TCS230/TCS3200 Sensor Calibration – Arduino++ is the most read article.

This might be a lame question, but how does one figure the Re and Ee values? Especially Re (device responsivity for a given wavelength of light in kHz/(mW/cm2)

Re is the device responsivity for a given wavelength of light given in kHz/(mW/cm2). This is a property of the sensor. Ee is the incident irradiance in mW/cm2 and is a property of the light striking the sensor.

Re is given in the datasheet for the sensor, although this seems to be dependent on the wavelength of incident light - "Irradiance responsivity Re is characterized over the range from zero to 5 kHz."

Aah, I couldn't find it in the datasheet first - but see it now. Thanks!

Btw, do you know what the difference from period and frequency measurements are?

Currently I'm reading the sensor by measuring intervals between pin transitions on the "out" pin, getting an average over 1 ms and converting this to frequency... would this be frequency measurement then?
it's just the datasheet that talks about it like 2 very different terms, and I'm a bit confused. How else than what I just described would it be possible to measure the sensor?

They are different but related. That is a very simple Google question ("difference between frequency and period") and learned in high school physics.

Well I know what the difference between frequency and period is. The datasheet is just describing it as two distinct ways of measuring. But in that case, I'll just have to assume that all the datasheet is referring to is simply the conversion from one to the other.

Hi,
Why are you using two threads for the same problem?

http://forum.arduino.cc/index.php?topic=469940.0
IMG_4964res.jpg
IMG_4965res.jpg

Tom… :slight_smile: