jueves, 19 de marzo de 2015

Detectar colores con Color Sensor (SKU:SEN0101)


Este proyecto esta basado en un sensor de dfrobot  tcs3200, el cual mediante 4 entradas digitales seleccionamos unos filtros. El sensor  produce una salida de onda cuadrada cuya frecuencia es proporcional a la intensidad del filtro elegido.

Mas información: http://www.dfrobot.com/wiki/index.php?title=TCS3200_Color_Sensor_%28SKU:SEN0101%29

Para esto es importante, la iluminación. Por defecto el sensor tiene leds blancos, pero hay que recordar que la luz blanca tiene color rojo, verde y azul, por lo que contamina los datos, además el tipo de material también afectará al resultado.  

Importante la luz no debe incidir directamente en el sensor, también contamina el resultado.

Además en VB al intentar reconstruir el color, siempre habrá un error. En la mayoría de los casos el color será muy diferente al color reconstruido y será mejor guiarse por un canal (por ejemplo el rojo) que por la suma de los tres.





El programa que hecho servir es el mismo programa que hay en la web del fabricante, pero le hecho unos pequeños cambios para poder comunicarme con VB.


Código Arduino modificado:

 int s0=3,s1=4,s2=5,s3=6;
int out=2;
int flag=0;
byte counter=0;
byte countR=0,countG=0,countB=0;
void setup()
 {
 Serial.begin(9600);
 pinMode(s0,OUTPUT);
 pinMode(s1,OUTPUT);
 pinMode(s2,OUTPUT);
 pinMode(s3,OUTPUT);
 
 }
void TCS()
 {
 flag=0; 
 digitalWrite(s1,HIGH);
 digitalWrite(s0,HIGH);
 digitalWrite(s2,LOW);
 digitalWrite(s3,LOW);
 attachInterrupt(0, ISR_INTO, CHANGE);
 timer0_init();
 
 }
void ISR_INTO()
 {
 counter++;
 }
 void timer0_init(void)
{
  TCCR2A=0x00;
  TCCR2B=0x07;   //the clock frequency source 1024 points
  TCNT2= 100;    //10 ms overflow again
  TIMSK2 = 0x01; //allow interrupt
 }
 
 
 int i=0;
 ISR(TIMER2_OVF_vect)//the timer 2, 10ms interrupt overflow again. Internal overflow interrupt executive function
{
    TCNT2=100;
    flag++;
 if(flag==1)
  {
    countR=counter;
    Serial.print("R");
    if (counter < 100) { Serial.print (0); }
    if (counter < 10) {Serial.print (0); }
    Serial.print(countR,DEC);
    digitalWrite(s2,HIGH);
    digitalWrite(s3,HIGH);
  }
  else if(flag==2)
   {
    countG=counter;
    Serial.print("G");
    if (counter < 100) { Serial.print (0); }
    if (counter < 10) {Serial.print (0); }
    Serial.print(countG,DEC);
    digitalWrite(s2,LOW);
    digitalWrite(s3,HIGH);
   }
   else if(flag==3)
    {
    countB=counter;
    
    Serial.print("B");
    if (counter < 100) { Serial.print (0); }
    if (counter < 10) {Serial.print (0); }
    Serial.print(countB,DEC);
    digitalWrite(s2,LOW);
    digitalWrite(s3,LOW);
    
    }
    else if(flag==4)
     {
     Serial.print("\n");
     flag=0;
     }
       counter=0;
     
}
void loop()
 {
  TCS();
while(1);
 }

 En el visual basic leo los datos recibidos, un ejemplo:

R122G131B107
R121G130B106
R121G130B106
R120G131B107
R121G130B106
R121G                  ----Trama incompleta

Mediante las letras R, G y B identifico los valores de cada canal. Para evitar que los valores cambien para cada trama hago servir un timer de 500ms donde cada vez muestro la media de las tramas de cada canal. Para eso hago servir 3 arrays, en este caso la array del canal R tendría 6 valores, mientras que el array del canal G y B 5 valores.

Rojo=(122+121+121+120+121+121)/6= 121
Verde=(131+130+130+131+130)/5= 130
Azul=(107+106+106+107+106)/5= 106



Código del  Timer1 de visual basic:

  Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick


        Dim cuenta As Integer
        Dim textin As String
        Dim max_muestras As Integer = 100
        Dim roig(max_muestras) As Integer 'Red
        Dim cnt_r As Integer = 0
        Dim verd(max_muestras) As Integer 'Green
        Dim cnt_g As Integer = 0
        Dim blau(max_muestras) As Integer 'blue
        Dim cnt_b As Integer = 0

        textin = SerialPort1.ReadExisting() 'guardo todos los datos del puerto
        cuenta = textin.Length
        TextBox1.Text = TextBox1.Text + textin

        'ejemplo puedo recibir:
        ' R005G200B255
        ' R006G199B255
        ' R006G201
        'Tengo 3 datos del canal rojo, 3 del verde y dos del azul

        For i As Integer = 0 To (cuenta - 1) 'leo los datos
            If (textin(i) = "R") And ((i + 3) <= (cuenta - 1)) Then
                roig(cnt_r) = CInt(textin(i + 1) + textin(i + 2) + textin(i + 3))
                'guardo en un array los datos del canal rojo
                cnt_r = cnt_r + 1 'cuento los datos que tengo en el canal rojo
            End If
            If (textin(i) = "B") And ((i + 3) <= (cuenta - 1)) Then
                verd(cnt_g) = CInt(textin(i + 1) + textin(i + 2) + textin(i + 3))
                cnt_g = cnt_g + 1
            End If
            If (textin(i) = "G") And ((i + 3) <= (cuenta - 1)) Then
                blau(cnt_b) = CInt(textin(i + 1) + textin(i + 2) + textin(i + 3))
                cnt_b = cnt_b + 1
            End If

        Next

        If (cnt_r > 0) Then
            For i As Integer = 0 To cnt_r - 1
                Red = Red + roig(i) ' 5+5+6 =16
            Next
            Red = Red / cnt_r 'Hago una media  16/3= 5
            If Red >= 0 And Red <= 255 Then 'Compruebo qu el resultado es coherente
                lRed.Text = Red
                ProgressBarRed.Value = Red '5
            End If
            cnt_r = 0
        End If
        If (cnt_g > 0) Then
            For i As Integer = 0 To cnt_g - 1
                Green = Green + verd(i)
            Next
            Green = Green / cnt_g 'Hago una media 
            If Green >= 0 And Green <= 255 Then
                lGreen.Text = Green
                ProgressBarGreen.Value = Green
            End If
            cnt_g = 0
        End If
        If (cnt_b > 0) Then
            For i As Integer = 0 To cnt_b - 1
                Blue = Blue + blau(i)
            Next
            Blue = Blue / cnt_b 'Hago una media 
            If Blue >= 0 And Blue <= 255 Then
                lBlue.Text = Blue
                ProgressBarBlue.Value = Blue
            End If
            cnt_b = 0
        End If

        If Red >= 0 And Red <= 255 And Green >= 0 And Green <= 255 And Blue >= 0 And Blue <= 255 Then
            colormuestra.BackColor = Color.FromArgb(Red, Green, Blue)
        End If

    End Sub

Descargar proyecto: http://www.4shared.com/zip/ucIrUOIm/Control_LedRGB.html