Arduino Intro Labs for Tangible Computing
6. Lab 4 - Recognizing Colors




6.1 Objective of the Colour Lab

The purpose of this lab is to introduce basic experimental concepts of gathering sensor data that is involved with hardware. You will obtain data and use it to modify the output of the program. You will also get an introduction (or a refresher) on colour and how we and how machines can percieve colour and light. While we can identity colours easily, machines do not.

We will further practice reading and writing more complicated pieces of code. As before you will be given code but this time it will take some jumping around in the program to fully understand what is happening. We will also introduce new ways to debug code by accessing the values of your variables by printing them to a Serial Monitor.

The outcomes of this lab are:
  1. Use the serial monitor to obtain data from an Arduino program.
  2. Write procedures that take parameters and return a result.
  3. Use pulse wave modulation to control the intensity of a LED.
  4. Get more practice at analog input.
  5. Get more practice at complicated logical sequences of if-then statements, particularly in situations where the decisions are fuzzy and require thresholds.
  6. Use the absolute value function.
  7. Take into account that physical devices need to be calibrated to take into account that both the devices and the physical world they interact with are not necessarily constant or consistent over time.


6.2 Background Information: Colour and Light

Humans perceive color by how their red, green, and blue cones respond to the light coming from the environment. We have a complex visual system that takes into account the light illuminating the surface as well as the light from the surface. The visible light spectrum refers to the way our visual system translates light wavelengths into primary colors. See below for the typical relationship between wavelength and color.

Machines do not perceive color, the best they can do is sense the mix of wavelengths arriving on their sensors and translate it to what a human might name as a color. Color cameras have three sensors that filter the light into red, green, and blue intensities and use this to record color. Cameras also have a white balance which is used to estimate the kind of light that is falling on the scene.

6.3 Materials and Tools

Photoresistor
The Arduino does not have a camera, but it does have a simple light sensor called a photoresistor. It is a device whose resistance varies with the intensity of the light falling on it. As the light gets stronger the resistance decreases. Thus you can measure the amount of light falling on the photoresistor. If you arrange the photoresistor in a voltage divider circuit, then you can measure a voltage that is proportional to the resistance of the photoresistor, and thus is proportional to the intensity of the light.

When the illumination on a surface is of a particular color, then the photoresistor can be used to sense how well that color is reflected or absorbed by the surface. By measuring the amount of red, green, and blue being relfected from the surface we can detect the color of the surface.
Below is the data for a Silonex NORPS 12 photoresistor. The photoresistor we use has a relative response curve that looks roughly like the curve on the left, and a resistance curve that varies with light intensity that looks roughly like the curve on the right.
Compare the response curve to the spectrum below. Note how the photoresistor is more sensitive to reds and greens (roughly in the 525nm to 650nm range), and not very sensitive to blues (about less than 500nm). This will impact our ability to recognize colors with our program.



Here is a more detailed article on this http://www.sentex.ca/~mec1995/tutorial/photocell/photocell.html.



Multicolour LED

We can create almost any color by mixing red, green, and blue light. A RGB LED has three LEDs inside one package. By varying the intensity of each LED you can mix these primary colors and generate a wide range of color hue (the actual mix of colors) and saturation (the amount of white mixed in with the color).

The intensity of a LED is controlled by turning it off and on very rapidly. Your eye cannot see the flashes, but it can detect the proportion of on and off time. The more on the LED is, the brighter it appears to you. This on-off timing relationship is called a duty cycle. Duty cycle describes the proportion of one unit of time during which the device is on. So a 100% duty cycle means always on, 50% means on half the time, and 0% means off. You can operate a digital output in Pulse Width Modulation (PWM) mode by using the analogOutput function. You give the function a digital pin number and a duty cycle value (from 0 to 255) where 0 is 0% (LOW) and 255 is 100% (HIGH).



The Serial Monitor

So far we have not had to get complicated information out of the program running on the Arduino. But now we need to get the actual intensity measurements for the colors we sense from the surfaces. Once you have uploaded the program, select the serial monitor (Tools -> Serial Monitor or look for a manifying glass symbol), and you should get a window that will start printing the measurement results in a form something like this:



In this example, a red sheet of paper is held over the sensor and then removed. 110 is the intensity of the red reflected back when a red piece of paper is held over the multicolour LED. The 66 and the 58 show the intensity of the green and blue being reflected to the photoresistor from the red sheet of paper.

The image also demonstrates that you should not use the first readings when you hold a coloured piece of paper overtop because you may read the values from when you did not have the sheet of paper overtop. It would be best to not read the first set of values when you hold the paper over the photoresistor.

6.4 The Circuit and Code

Go ahead and build the circuit below and load the program. Note how there is a black paper collar around the photoresistor. This is to shield it from stray light so that it just sees what is above it. If you have the black box version of the kit, then you can get a dark environment by putting the Arduino in the box and partially closing the lid.

NOTE: The longest LED lead on the RGB LED is the GROUND. The other paths of the leads must each have a 560Ω (Green Blue Brown) resistor! Here is more important wiring information about the RGB-LED!

For the Photoresistor, it does not matter which way you hook up the wires, just as long as there is a 10kΩ (Brown Black Orange) resistor in the positive path. If you don't have a 10kΩ resistor handy, then you can use the 10kΩ potentiometer: it has a 10kΩ resistance between the end pins. If you want to get clever, you can use the potentiometer to calibrate your sensor by hooking it up as a variable resistor: use one end and one middle pin.
Arduino Mega Arduino Uno Black Paper Collar Added
Click the image for full size!






code/Lab_Color/Lab_Color.ino

    /* Color sensor
     
    A RGB LED has three LEDs inside one package.  By varying 
    the intensity of each LED you can mix these primary
    colors and generate a wide range of different hues and 
    saturation.
     
    The intensity of a LED is controlled by turning it off and
    on at a variable duty cycle using the analogOutput property
    of the digital output pins.
     
    A photoresistor is a device whose resistance varies with 
    the intensity of the light falling on it.  As the light
    gets stronger the resistance decreases.  Thus you can measure
    the amount of light falling on the photoresistor.
     
    If the illumination on a surface is of a particular color,
    then the photoresistor can be used to sense how well that
    color is reflected or absorbed by the surface.  And thus
    we can detect the color.
     
    */
     
    int SensorPin = 0;
    int RedPin = 11;
    int GreenPin = 10;
    int BluePin = 9;
     
    /* The senseColor function sets the LED to a particular
    mix of red, green, and blue, and then senses the intensity
    of the light falling on the photoresistor.  The sampleDelay
    parameter is the number of milliseconds to wait after turning
    on the LED before sensing the intensity.  It takes a while
    for the photoresistor to react, so a delay of 1 second is 
    appropriate.  
     
    So that the value returned by this function increases as
    a function of increasing intensity, we subtract the voltage
    read from the sensor from 1024.
     
    NOTE: this function also displays the values read on the
    serial monitor using the printMeasurement procedure.
     
    */
     
    int senseColor(
      int redOut, int greenOut, int blueOut, int sampleDelay) 
    {
      int intensity;
      
      // illuminate the surface with three colors
      
      analogWrite(RedPin, redOut);
      analogWrite(GreenPin, greenOut);
      analogWrite(BluePin, blueOut);
      
      // wait for the sensor to respond
      delay(sampleDelay);
      
      // return the intensity.  A lower level means a brighter
      // illumination, so rescale
      
      intensity = 1024 - analogRead(SensorPin);
      
      printMeasurement(redOut, greenOut, blueOut, intensity);
      
      return intensity;
    }
     
    /* The printMeasurement procedure uses the serial monitor
    to print the red, green, blue values set for the LED and
    the measured intensity.
    */
     
    void printMeasurement(int red, int green, int blue, 
    int intensity) {
      Serial.print("RGB LED input values: ");
      Serial.print(red, DEC);
      Serial.print(", ");
      Serial.print(green, DEC);
      Serial.print(", ");
      Serial.print(blue, DEC);
      Serial.print(". Intensity: ");
      Serial.println(intensity, DEC);
      }
     
    void setup() {
        pinMode(RedPin, OUTPUT);
        pinMode(GreenPin, OUTPUT);
        pinMode(BluePin, OUTPUT);
        
        Serial.begin(9600);
    }
     
    void loop() {
      int redIn;
      int greenIn;
      int blueIn;
      int blackIn;
     
      int sampleDelay = 1000;
      
      redIn = senseColor(255, 0, 0, sampleDelay);
      greenIn = senseColor(0, 255, 0, sampleDelay);
      blueIn = senseColor(0, 0, 255, sampleDelay);
     
      blackIn = senseColor(0, 0, 0, sampleDelay);
     
      Serial.println(" ");
      delay(2000);
    }


This program currently prints out the values that were passed to the multicoloured LED light and the resulting intensity that the photoresistor picked up from being reflected back from the produced light on the paper. By using this basic output recorded in redIn and the other colour intenties, complete the following tasks below.

6.5 Tasks

  1. Measuring Colour: Now that your circuit is built, try putting different colors of paper above the LED and photoresistor and notice what intensity values are being returned for red, green and blue for each of the colored papers. You will notice that it is quite obvious when red and green paper is tested, but blue is harder. This is because the photoresistor is less sensitive to blue parts of the spectrum.
  2. Color Recognition: Modify the program to actually recognize red, green, and yellow colors, and print out a message describing what color it thinks it is seeing.
  3. Calibration: We don't always conduct the experiment in the exact same environment all the time. Typically in experiments we have some sort of reference value of what kind of values we're suppose to get. For this part you're going to add a pushbutton and when it's pressed, it will allow the program to enter a calibration mode. In this mode each colour piece of paper will be held up to the sensor and their red, green, blue and black levels will be saved as that coloured paper's reference values. Then when trying to recognize the colour, you can compare the readings of the coloured paper to each coloured paper's referenced values and if they are close enough within a certain error, the program will identify it as that colour.

6. Lab 4 - Recognizing Colors
Arduino Intro Labs for Tangible Computing / Version 1.00 2012-09-24