RGB Color Sensor

For the Autonomous Surface Vehicle Competition this year one of the challenges is to detect the color sequence of a flashing LED array underwater. In order to do this I had discussed several ideas with a good friend, and teammate, Aaron Casson. I had thought that we could be utilize photoresistors for detecting the differences in light intensity. Aaron had an idea to use different colored filters in front of the photoresistors to specify which wavelengths of light would pass through the filter, which would allow us to compare how much of each color-spectrum is found, thus allowing us to distinguish the color.

We felt pretty dumb after I searched online for RGB color sensors, because we had spent quite quite a bit of time thinking of ways to get filters in order to make these sensors while allowing us to easily mount them to our boat. Turns out that RGB color sensors are abundant online, and these manufactured analog sensors have a large array of filtered photoresistors in for the red, green, and blue color spectrums. The sensor we chose contained a TCS3200, which is a "programmable color light-to-frequency converter that combines configurable silicon photodiodes and a current-to-frequency converter on a single monolithic CMOS integrated circuit," that an Arduino micro-controller can easily utilize to help with our challenge. The array contains an 8x8 array of photodiodes, 16 filters for photodiode for sensing the red, green, and blue color spectrum. The remaining photodiodes are clear with no filters which can also help us in the challenge since we have to find the sensor that is lit up with white light before the color sequences are initiated by a JSON message from our boat. 

 

    To the right is the top view of the sensor, from the Texas Advanced Optoelectronic Solutions (TAOS) datasheet on the TCS3200

On the left is an image found from Reibot.org, which clearly shows the filter array. It is pretty neat to see the color filters arranged in that pattern because it allows for a more even reading of the RGB spectrums. Some of these arrays I have found have all the filter colors grouped together, which I would assume to be slightly less precise but I don’t think it would be very noticeable considering the array is a 1mm x 1mm square. I found a closer image of the array from  user comment on the order page for a RGB  Sparkfun sensor. I felt that he deserved credit for the unique photo, so I posted to his comment below along with his photo.

After ordering a couple of sensors that had the TCS3200 chip off of eBay for around $4 I was able to test the sensor that had built in LEDs to read the color of objects that do not emit light on their own, and it seemed to be pretty effective. Following that, I removed the LEDs from the sensor and tested it with just colored light. It did alright in tests, but I really need to see how it would do outside, and out under the water.

In order to explain the logic of the sensor and how the boat would utilize the sensor data for recording and returning the light sequence I made a visual demonstration which consisted of the sensor on the outside of a waterproof box, with output LEDs in the inside to display the color of the input data. I just wanted a quick display reference so I only included a red, green, and blue LED to display which color spectrum found the largest amount of light. It took a lot of effort to resist getting a RGB-LED and wiring it up to a transistor to output a larger and more accurate variety of colors. Unfortunately I need to use that time for writing more autonomous boat code, or for documentation, like I’m doing at this moment.

Anyway, the build is not very elaborate. The sensor was placed into a “waterproof” container that had several holes. I used some of the inside organizer pieces that were in the way for the electronics for patching the holes. I remelted the thermoplastic around the hole and cooled the liquid plastic around both holes on the bottom and then I used hot glue around the sensor at the top for a flush seal. The sensor itself is not waterproof, so sealing the holes was completely unnecessary but I plan on using this box for other things later once I remove the sensor from the outside and I was trying to just have less holes the next time I need to use the container.

 

        I ran the wires through the bottom before sealing it in with hot glue. The wires ran into an Arduino and breadboard. The pinout I used is in my code, which is at the end of this document. The red, green, and blue leds are attached to the breadboard with 150Ω resistors on their ground leads. I added some Li-Ion batteries to make it portable and attached a switch to the top side.

        And here are some images of the color display. If you look carefully you can see the LEDs in the top right hand corner of the box displaying the color seen in front of the sensor. The LEDs around the sensor itself are the ones used to light up the object and reflect back the object’s color. It is white light, but does appear bluish in the pictures. For the image that I am holding my shirt over the sensor the blue LED is lit in the top-right hand corner of the box, which indicates that the sensor is finding the largest spectrum of light in blue wavelength. The same process is shown for the red and green colors. The red is very dim from a lack of power, due in part to two sensors being activated to read the red spectrum alongside the four white LEDs being lit.

        And here is the code I used just for the recognition and display:

//pins for the sensor are s0,s1,s2,s3 following the datasheet schematic//red,green,blue are the pins for the LED//g_Pin is the ground pin, or pin to utilize the switch                     //(if detected pin==GND turn on/off)int s0=3,s1=4,s2=5,s3=6,red=13,green=12,blue=11,g_Pin=8;//pins to indicate direction boat will travel with a triangular                     //photoresistor arrayint led_L=48,led_R=50,led_B=52;int flag=0;int counter=0;int countR=0,countG=0,countB=0;void setup()  {// Serial.begin(115200);  pinMode(s0,OUTPUT);  pinMode(s1,OUTPUT);   pinMode(s2,OUTPUT);  pinMode(s3,OUTPUT);  }void TCS()  {    digitalWrite(s1,HIGH);    digitalWrite(s0,LOW);    flag=0;    attachInterrupt(0, ISR_INTO, CHANGE);    timer2_init();  }void ISR_INTO()  {    counter++;  }  void timer2_init(void)  {    TCCR2A=0x00;    TCCR2B=0x07; //the clock frequency source 1024 points    TCNT2= 100;    //10 ms overflow again    TIMSK2 = 0x01; //allow interrupt  }  int i=0;  ISR(TIMER2_OVF_vect)//the timer 2, 10ms interrupt overflow again. Internal overflow interrupt executive function{  TCNT2=100;  flag++;  if(flag==1)   {     counter=0;   }  else if(flag==2)    {     digitalWrite(s2,LOW);     digitalWrite(s3,LOW);      countR=counter/1.051;     Serial.print("red=");     Serial.println(countR,DEC);     digitalWrite(s2,HIGH);     digitalWrite(s3,HIGH);       }  else if(flag==3)     {      countG=counter/1.0157;     Serial.print("green=");     Serial.println(countG,DEC);      digitalWrite(s2,LOW);      digitalWrite(s3,HIGH);          }  else if(flag==4)     {      countB=counter/1.114;     Serial.print("blue=");     Serial.println(countB,DEC);      digitalWrite(s2,LOW);      digitalWrite(s3,LOW);      }  else      {      flag=0;        TIMSK2 = 0x00;      }      counter=0;      delay(2);}void loop()  {        //if (g_Pin == HIGH)    //{   delay(10);   TCS();   if((countR>10)||(countG>10)||(countB>10))    {       if((countR>countG)&&(countR>countB))        {             Serial.print("red");             Serial.print("\n");             digitalWrite(red, HIGH);             delay(250);             digitalWrite(red, LOW);        }       else if((countG>=countR)&&(countG>countB))        {             Serial.print("green");             Serial.print("\n");             digitalWrite(green, HIGH);             delay(250);             digitalWrite(green, LOW);        }       else if((countB>countG)&&(countB>countR))       {             Serial.print("blue");             Serial.print("\n");             digitalWrite(blue, HIGH);             delay(250);             digitalWrite(blue, LOW);       }     }   else    {      delay(1000);          }   }