Color Sensing with TCS3200, Need Help with Code & Understanding

Hi Everyone,

I just picked up an Arduino "Clone" called the UNO R3.

I'm using a TCS3200 Color Sensor, and a RGB LED board that has the Resistor built in.

I'm trying to learn and understand how Color Sensing works, where the sensor scans the color, and outputs the same color to the RGB LED.

What I First Found

First, I found this code online that looks to be like it'll do exactly what I need. However, it doesn't work, even though the creator has a YouTube video to show it working. When I use the code, the sensor outputs nothing to the LED, and when I look at the Terminal, it seems like its not detecting anything. I've checked my wiring multiple times.

Here's the code: Color Sensing Using Arduino - Embedded Laboratory

What I Found Next, Which Does Work...Sorta

I found this code, which works as intended, but it's a bit too basic. It only is capable of detecting and outputting Red, Green and Blue, individually. It doesn't detect nor output white, cyan, purple, or any other "mix". It uses digitalwrite, which I've changed to analogwrite, in hopes to get a more varied output, with no avail.

Additionally, his code shows the LED is "off" (all set to LOW) when not detecting anything, but my LED remains red until it detects a color. Not sure why...

Here's the code: https://engmousaalkaabi.blogspot.hk/2015/12/color-sensor-using-arduino-and-tcs230.html

So, What Now?

Can anyone assist me with either code? I'm just wanting the sensor to be able to "scan" more colors, and output the colors (including mixed, like RED and Blue to make purple, etc.

Much appreciated. This is just for educational use, as I'm trying to learn more about the subject. I'm poor at programming.

the sensor outputs nothing to the LED

No sensor outputs to leds. A sensor sends signals to the central unit (your Arduino), which does something with the info and outputs in turn something to a LED or something else.

It only is capable of detecting and outputting Red, Green and Blue, individually

That's all there is, if we are just talking about colours humans can see. Put together the values of red, green and blue and you get all the colours.

If I remember correctly, your sensor lights with four white LEDs an object close to the LEDs. Inbetween, on the PCB, is the actual sensor, which reads how much red, green and blue is reflected (or received from any ambient light around).

EDIT

Ok, your latter link obviously shows a project, where the sensor really doesn't do anything else than detect one of the three colours, whichever is the strongest.

Johan_Ha:
No sensor outputs to leds. A sensor sends signals to the central unit (your Arduino), which does something with the info and outputs in turn something to a LED or something else.
That's all there is, if we are just talking about colours humans can see. Put together the values of red, green and blue and you get all the colours.

If I remember correctly, your sensor lights with four white LEDs an object close to the LEDs. Inbetween, on the PCB, is the actual sensor, which reads how much red, green and blue is reflected (or received from any ambient light around).

EDIT

Ok, your latter link obviously shows a project, where the sensor really doesn't do anything else than detect one of the three colours, whichever is the strongest.

I didn't mean the sensor itself interfaces with the LEDs... I mean the first project's code doesn't "output" any color to the LED. The RGB LED just remains off, however the video shows it as working properly. So I'm not sure what the issue is...

The second code seems to do as I'm looking for, but it only can change the LED to Red, Green or Blue. It can't do cyan, purple, white, etc (all of which are a mix of each color at a certain intensity?). So I want to update it to do that, but I'm not sure how to go about doing so.

Basically, in a nutshell:

I'm looking for/trying to make code that will use the TCS3200 to "scan" a color, and output the same color onto the RGB LED. Basically I want to be able to put a piece of colored paper in-front of the Color Sensor, and have the LED display the color of the paper. I'd like to be able to "input" a piece of colored paper, and "output" the colors onto the LED..

This first code seems to do this, but doesn't work. I'd love to use this code, just for experimenting with, but I'm not sure why it doesn't work.

And the second code, can only "scan" red, green or blue color, and put it to the LED. It can't do orange, yellow, purple, etc like the first code claims to do. It's much more basic as well....

Sorry for my lack of technological terms, English isn't my first language.

Keep on searching for other examples. There must be hundreds. Like this one:

If you run into the same problem again, either your sensor is bad or your way of connecting everything is faulted.

Yeah, I'll keep looking around. I kinda think the first code is broken, as my sensor does work with the second code. I also checked my wiring a lot for the first code.

I appreciate the link. Google is banned in my country, so it's hard for me to find resources or snippets.

EDIT: Ah, that code isn't for using an RGB LED with it to display the color.

But I guess I can use it to test my sensor. :slight_smile:

EDIT 2: Just wired it up and tested, yeah the sensor works fine. Now to figure out how to output the RGB info that it displays in serial monitor, into the RGB LED.... Any ideas?

EDIT 3: Here's my code. I've got the LED to turn on, but it's displaying white (and all the RGB colors). I've bolded the code that I added. I'm getting closer, but not figured out why it doesn't work yet.

It's still displaying the RGB values into the terminal. But not putting them into the LED.

#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8
#define RGBLEDR 10
#define RGBLEDG 11
#define RGBLEDB 12

int frequency = 0;
void setup() {
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);
** pinMode(RGBLEDR, OUTPUT);**
** pinMode(RGBLEDG, OUTPUT);**
** pinMode(RGBLEDB, OUTPUT);**

// Setting frequency-scaling to 20%
digitalWrite(S0,HIGH);
digitalWrite(S1,LOW);

Serial.begin(9600);
}
void loop() {
// Setting red filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,LOW);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 25,72,255,0);
** digitalWrite(RGBLEDR,frequency);**
// Printing the value on the serial monitor
Serial.print("R= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.print(" ");
delay(300);
// Setting Green filtered photodiodes to be read
digitalWrite(S2,HIGH);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 30,90,255,0);
** digitalWrite(RGBLEDG,frequency);**
// Printing the value on the serial monitor
Serial.print("G= ");//printing name
Serial.print(frequency);//printing GREEN color frequency
Serial.print(" ");
delay(300);
// Setting Blue filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 25,70,255,0);
** digitalWrite(RGBLEDB,frequency);**
// Printing the value on the serial monitor
Serial.print("B= ");//printing name
Serial.print(frequency);//printing BLUE color frequency
Serial.println(" ");
delay(300);
}

Write a separate program that outputs various RGB values to the LED. When you get a hang of it, you know how to fix the code in your post #4.

Johan_Ha:
Write a separate program that outputs various RGB values to the LED. When you get a hang of it, you know how to fix the code in your post #4.

Yeah, I'm guessing that I need to make a void argument(?), that has the R,G,B number passed into it, and then digitalwrite() into the LED.

I'm studying some of the RGB tutorials to see if they'll help me.

Something along the lines of

LEDColor(frequency) in the void loop,

and then a separate function of:

void LEDColor() {
digitalWrite(RGBLEDR,frequency);
digitalWrite(RGBLEDG,frequency);
digitalWrite(RGBLEDB,frequency);

}

You have correct values in the termina? Just write them with analogWrite() to the right LED pins. Not digitalWrite().

Johan_Ha:
You have correct values in the termina? Just write them with analogWrite() to the right LED pins. Not digitalWrite().

Yeah, the terminal has the correct RGB values. They show up as:

R= 104 G= 124 B= 142
R= 98 G= 124 B= 148
R= 104 G= 124 B= 142
R= 98 G= 124 B= 176

They're constantly changing because every 300(ms?) the loop runs again or whatever. And thats what I want it to do.

What I'm stuck on is getting these values to write to the LED dynamically, I guess? (So if I just analogwrite the first set of RGB number, it will just stay at those. I dont want that, I want it to write to the LED in the same way its writing to the terminal, if that makes sense).

I made a function for it, that uses analogwrite, but I'm not sure what arg to pass into it.

void LEDColor(int v1, int v2, int v3) {
  analogWrite(RGBLEDR,v1);
  analogWrite(RGBLEDG,v2);
  analogWrite(RGBLEDB,v3);
  
}[b][/b]

It's been a few years since I did any programming, so I appreciate the help.

v1,v2,v3 are the RGB values that get displayed in the terminal. Just not sure what argument to pass into the function to actually do that. I know I need to take the RGB values that are shown in the terminal and put them on the LED.

If you write R = 124 to the rerminal, you pass 124 as the arg v1.

Johan_Ha:
If you write R = 124 to the rerminal, you pass 124 as the arg v1.

Hmm, I'm not too sure what you mean.

Here's the code, just toying around with passing "frequency" into function. What needs to be changed?

#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8
#define RGBLEDR 10
#define RGBLEDG 11
#define RGBLEDB 12

int frequency = 0;
void setup() {
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);
pinMode(RGBLEDR, OUTPUT);
pinMode(RGBLEDG, OUTPUT);
pinMode(RGBLEDB, OUTPUT);

// Setting frequency-scaling to 20%
digitalWrite(S0,HIGH);
digitalWrite(S1,LOW);

Serial.begin(9600);
}
void loop() {
// Setting red filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,LOW);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 25,72,255,0);
LEDColor(frequency,frequency,frequency);
// Printing the value on the serial monitor
Serial.print("R= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.print(" ");
delay(300);
// Setting Green filtered photodiodes to be read
digitalWrite(S2,HIGH);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 30,90,255,0);
LEDColor(frequency,frequency,frequency);
// Printing the value on the serial monitor
Serial.print("G= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.print(" ");
delay(300);
// Setting Blue filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 25,70,255,0);
LEDColor(frequency,frequency,frequency);
// Printing the value on the serial monitor
Serial.print("B= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.println(" ");
delay(300);
}

void LEDColor(int v1, int v2, int v3) {
analogWrite(RGBLEDR,v1);
analogWrite(RGBLEDG,v2);
analogWrite(RGBLEDB,v3);

}

Yeah, the terminal has the correct RGB values. They show up as:

R= 104 G= 124 B= 142
R= 98 G= 124 B= 148
R= 104 G= 124 B= 142
R= 98 G= 124 B= 176

There you output the same values you have to write to the LED pins.

The outputs constantly change because: 1) Different colors & objects being sensed 2) Different lighting and such.

So, I worry that statically assigning them would make it so only these colored objects or cards would be scannable. (And I’d probably have to go scanning pretty much everything I want to “sense” with the TCS3200 color sensor, to log it in the code.)

Is there no way to “dynamically” do it? Like tell the RGB LED to display the color based upon the information that’s streamed into terminal, dynamically?

If this doesn’t pose a problem, because most colors will be detected and outputted in a similar way to eachother (like a white card would show a white LED and a white wall would show a white LED), then could you provide me the code necessary to do that?

I feel lost, hah! Thank you again, you’ve been super helpful. I gave you karma :slight_smile:

So you have a moment in your program when this is written to the terminal:
R= 104 G= 124 B= 142

Locate that line in the code. Add something that will write those same values, whichever they are, to the pins connected to the RGB LED. Or am I missing something here?

You manage to write 104 in the terminal. Then 98. Why don't you manage to write the same values to the RGB LED pins? Writing to the terminal happens "dynamically", right? So should writing to the LEDs.

I'll give that a shot! That's what I've been trying to do, just not sure exactly how to do that. I've tried using the integer of "frequency" because thats what seems to be used to set those numbers, but maybe it's not.

I'll keep messing around with it. I found some code online that does work properly, but it's not efficient and not so good for my sensor. So I really want to get this one working.

EDIT:

Awesome, I think I got it, kinda! It's not so accurate, and sometimes I get negative results (like R -382), could you check?

What I changed was, setting a int for each corresponding color (R,G,B) and making that equal the frequency before the frequency is used to detect another color. Then I've set the analogwrite to write that number to the pin.

What I think I need to do next is: 1) Calibrate the sensor so its more accurate. 2) Find some way to remove the negative numbers (so it is just from 0 to 255), and 3) Turn off RGB LED if it's not detecting anything (or if it detects the same "environmental color data" for an extended period of time.).

I'd appreciate some tips and feedback on how to do that.

For some reason, even when scanning a green or blue, etc color object, the red LED is on as well. Not sure why. As the number for the red would be low (like negatives actually in terminal), so the pin shouldnt be getting any data. Maybe I need to get rid of these negative values...

#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8
#define RGBLEDR 10
#define RGBLEDG 11
#define RGBLEDB 12

int frequency = 0;
int rcolor;
int gcolor;
int bcolor;

void setup() {
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);
pinMode(RGBLEDR, OUTPUT);
pinMode(RGBLEDG, OUTPUT);
pinMode(RGBLEDB, OUTPUT);

// Setting frequency-scaling to 20%
digitalWrite(S0,HIGH);
digitalWrite(S1,LOW);

Serial.begin(9600);
}
void loop() {
// Setting red filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,LOW);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 25,72,255,0);
rcolor = frequency;
//LEDColor(frequency,frequency,frequency);
// Printing the value on the serial monitor
Serial.print("R= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.print(" ");
delay(300);
// Setting Green filtered photodiodes to be read
digitalWrite(S2,HIGH);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 30,90,255,0);
gcolor= frequency;
// LEDColor(frequency,frequency,frequency);
// Printing the value on the serial monitor
Serial.print("G= ");//printing name
Serial.print(frequency);//printing GREEN color frequency
Serial.print(" ");
delay(300);
// Setting Blue filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB Model of 0 to 255
frequency = map(frequency, 25,70,255,0);
bcolor = frequency;
// LEDColor(frequency,frequency,frequency);
// Printing the value on the serial monitor
Serial.print("B= ");//printing name
Serial.print(frequency);//printing BLUE color frequency
Serial.println(" ");
delay(300);

analogWrite(RGBLEDR,rcolor);
analogWrite(RGBLEDG,gcolor);
analogWrite(RGBLEDB,bcolor);

}

Put the code in code tags, not quote tags.

Change this:

  // Setting Blue filtered photodiodes to be read
  digitalWrite(S2,LOW);
  digitalWrite(S3,HIGH);
  // Reading the output frequency
  frequency = pulseIn(sensorOut, LOW);
  //Remaping the value of the frequency to the RGB Model of 0 to 255
  frequency = map(frequency, 25,70,255,0);
  bcolor = frequency;

...to this:

  // Setting Blue filtered photodiodes to be read
  digitalWrite(S2,LOW);
  digitalWrite(S3,HIGH);
  // Reading the output frequency
  frequency = pulseIn(sensorOut, LOW);
  //Remaping the value of the frequency to the RGB Model of 0 to 255
  bcolor = map(frequency, 25,70,255,0);

This is just for clarity. Let the frequency variable hold the frequency value . Don't change that variable to anything else. Instead use bcolor for the converted value.

That won't correct the harmful negative values. The map function will return a negative value, if the frequency goes (due to faulty reading from the sensor?) over the upper limit. The map function doesn't automatically restrict the values to the 0 - 255 interval.

Either check for faulty readings and neglect them. Or dig into the cause of the faults. One thing that might cause them is that the sensor logic is not as fast as the Arduino. With some other digital sensor - don't remember what it was - people did something like this:

digitalWrite(S2,LOW);
digitalWrite(S2,LOW);
digitalWrite(S3,HIGH);
digitalWrite(S3,HIGH);

Thank you so much. I'll change the code a bit later, and will update you on my findings.

I'm curious if the negative values would be pushed into the LED, or if the code treats negative values as equal to 0. Maybe an if else statement could handle that?

I'm not sure why the red LED seems to be on even if I'm "scanning" a green object, but I've had a bit better results when using a "shroud" around the sensor (to block out outside light). I diffused the LED with some tape for the time being, and the effect of the red is a lot less noticeable (good!).

Just take care that you change each negative value to 0 before outputting it. A negative value just becomes another positive value. val + 256 or something similar. Better set it to zero.