Saturday, January 14, 2017

Color Sensing Using Arduino

Color is one of the most important thing in our daily life, few days back i am thinking of a method by which we can sense color and do task based on the particular color.
After searching on internet i found few methods for sensing color the first method uses Red, Green, Blue Led and Photo-detectors (Photo-diodes, Photo-transistors, LDR), and the other method uses the color sensor from the TAOS (Texas Advanced Opto-electronics Solutions), so without wasting time i purchased the TCS3200 module from online and started playing with it.
So in this post i will show you how to use TCS3200 sensor with Arduino to sense multiple color papers and produce the same color using RGB Led.

So here is the list of components required to complete this project.

Components Required:
  • Color Sensor, TCS3200
  • External Power Supply for Arduino
  • Arduino Board (Arduino Uno)
  • Few Connecting Cables
  • Different Color Papers
  • RGB Led
  • And Few Resistors for Connecting RGB Led with Arduino (220 Ohm)
Connection Diagram:
Connection Diagram

The above figure shows the connection diagram, if you want to use some different pins then just update the macros associated with pin numbers in the sketch file present below in this post.

Sensor is Placed inside a Black Box-Image 1

Sensor is Placed inside a Black Box-Image 2
The above figure shows my setup, and the TCS3200 sensor is present inside this black box, I choose this black box to minimize the effect of IR rays and the unintended reflection, as black surfaces absorb most of the colors and doesn't reflect back anything, that's why we see black. 

Sensor Description:
Before proceeding further let get a short description of the sensor from its datasheet.
TCS3200 senses light with the help of 8x8 array of photo diodes, which means this sensor has total 64 photo-diodes present in it.

Out of these 8x8 array of photo-diodes:
  • 16 Photo-diodes are used to sense red color as they have red filter
  • 16 Photo-diodes are used to sense green color as they have green filter
  • 16 Photo-diodes are used to sense blue color as they have blue color filter
  • 16 Photo-diodes don’t have any filters
The sense light is converted into current and then a current to frequency converter is used to generate a square wave output depending upon the light received on Photo-diodes, this is illustrated using the following block diagram.
Functional Block Diagram
The pin-out of the sensor is as follow: 
Pin Out of the Sensor
Pin Number S2 and S3 are used to select the Photo Diode type, as we can’t activate all the photo-diodes at once, use the following table to select the group of photo-diodes.
Photo-diode Selection Table
Output Frequency Scaling feature is also present in this sensor, which makes this sensor easy to interface with devices like Arduino and other micro-controllers.
S0 and S1 pins of this sensor can be used to scale down the output frequency of this device, use the following table to select the scaling.
Output Frequency Scaling Table
This graph is the Spectral Responsivity Curve of this sensor, so as you can see clearly that in the infrared region of the spectrum all the red, green, blue filters are giving same response, which makes this sensor almost unusable if the Infra-Red signals are present, that’s why I used a Black Box to prevent the Infra-Red Signals from interfering with sensor readings.
Spectral Responsivity Curve
Another approach to prevent Infra-red rays is to use IR Filters to block the IR rays reaching the sensor, but they are quite costly, so I would suggest either to use black box with this sensor or use TCS34725 color sensor, which has inbuilt IR blocking filter inside it, as you can see in the spectral responsivity curve of the TCS34725 that the effect of IR signal is negligible and can be filtered out easily in software.
Spectral Responsivity Curve
In this project i used Red, Green, Blue, Yellow, Light Green, and Orange color papers for showing demo, but before that i used these papers to calculate the Red, Green, and Blue component value from the sensor and noted them in a Excel sheet as shown below.
Recorded Values for Calibration
Now i will use these values to detect colors and then display the detected color using RGB Led, you can also watch the video to see the demo.



The Program is as follow:
 #define NO_SAMPLES 100u  
 #define THRESHOLD  5u  
 // Color Thresholds  
 #define IDLE_RED_THRESHOLD   287u  
 #define IDLE_GREEN_THRESHOLD  95u  
 #define IDLE_BLUE_THRESHOLD   303u  
 #define RED_RED_THRESHOLD    164u  
 #define RED_GREEN_THRESHOLD   72u  
 #define RED_BLUE_THRESHOLD   174u  
 #define GREEN_RED_THRESHOLD   207u  
 #define GREEN_GREEN_THRESHOLD  65u  
 #define GREEN_BLUE_THRESHOLD  219u  
 #define BLUE_RED_THRESHOLD   227u  
 #define BLUE_GREEN_THRESHOLD  65u  
 #define BLUE_BLUE_THRESHOLD   241u  
 #define L_GRN_RED_THRESHOLD   157u  
 #define L_GRN_GREEN_THRESHOLD  51u  
 #define L_GRN_BLUE_THRESHOLD  166u  
 #define YLOW_RED_THRESHOLD   107u  
 #define YLOW_GREEN_THRESHOLD  46u  
 #define YLOW_BLUE_THRESHOLD   114u  
 #define ORNG_RED_THRESHOLD   121u  
 #define ORNG_GREEN_THRESHOLD  52u  
 #define ORNG_BLUE_THRESHOLD   128u  
 // Sensor Connections  
 const byte S0  = 8;  
 const byte S1  = 9;  
 const byte S2  = 10;  
 const byte S3  = 11;  
 const byte Sout = 12;  
 const byte RED  = 3;  
 const byte GREEN = 5;  
 const byte BLUE  = 6;  
 uint16_t sumOfSamples = 0;  
 uint16_t redData = 0;  
 uint16_t greenData = 0;  
 uint16_t blueData = 0;  
 void setup()   
 {  
  pinMode(S0, OUTPUT);  
  pinMode(S1, OUTPUT);  
  pinMode(S2, OUTPUT);  
  pinMode(S3, OUTPUT);  
  pinMode(Sout, INPUT);  
  // Setting frequency-scaling to 20%  
  digitalWrite(S0,HIGH);  
  digitalWrite(S1,LOW);  
  Serial.begin(115200);  
 }  
 void loop()   
 {  
  int i = 0;  
  // Apply Red Filter  
  digitalWrite(S2,LOW);  
  digitalWrite(S3,LOW);  
  delay(1);  
  sumOfSamples = 0;  
  for (i=0; i < NO_SAMPLES; i++)  
  {  
   // Reading the Pulse Width  
   sumOfSamples += pulseIn(Sout, LOW);  
  }  
  redData = sumOfSamples/NO_SAMPLES;  
  Serial.print("R = ");  
  Serial.print(redData);  
  delay(100);  
  // Apply Green Filter  
  digitalWrite(S2, HIGH);  
  digitalWrite(S3, HIGH);  
  delay(1);  
  sumOfSamples = 0;  
  for (i=0; i < NO_SAMPLES; i++)  
  {  
   // Reading the Pulse Width  
   sumOfSamples += pulseIn(Sout, LOW);  
  }  
  greenData = sumOfSamples/NO_SAMPLES;  
  Serial.print(" G = ");  
  Serial.print(greenData);  
  delay(100);  
  // Apply Blue Filter  
  digitalWrite(S2, LOW);  
  digitalWrite(S3, HIGH);  
  delay(1);  
  sumOfSamples = 0;  
  for (i=0; i < NO_SAMPLES; i++)  
  {  
   // Reading the Pulse Width  
   sumOfSamples += pulseIn(Sout, LOW);  
  }  
  blueData = sumOfSamples/NO_SAMPLES;  
  Serial.print(" B = ");  
  Serial.print(blueData);  
  Serial.println(" ");  
  delay(100);  
  if( isIdle() )  
  {  
   // Turn-Off All Led's  
   Serial.println("All Led's Off");  
   Set_RGB_Color(0,0,0);  
  }  
  if( isRed() )  
  {  
   // Turn-On Red Led  
   Serial.println("Red Led");  
   Set_RGB_Color(255u,0,0); // Red  
  }  
  if( isGreen() )  
  {  
   // Turn-On Green Led  
   Serial.println("Green Led");  
   Set_RGB_Color(0,255u,0); // Green  
  }  
  if( isBlue() )  
  {  
   // Turn-On Blue Led  
   Serial.println("Blue Led");  
   Set_RGB_Color(0,0,255u); // Blue  
  }  
  if( isYellow() )  
  {  
   // Turn-On Yellow Led  
   Serial.println("Yellow Led");  
   Set_RGB_Color(250,75,0); // Yellow  
  }  
  if( isLightGreen() )  
  {  
   // Turn-On Light Green Led  
   Serial.println("Light Green Led");  
   Set_RGB_Color(250,200,50); // Light Green  
  }  
  if( isOrange() )  
  {  
   // Turn-On Orange Led  
   Serial.println("Orange Led");  
   Set_RGB_Color(250,40,0);   // Dark Yellow/ Orange  
  }  
  delay(2000);  
 }  
 boolean isIdle( void )  
 {  
  boolean status = false;  
  if ( ((IDLE_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (IDLE_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((IDLE_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (IDLE_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((IDLE_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (IDLE_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 boolean isRed( void )  
 {  
  boolean status = false;  
  if ( ((RED_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (RED_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((RED_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (RED_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((RED_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (RED_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 boolean isGreen( void )  
 {  
  boolean status = false;  
  if ( ((GREEN_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (GREEN_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((GREEN_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (GREEN_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((GREEN_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (GREEN_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 boolean isBlue( void )  
 {  
  boolean status = false;  
  if ( ((BLUE_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (BLUE_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((BLUE_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (BLUE_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((BLUE_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (BLUE_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 boolean isLightGreen( void )  
 {  
  boolean status = false;  
  if ( ((L_GRN_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (L_GRN_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((L_GRN_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (L_GRN_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((L_GRN_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (L_GRN_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 boolean isYellow( void )  
 {  
  boolean status = false;  
  if ( ((YLOW_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (YLOW_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((YLOW_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (YLOW_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((YLOW_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (YLOW_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 boolean isOrange( void )  
 {  
  boolean status = false;  
  if ( ((ORNG_RED_THRESHOLD-THRESHOLD) < redData)   
  && (redData < (ORNG_RED_THRESHOLD+THRESHOLD)) )  
  {  
   if ( ((ORNG_GREEN_THRESHOLD-THRESHOLD) < greenData)   
   && (greenData < (ORNG_GREEN_THRESHOLD+THRESHOLD)) )  
   {  
    if ( ((ORNG_BLUE_THRESHOLD-THRESHOLD) < blueData)   
    && (blueData< (ORNG_BLUE_THRESHOLD+THRESHOLD)) )  
    {  
     status = true;  
    }  
   }  
  }  
  return status;  
 }  
 void Set_RGB_Color( uint8_t red, uint8_t green, uint8_t blue)  
 {  
  analogWrite(RED, red);  
  analogWrite(GREEN, green);  
  analogWrite(BLUE, blue);  
 }  

The following images illustrate the behavior of my system after running the above Arduino Sketch.
Blue Color Paper Detected and Blue Led Glows

Light Green Color Paper Detected and Light Green Led Glows

Green Color Paper Detected and Green Led Glows

Orange Color Paper Detected and Orange Led Glows

Red Color Paper Detected and Red Led Glows

Yellow Color Paper Detected and Yellow Led Glows
Conclusion:
This method works fine, and for those who want to do some more experiment they can use convex lens to increase the range of the sensor and use red green and blue, high intensity led to illuminate the surface of the object.

2 comments:

  1. Hello Sir amazing piece of work ,can u suggest a program where purple color can be detected

    ReplyDelete
    Replies
    1. Thanks.
      You have to follow the same approach to detect the purple color as used above for other colors.
      Steps:
      Take Purple color and check the values given by sensor, and use these values next time detect the purple color with some threshold.

      Delete