Let's Make Robots!

$2 Color Detection Sensor

AttachmentSize
ColourSensor.pde2.78 KB

SENSOR

My original inspiration was "
http://www.societyofrobots.com/sensors_color.shtml". I made this sensor one evening long ago and have been meaning to share it as a good project for beginners. Basically wire it up like in the schematic and make sure all the LEDs point in such a way that any reflecting light will hit the photo resistor (I didn't do this well enough and had to compensate in the code for it). Run the code and tweak the calibration numbers to get it to work right.

The sensor works decently well for how simple it is. It can work with a variety of materials (in the video I use cloth, plastic, paper ect.). However the range is limited about 1 inch and if the objected is too angled it may not work at all. For best results keep the sensor normal to your sample surface.

It works because an object will reflect the most color that is of the same color as an object. This is why that object appears that color to us. This means a red object will reflect more of the red light than of the green, blue or yellow LED and cause the greatest change in the photo resistor readings. We can use this to determine color.

Future improvements on the projects can include using PWM to determine the exact shade of an object. Also modulation may be possible but some other sensor other than a photo resistor must be used (photo resistors don't have the response time for it). Perhpas a TSL230 or similar.

Check that your LEDs work ;)

And here is what it looks like after battling polymorph for an hour.....

MATERIALS
1 - Photoresistor
4 - 560 ohm resistors
1 - 10k resistor
4 - LEDs (Red, Blue, Yellow, Green)

SCHEMATIC

Here is the schematic of the sensor I made.



CODE

The code bellow is the one that I was running when I made the video. It continually turns the LEDs on to sample an object and then flashes one LED once it has reached a decision. It also prints all the numbers to a serial monitor so that you can see what the sensor sees and adjust it (If your physical one is as faulty as mine was....). The .pde file is included bellow for all you Arduino lovers. Remember a small cool down time is required for the photo resistor between samples.

**Uploaded Code with the faster runtime now.

//Pins
int photoResistor = 0;

int b = 2;
int r = 3;
int g = 4;
int y = 5;

//Calibration
// AKA Terrible software solution to a hardware problem....
double bAdj = 1.0;
double rAdj = 1.02;
double gAdj = 1.0;
double yAdj = 1.17;
double ambientAdj = 1.0;

void setup()
{
  pinMode(g, OUTPUT);
  pinMode(y, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(r, OUTPUT);
  pinMode(photoResistor, OUTPUT);
  Serial.begin(9600);
}

void loop()
{  
    allOff();
    delay(100);
    asses(100,100);
}

void allOff()
{
    digitalWrite(g, LOW);
    digitalWrite(y, LOW);
    digitalWrite(r, LOW);
    digitalWrite(b, LOW);
}

void allOn()
{
    digitalWrite(g, HIGH);
    digitalWrite(y, HIGH);
    digitalWrite(r, HIGH);
    digitalWrite(b, HIGH);
}

void pulse(int colour)
{
   for(int i=0;i<3;i++)
   {
      digitalWrite(colour, HIGH);
      delay(100);
      digitalWrite(colour, LOW);
      delay(100);
   }
}
 

void asses(int colldownTime, int saturationTime)
{
 
    delay(500);
    double ambient = analogRead(photoResistor);
    Serial.print("Ambient: ");
    Serial.println(ambient*ambientAdj);
    
    digitalWrite(g, HIGH);
    delay(saturationTime);
    double green = analogRead(photoResistor);
    Serial.print("Green: ");
    Serial.println(green*gAdj);
    digitalWrite(g, LOW);
    delay(colldownTime);
    
    digitalWrite(r, HIGH);
    delay(saturationTime);
    double red = analogRead(photoResistor);
    Serial.print("Red: ");
    Serial.println(red*rAdj);
    digitalWrite(r, LOW);
    delay(colldownTime);
    
    digitalWrite(b, HIGH);
    delay(saturationTime);
    double blue = analogRead(photoResistor);
    Serial.print("Blue: ");
    Serial.println(blue*bAdj);
    digitalWrite(b, LOW);
    delay(colldownTime);
    
    digitalWrite(y, HIGH);
    delay(saturationTime);
    double yellow = analogRead(photoResistor);
    Serial.print("Yellow: ");
    Serial.println(yellow*yAdj);
    digitalWrite(y, LOW);
    delay(colldownTime);
    
    double rawData[] = {(green*gAdj), (red*rAdj), (blue*bAdj), (yellow*yAdj)};
    double maximum = ambient*ambientAdj;
    int decision;
    
    for (int i=0; i<4; i++)  
    {
       if (maximum<rawData[i])
      {
          maximum = rawData[i];
          decision = i+1;
      }
    }
         
    Serial.println("");
    
    if(decision == 0)
    {
       Serial.println("No object detected.");
       allOn();
       delay(1000);
       allOff();
    }
    else if(decision == 1)
    {
       Serial.println("I think its green.");
       pulse(g);
    }
    else if(decision == 2)
    {
       Serial.println("Looks red to me.");
       pulse(r);
    }
    else if(decision == 3)
    {
       Serial.println("Blue for sure!");
       pulse(b);
    }
    else if(decision == 4)
    {
       Serial.println("Booring old yellow.");
       pulse(y);
    }
    Serial.println("");

}


/* All my work is distributed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License or any subsiquent version of that license. Details here "http://creativecommons.org/licenses/by-nc-sa/3.0/". You don't need to give me any credit but any derivative works must remain free and open source to the community. All code, diagrams and details are provided on an "as is" basis with no expressed or implied waranties for suitability to any purpose - don't blame me if something breaks. */

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Gonzik's picture

Sorry for the late response. I have never worked with a Picaxe so you will have to write the code yourself. As for the schematic it would be the same. Both systems use 5V logic so just hook up the photo resistor to an analogue pin using a voltage divider and hook up the LED's to digital pins.

Geir Andersen's picture

You might also have a look at this http://www.rev-ed.co.uk/docs/AXE045.pdf
I have done some work with the TCS230 sensor and it’s a pain to work with without a lens assembly.
http://letsmakerobots.com/node/18124
The lens also have a IR filter.

Antonb's picture

you could use three photoresistors each fitted with a light filter according to the corresponding LEDs 

Gonzik's picture

Yeah I thought of that too but then you need to space them out so that they don't affect each other and you might end up not sampling the same surface. I suppose its possible to have them angled differentley (One normal to surface and the other two 45 degrees off of that but I really think the light to frequency IC TSL230 is the best way to approach such a problem they are cheap from sparkfun). O and by the way Anton I'm a fan of your MTR and the servo encoders you made - hope to be at that level one day ;)

Something like this maybe with a photoresistor next to each LED?


1 - Red LED, photoresistor for Green LED
2 - Blue LED, photoresistor for Blue LED
3 - Green LED, photoresistor for Red LED
1     2     3
--------------------
\       l      /   
  \     l     /
    \   l   /
  sample

Antonb's picture

I guess a possible arrangement could be having a single central powerful white LED for illumination, and circumferentialy around it three photoresistors/photodiodes each fitted with a different colour filter. Bear in mind that the spectral responsivity (output responce to different wavelengths) for the photoresistors/photodiodes is not linear and you would have to compensate in software with separate gains on each filtered output.

check this out:  http://www.farnell.com/datasheets/48714.pdf 

Awesome little colour sensor from Texas Instruments, but I think they dont make it anymore :(

I really appreciate your comments for my work - Thanks ;)

hardmouse's picture

Do you think it's possible to try one of those tri-color RGB LED and have multicolor looping in the code to get more precise scale of color tone?

Gonzik's picture

I think it is possible but it's hard to do it practically with a photoresistor. When I tested it objects reflect all colors even those that are not in their own spectrum. So a yellow object will reflect Red and Green as it should, but the Blue LED will also cause a change in the photoresistor. So when you mix those colors in proportion to how much of a change they caused in the photoresistor you won't get yellow back. To try and filter out this "noise" is very hard and seems to be dependant on the surface of the object. The problem is that even in this simple setup the difference between how much of a change a red LED and a blue LED reflected off red was very miniscule. The arduino gives back a raw value between 0 and 1024 and the difference between colors was offten only maybe 15. I fear that with PWMing errors could accumulate to the point of making the sensor usless. But in theory it is possible !!!

         
LordGG's picture

Great idea :)

XicoMBD's picture

I like your project very much. I've tried to do something like this a big while ago but I wasn't very successful...

But, can't you make it a bit faster?

Gonzik's picture

Ya you can, faster video uploaded. You can't make it faster than 1 second though b/c the ptotoresistor needs to cool down before and after a reading of .1 seconds (response time on them things is slow). For anything faster you will need somekind of electromagnetic frequency sensors to detect the color.