domingo, 10 de agosto de 2014

Arduino: Sensor de Cores RGB

1. Introdução


Esse projeto visa construir um detector de cores usando componentes baratos e fáceis de encontrar e uma placa Arduino. Eu usarei o Mega nesse projeto, porque é o que tenho disponível, mas o Uno já atende perfeitamente.

2. Teoria


Talvez a idéia de detectar cores com um LDR possa parecer estranha a uma primeira vista, mas veremos que é algo possível e relativamente fácil. Ao final, teremos um detector com um bom nível de precisão e a um preço bastante acessível.

2.1 Foto-resistores

Um foto-resistor - também chamado de LDR (Light Dependent Resistor) - é um tipo de resistor que varia sua resistência de acordo com a quantidade de luz que chega a ele. A resistência é inversamente proporcional a quantidade de luz, ou seja, quanto mais luz, menor a resistência elétrica. Os foto-resistores são muito usados em células fotoelétricas para a automatização de postes de iluminação pública e luzes de emergência. Abaixo a imagem real de um LDR e sua representação simbólica.


2.2 O Sistema de Cores RGB

RGB é a abreviatura de Red/Green/Blue. Esse sistema se baseia no fato que todas as cores podem ser formadas a partir dessas três cores básicas e é usado em inúmeros dispositivos atuais como monitores, televisores, projetores multimídia, máquinas fotográficas etc.

Sistema de Cores RGB

2.3 Um pouco de Ótica

Sabemos que o que forma as cores para a nossa percepção é a reflexão de certas ondas luminosas. Um objeto verde reflete as frequências de onda correspondentes ao verde. Os tons de vermelho também tem sua faixa de frequência específica, bem como o azul. A faixa visível varia da frequência 400THz (tons vermelhos) até 790THz (tons violeta).

A idéia básica do tipo de detector que buscamos construir é associar a emissão de luz no sistema RGB, feita pelos LED's e a reflexão da mesma por amostras de cor. Por exemplo, se acionarmos um LED vermelho próximo a uma amostra vermelha, a quantidade de luz refletida será razoavelmente grande. Se a amostra for azul ou verde, a luz refletida será bem menor. Se colocarmos um LDR para "sentir" a luz refletida, poderemos detectar quando a amostra vermelha é testada.

Por fim, se conseguirmos associar três LED's, sendo um vermelho, um verde e um azul, poderemos detectar qualquer das cores básicas do RGB. E se armazenarmos cada valor RGB, poderemos até replicar a exata cor da amostra, bastando reunir os valores detectados de vermelho, verde e azul!

3. Montagem do Detector

Vamos partir agora para a construçao do sistema em uma protoboard ou PCB.

3.1 Componentes Necessários


  • 1 protoboard (ou se preferir soldar, uma PCB)
  • 1 sensor LDR
  • 3 LED's: Um azul, um verde e um vermelho (preferencialmente pode-se usar um único LED RGB)
  • 1 pushbutton
  • 1 buzzer
  • 4 resistores de 350 Ohms
  • 1 resistor de 10KOhms

3.2 Esquema de Montagem

Usei o Fritzing para desenhar o modelo abaixo. Trata-se de um excelente software livre. Pode ser baixado gratuitamente em http://fritzing.org.


Recomendamos fortemente que seja montada uma pequena câmara escura que proteja o detector (o conjunto dos três LED's + LDR) das emissões de luz do ambiente externo. Se não for usada essa câmara, haverá muita interferência de luz externa. Abaixo o sistema real já montado. Note a câmara escura com os três LED's e o LDR dentro.



4. Codificação

O código a seguir não foi totalmente criado por mim. Encontrei diversas referências e trechos na Internet e montei o meu fazendo as adaptações que achei pertinentes e que melhor serviam a mim. Na sessão de referências há links para os sites de onde me baseei.

Agora abra a IDE do Arduino e digite isso.


/* RGB SENSOR */

const int LDR = 0; // ldr sensor on analog pin 0
const int redLed = 2;
const int greenLed = 3;
const int blueLed = 4;
int ledArray[] = {redLed, greenLed, blueLed};

const int buzzer = 8;
int buzzTone=200;

const int button = 7;
int buttonState = 0;

float colorArray[] = {0,0,0};
float whiteArray[] = {0,0,0};
float blackArray[] = {0,0,0};

//int avgRead;

int ldrvalue = 0;

// Values for detected colors
int redval = 0;
int greenval = 0;
int blueval = 0;

boolean balanced = false;

void setup () {
  Serial.begin (9600);
  pinMode (redLed, OUTPUT);
  pinMode (greenLed, OUTPUT);
  pinMode (blueLed, OUTPUT);
  pinMode (button, INPUT);
  pinMode (buzzer, OUTPUT);
  Serial.println ("Press button to start");
  beepBuzzer (1);
}

void loop () {
  waitButton();
  //buttonState = digitalRead (button);
  //if (buttonState == HIGH) {
    if (!balanced) {
      blinkLeds (3);
      Serial.println ("Performing Balance...");
      rgbBalance();
    }
    else {
      rgbSense();
      printColors();
      beepColor();
  }
}

void rgbBalance() {
  // White Balance: operador deve colocar amostra branca sobre o sensor.
  Serial.println ("White balance [press button to start] ...");
  waitButton();
  delay(500);
  // Le os valores red/green/blue para a amostra branca.
  Serial.print ("White Array: [");
  for (int i=0;i<3;i++) {
    digitalWrite (ledArray[i], HIGH);
    delay(100);
    whiteArray[i] = getAvgRead(5);
    digitalWrite (ledArray[i], LOW);
    Serial.print (whiteArray[i]);
    delay(100);
  }
  Serial.println ("] OK");
  
  // Black Balance: operador deve colocar amostra preta sobre o sensor.
  Serial.println ("Black balance [press button to start] ...");
  waitButton();
  delay(500);  // Espera oito segundoa para usuario posicionar a amostra negra.
  //  Le os valores red/green/blue para a amostra negra.
  Serial.print ("Black Array: [");
  for (int i=0;i<3;i++) {
    digitalWrite (ledArray[i], HIGH);
    delay(100);
    blackArray[i] = getAvgRead(5);
    digitalWrite (ledArray[i], LOW);
    Serial.print (blackArray[i]);
    delay(100);
  }
  Serial.println ("] OK");
  balanced = true;
  delay(2000);
}

void rgbSense () {
  float greyDiff=0;
  for (int i=0; i<3;i++) {
    digitalWrite (ledArray[i], HIGH);
    delay(100);
    colorArray[i] = getAvgRead(5);
    greyDiff = whiteArray[i] - blackArray[i];
    colorArray[i] = (colorArray[i] - blackArray[i]) / greyDiff*255;
    digitalWrite (ledArray[i], LOW);
    delay(100);
  }
}

int getAvgRead (int times) {
  int value=0;
  int summ=0;
  int avg=0;
  for (int i=0;i<times;i++) {
    value = analogRead(LDR);
    summ = value + summ;
    delay(10);
  }
  avg = summ/times;
  return avg;
}

void blinkLeds (int times)
{
  for (int i=0;i<times;i++) {
    digitalWrite (redLed, HIGH);
    digitalWrite (greenLed, HIGH);
    digitalWrite (blueLed, HIGH);
    delay(500);
    digitalWrite (redLed, LOW);
    digitalWrite (greenLed, LOW);
    digitalWrite (blueLed, LOW);
    delay(500);
  }
}

void beepBuzzer (int times)
{
  for (int i=0;i<times;i++) {
    tone (buzzer, 2000);
    delay(100);
    noTone (buzzer);
    delay(100);
  }
}

void printColors () {
  Serial.print ("R: ");
  Serial.println(int(colorArray[0]));
  Serial.print("G = ");
  Serial.println(int(colorArray[1]));
  Serial.print("B = ");
  Serial.println(int(colorArray[2]));
  Serial.println();
}

void beepColor ( )
{
  // Red: 1 beep; Green: 2 beeps; Blue: 3 beeps
  int beeps=0;
  int color;
    
  if (colorArray[0]>colorArray[1])
  {
    color = colorArray[0];
    beeps=1;
  }
  else {
    color = colorArray[1];
    beeps=2;
  }
  
  if (color<colorArray[2]) {
    beeps=3;
  }
  beepBuzzer(beeps);
}


void waitButton ()
{
  while (true) {
    buttonState = digitalRead (button);
    if (buttonState == HIGH) {
      beepBuzzer(1);
      break;
    }
  }
}


5. Operação

Para que o sistema funcione adequadamente é necessário realizar o balanço inicial de luz para amostras brancas e pretas. Será necessário usar a interface serial da IDE do Arduino para se familiarizar com o funcionamento. Através da interface serial, o sistema dará as instruções básicas de operação, que consistem no que está descrito abaixo.

Após ligar, o sistema solicitará que o operador coloque a amostra branca sobre o detector (o conjunto dos LED's + o LDR) e pressione o botao. Após isso ele deverá colocar a amostra preta sobre o detector e pressionar novamente o boato. Nesse momento o balanceamento foi feito e o sistema está pronto para uso.

Coloque qualquer amostra de cor sobre o detector e pressione o botao. O sistema lerá a a cor predominante (vermelho, verde ou azul) da amostra e emitirá bips da seguinte forma:


  • 1 bip: vermelho
  • 2 bips: verde
  • 3 bips: azul


Nos testes que fiz, o sistema se mostrou bem eficiente. Muitas melhorias podem ainda ser feitas. Pode-se trocar o conjunto de três LED's por  um único LED RGB. Outra melhoria é colocar ainda outro LED RGB e tentar "imitar" a cor lida.

Caso você faça melhorias nesse sistema, peço que mantenha vivo o espírito do software/hardware livre e compartilhe o que foi feito com o público em geral.

6. Referências

http://www.instructables.com/id/Using-an-RGB-LED-to-Detect-Colours/?ALLSTEPS
http://www.georgegardner.info/arduino/photoresistor-color-sensing-with-the-arduino.html