The world is colorful – part 3 of 3

In this post we will demonstrate how to identify the color of a sample by using the TCS3414 digital color sensor.  From a technical point of view, color is determined by 3 major factors: the illuminator (light source), the object, and the observer (the detector).  In some cases the object is combined with the illuminator, as in part 2 of this series, where the object we want to measure is actually the illuminator itself, i.e. the LED light.  However, in many other cases, we want to find out the color of a real object, such as a piece of color paper, or the paint on a wall.

 

A. Project description

In this project, we will use a white LED as the illumination source, the TCS3414 digital color sensor as the detector, to find out the color of several color cards. Our target is to identify each card. We will use the Serial Monitor coming with the Arduino IDE to communicate with Arduino Nano board and receive the measurement result. Please refer to this post for connecting Nano to a PC.

The main idea of this project is, when illuminated by a broadband white LED, a card will reflect different red, green and blue light, depending on its color. Those different red, green and blue light signals will be detected by the TCS3414 color sensor. By matching the weight of (red, green, blue) color combination with previously measured library data, the color of the measured card can be identified.

 

B. Material

1. Arduino Nano board x 1
2. Breadboard x 1
3. TCS3414 evaluation board x 1
4. Broadband white LED x 1
5. 150 Ohm resistor x 1
6. 10k Ohm resistor x 2 (optional)
7. Jumper wires
8. USB cable (A plug to mini-B plug) x 1
9. Some color cards and cardboard

 

C. Key notes

TCS3414 comes with a small package, roughly 3mm x 2mm size. It’s hard to handle directly in a prototype project. Luckily, there are some evaluation board developed for it, with the TCS3414 sensor soldered on the evaluation board and the evaluation board can be directly plugged into a solderless breadboard.

The supply voltage of the TCS3414 sensor is between 2.7V and 3.6V, so we can use the 3.3V output of the Arduino Nano board to drive the sensor.

In order for the I2C bus of TCS3414 and Arduino Nano to work well, we can connect two pull up resistors (about 1k Ohm to 10k Ohm) between the 3.3V supply voltage and the SCL and SDA pins. But in this project, we didn’t use the two pull up resistors and the system still works fine.

 

D. Diagram

Diagram

 

E. Arduino Sketch

 

/*
Color Sample Measurement

This sketch demonstrates how to use a white LED and
a TCS3414 color sensor to measure the color of a
sample and find its closest match from a library.

Open Source Photonics
osphotonics@gmail.com

9/12/2014
*/

#include <Wire.h>;

// define the pins to drive the white LED
int led = 3;    

// define parameters for serial communication
char inCommand[10];
int lf = 10;

// define parameters for TCS3414
unsigned int TCS3414values[4];  // [Clear,Red,Green,Blue]
int integrationTime = 100;      // ms
int delay1 = 14;                // ms, for TCS3414 to initiate

// define parameters for color search
unsigned int blackCal[4];     // to store black calibration data
unsigned int whiteCal[4];     // to store white calibration data
int libColorValue[10][4];     // to store library color values
char libColorName[10][4];     // to store library color names
int libColorTotal = 0;        // total color records in library

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);    // get the white LED ready
  Serial.begin(19200);       // start serial port at 19200 bps
  Wire.begin();              // join I2C bus
  TCS3414Start(delay1, integrationTime);  // get TCS3414 ready
}

void loop() {
  while (Serial.available() > 0) {
    Serial.readBytesUntil(lf,inCommand,8);  // read string 

    if (inCommand[6] == ';') { // proper command length and ending
      if (String(inCommand).substring(0,6) == "meaSam") {
        getMeasureSample();
      }
      else if (String(inCommand).substring(0,3) == "add") {
        getAddLib(inCommand);
      }
      else {
        Serial.print('?');  // unknown command
        Serial.print('\n'); // new line
      }
    }
    else {
      Serial.print('?');  // not proper command length and ending
      Serial.print('\n'); // new line
    }
  }
}

void getAddLib(char inCommand[7]) {
  int i,j;
  int colorExist;
  unsigned int tempValue[4];  // to store temporary data
  char tempName[4];

  //enable TCS3414 integration
  Wire.beginTransmission(0x39); // slave address: 0011 1001
  Wire.write(0x80);             // write to Control register
  Wire.write(0x03);             // Enable ADC_EN
  Wire.endTransmission();

  // allow integration
  delay(integrationTime+10);  // wait slightly longer

  // get back crgb values
  TCS3414All(TCS3414values);

  //disable TCS3414 integration
  Wire.beginTransmission(0x39); //slave address: 0011 1001
  Wire.write(0x80);             //write to Control register
  Wire.write(0x01);             //Disable ADC_EN
  Wire.endTransmission();

  tempValue[0] = TCS3414values[0];
  tempValue[1] = TCS3414values[1];
  tempValue[2] = TCS3414values[2];
  tempValue[3] = TCS3414values[3];

  // get color name from incommand
  tempName[0] = inCommand[3];
  tempName[1] = inCommand[4];
  tempName[2] = inCommand[5];
  tempName[3] = '';

  colorExist = 0;
  for (i=0;i<libColorTotal;i++) { // if the color is in the library
    if (String(tempName) == String(libColorName[i])) {
      // if yes, replace the old one
      libColorName[i][0] = tempName[0];
      libColorName[i][1] = tempName[1];
      libColorName[i][2] = tempName[2];
      libColorValue[i][0] = tempValue[0];
      libColorValue[i][1] = tempValue[1];
      libColorValue[i][2] = tempValue[2];
      libColorValue[i][3] = tempValue[3];
      colorExist = 1;
      break;
    }
  }

  if (!colorExist) {  // if not, append one at the end
    libColorName[libColorTotal][0] = tempName[0];
    libColorName[libColorTotal][1] = tempName[1];
    libColorName[libColorTotal][2] = tempName[2];
    libColorValue[libColorTotal][0] = tempValue[0];
    libColorValue[libColorTotal][1] = tempValue[1];
    libColorValue[libColorTotal][2] = tempValue[2];
    libColorValue[libColorTotal][3] = tempValue[3];
    libColorTotal = libColorTotal + 1;
  }

  // send back result
  Serial.print('*');
  for (i=0; I<4; i++) {
    Serial.print(tempValue[i]);
    if (i==3) {
      Serial.print('\n');
    }
    else {
      Serial.print(',');
    }
  }

  Serial.println("Library---");
  for (i=0;i<libColorTotal;i++) {
    Serial.print(String(libColorName[i])+':');
    for (j=0; j<4; j++) {
      Serial.print(libColorValue[i][j]);
      if (j==3) {
        Serial.print('\n');
      }
      else {
        Serial.print(',');
      }
    }
  }
}

void getMeasureSample() {
  int i;
  unsigned int tempValue[4];
  int bestMatch;
  float merit, tempMerit;

  //enable TCS3414 integration
  Wire.beginTransmission(0x39); // slave address: 0011 1001
  Wire.write(0x80);             // write to Control register
  Wire.write(0x03);             // Enable ADC_EN
  Wire.endTransmission();

  // allow integration
  delay(integrationTime+10);  // wait slightly longer

  // get back crgb values
  TCS3414All(TCS3414values);

  //disable TCS3414 integration
  Wire.beginTransmission(0x39); //slave address: 0011 1001
  Wire.write(0x80);             //write to Control register
  Wire.write(0x01);             //Disable ADC_EN
  Wire.endTransmission();

  tempValue[0] = TCS3414values[0];
  tempValue[1] = TCS3414values[1];
  tempValue[2] = TCS3414values[2];
  tempValue[3] = TCS3414values[3];

  bestMatch = -1;
  merit = 1e8;
  tempMerit = merit;

  for (i=0;i<libColorTotal;i++) {
    tempMerit = sq(float(tempValue[1])-float(libColorValue[i][1])) +
                sq(float(tempValue[2])-float(libColorValue[i][2])) +
                sq(float(tempValue[3])-float(libColorValue[i][3])) ;

    if (tempMerit < merit) {
      merit = tempMerit;
      bestMatch = i;
    }
  }

  Serial.print("Your best match is: ");
  Serial.println(String(libColorName[bestMatch]));

}

void TCS3414Start(int delay1,int integrationtime){
  // initialize
  Wire.beginTransmission(0x39); // slave address: 0011 1001
  Wire.write(0x80); // write to Control register
  Wire.write(0x01); // Turn the device on (does not enable ADC yet)
  Wire.endTransmission();

  delay(delay1); // for TCS3414 to initialize

  Wire.beginTransmission(0x39); //slave address: 0011 1001
  Wire.write(0x81);  // Write to Timing (integration) register
  Wire.write(0x01);  // set free running INTEG_MODE and integration time to 100ms
  Wire.endTransmission();

  Wire.beginTransmission(0x39); // slave address: 0011 1001
  Wire.write(0x87);             // write to Gain register
  Wire.write(0x10);             // set gain to x4
  Wire.endTransmission();
}

// ============================================================
// Sensor read functions - retrieves the CRGB raw sensor values
// ============================================================

void TCS3414All(unsigned int allcolors[]){

  allcolors[0] = TSC3414(1);  // Clear channel
  allcolors[1] = TSC3414(2);  // Red channel
  allcolors[2] = TSC3414(3);  // Green channel
  allcolors[3] = TSC3414(4);  // Blue channel

  //returns all colors;
}

// Gets the sensor value at selected channel and returns an unsigned int
unsigned int TSC3414(unsigned int channel) {
  unsigned int channelLow = 0;
  unsigned int channelHigh = 0;

  Wire.beginTransmission(0x39); // slave address: 0011 1001
  if (channel == 1) Wire.write(0xB6);             // read Clear register
  else if (channel == 2) Wire.write(0xB2);        // read Red register
  else if (channel == 3) Wire.write(0xB0);        // read Green register
  else if (channel == 4) Wire.write(0xB4);        // read Blue register
  Wire.endTransmission();

  Wire.beginTransmission(0x39); // slave address: 0011 1001
  Wire.requestFrom(0x39,2); // Request information
  channelLow = Wire.read();
  channelHigh = Wire.read();
  Wire.endTransmission();

  channelHigh = (channelHigh * 256) + channelLow;
  return channelHigh;
}

 

F. Result and discussion

After we connect the LED, the resistor and the TCS3414 sensor with the Arduino Nano board, we can get a breadboard system as shown below (the pins of the white LED can be cut shorter to match the height of the sensor board):

breadboard setup

Then we can connect the Nano board with a PC through the USB cable, and load the Arduino sketch shown in section E into the Nano board. The system will then start to work.  To avoid the crosstalk between the LED and the color sensor, we can add a piece of black paper as a blocker between them, as shown below:

breadboard setup with blocker

Also, in order to allow the TCS3414 sensor to detect the light reflected from the paper card and reject ambient light, we can add an enclosed spacer around the LED and the color sensor.  In this project, we simply fold a piece of cardboard to make a spacer, and add a black inner layer to minimize the straylight, as shown below:

breadboard setup with spacer

Now we can put the color paper card on top of the spacer to start building library and measuring color, as shown below (the color side should face the sensor):

setup with color card

After we open the Serial Monitor from the Arduino IDE, commands can be sent from PC to the Arduino board to let it work.  In this project we simply use two commands:

add***;
meaSam;

Both the commands are 7 characters long, with the last being ‘;’ to terminate the command.

The first command “add***;” is used to add a color in the library. The characters “***” represents the color name, so for example, you can use “addRed;” to add a red sample in the library, “addBlu;” to add a blue sample in the library, etc.  If there exists the same color in the library already, the existing one will be replaced by the new one. Before adding color, you should place the paper with the known color on top of the spacer, and then send the command. When the add color process is done, you can see the list of the current library from the Serial Monitor.  As long as the Arduino board remains connected to the PC, the library you built will remain valid, and you can use it to measure color.  If your Arduino board is disconnected from the PC or losses power, you need to build your library again.  You can add as many colors in the library as you want, as far as those colors are distinguishable. A good color measurement system can distinguish very close colors. In this project we want to see how far we can go. Our first target is to identify several major colors.

The following screenshot shows a test library we built:

library

The second command “meaSam;” is used to measure a real color sample, and find out from the library the closest match. Before measuring, you should place the color sample on top of the spacer, and then send the command. When the measurement is done, you can see the result from the Serial Monitor.

The following screenshot shows that we can successfully identify all the 7 colors we measured:

measure sample

In this post, we simply searched the color from known library. However, there is more work to be done in order to measure the true color of a sample. So the challenge to our readers is how to measure true color. Some clues may include white calibration and black calibration.

Hope you enjoy this post.  In the future when we have chance, we will work on a project to measure color in a better way using the same TCS3414 sensor, allowing us to identify hundreds and thousands of colors.

All the materials needed for this project can be purchased from eBay.

 

Thanks for reading.  Open Source Photonics Blogs are supported by 612 Photonics.

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: