| |

MARCA DIURNA EN SEÑALES

El problema que se intenta tratar es el de definir una metodología para decidir cuando una señal está para pintar o no, hablando de su marca diurna.

La idea es implementar un sistema que sea capaz de leer los colores y para ello se pensó en realizarlo con la ayuda de una placa arduino y un sensor de color, en particular el TCS3200 que es que mejores resultados ha ofrecido hasta el momento.

Por un lado para el desarrollo del arduino nos hemos apoyado del siguiente video.

Se ha completado información con las recomendaciones de la IALA E200-1 y E200-3, ya que técnicamente el proceso es el siguiente:

Con la ayuda del sensor conectado a un arduino, lo que se obtiene son tres valores R, G y B de cuanto rojo, cuanto verde y cuanto azul hay respectivamente. Sin embargo para llevarlo a la gráfica que nos encontramos en el GEPAN hay que traducir dichos valores a valores X Y Z según CIE 1931. Y no solo eso, sino además llevarlo a una forma normalizada.

Se han consultado los siguientes enlaces para ampliar información más detallada sobre el proceso de conversión de RGB a XYZ:

La conclusión y haciendolo todo breve, finalmente es una multiplicación algebraica de matrices. La matriz RGB 3×1 se premultiplica por una matriz 3×3 para obtener una matriz XYZ de 3×1.

Una vez obtenidos los valores XYZ, se normalizan de la siguiente manera:

Y ya con los valores de x e y se puede entrar en la siguiente gráfica para ver si el punto obtenido cae en la zona válida o no.


Adjunto el codigo empleado en arduino.

/*
  Color Sensor Calibration
  color-sensor-calib.ino
  Calibrate RGB Color Sensor output Pulse Widths
  Uses values obtained for RGB Sensor Demo sketch 
 
  DroneBot Workshop 2020
  https://dronebotworkshop.com
*/

//RGB values to XYZ using the Wide RGB D65 conversion formula
/* float a11 = 0.664511;float a12 = 0.154324;float a13 = 0.162028;
float a21 = 0.283881;float a22 = 0.668433;float a23 = 0.047685;
float a31 = 0.000088;float a32 = 0.072310;float a33 = 0.986039;  */

//RGB values to XYZ using the  adobe D65 conversion formula
//* 0.5767309  0.1855540  0.1881852
// 0.2973769  0.6273491  0.0752741
// 0.0270343  0.0706872  0.9911085 */

//RGB values to XYZ using the  sRGB D65 conversion formula
/* float a11 = 0.4124564;float a12 = 0.3575761;float a13 = 0.1804375;
float a21 = 0.2126729;float a22 = 0.7151522;float a23 = 0.0721750;
float a31 = 0.0193339;float a32 = 0.1191920;float a33 = 0.9503041; */

//TO COPY HERE THE ONES TO USE
float a11 = 0.649926;
float a12 = 0.103455;
float a13 = 0.197109;
float a21 = 0.234327;
float a22 = 0.743075;
float a23 = 0.022598;
float a31 = 0.0000000;
float a32 = 0.053077;
float a33 = 1.035763;


float R, G, B, C;


// Define color sensor pins

#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8

#include <TCS3200.h>
TCS3200 tcs3200(S0, S1, S2, S3, sensorOut);
// Define color labels for identification
String color_indices[] = { "Red", "Green", "Blue" };
// Define RGB color values corresponding to the color labels
RGBColor color_values[] = {
  { 255, 0, 0 },  // Red
  { 0, 255, 0 },  // Green
  { 0, 0, 255 },  // Blue
};


int redMin = 22;
int redMax = 310;
int greenMin = 17;
int greenMax = 333;
int blueMin = 18;
int blueMax = 263;

int redValue;
int greenValue;
int blueValue;
int clearValue;

// Variables for Color Pulse Width Measurements

int redPW = 0;
int greenPW = 0;
int bluePW = 0;
int clearPW = 0;

void setup() {

  // Set S0 - S3 as outputs
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);

  // Set Sensor output as input
  pinMode(sensorOut, INPUT);

  // Set Pulse Width scaling to 20%
  digitalWrite(S0, HIGH);
  digitalWrite(S1, LOW);

  // Setup Serial Monitor
  Serial.begin(9600);
}

void loop() {
  String color = "";
  // Read Red Pulse Width
  redPW = getRedPW();
  redValue = map(redPW, redMin, redMax, 255, 0);
  R = constrain(redValue, 0, 255);
  //R=redPW;

  // Delay to stabilize sensor
  delay(200);

  // Read Green Pulse Width
  greenPW = getGreenPW();
  greenValue = map(greenPW, greenMin, greenMax, 255, 0);
  G = constrain(greenValue, 0, 255);
  //G=greenPW;

  // Delay to stabilize sensor
  delay(200);

  // Read Blue Pulse Width
  bluePW = getBluePW();
  blueValue = map(bluePW, blueMin, blueMax, 255, 0);
  B = constrain(blueValue, 0, 255);
  //B=bluePW;

  //clear
  clearPW = getClearPW();
  //clearValue = map(clearPW, blueMin, blueMax, 255, 0);
   //C = constrain(clearValue, 0, 255);

  // Delay to stabilize sensor
  delay(200);

  //TRANSFORMACION A CIE
  if ((R > 210) & (G > 210) & (B > 210)) {
    color = "White";
  }
  if ((R < 40) & (G < 40) & (B < 40)) {
    color = "Black";
  }
  if ((180 <= R) & (R <= 255) & (170 <= G) & (G <= 255) & (0 <= B) & (B <= 160)) {
    color = "Yellow";
  }
  if ((G - B > 20) & (G - R > 30)) {
    color = "Green";
  }
  if ((B - G > 20) & (B - R > 40)) {
    color = "Blue";
  }
  if ((R - G > 40) & (R - B > 40)) {
    color = "Red";
  }






  Serial.print("R= ");
  Serial.print(R);
  Serial.print("  G= ");
  Serial.print(G);
  Serial.print("  B= ");
  Serial.print(B);
  Serial.print("  C= ");
  Serial.print(clearPW);
  Serial.print("    => ");


  R = getGammaCorrectedValue(R / 255);
  G = getGammaCorrectedValue(G / 255);
  B = getGammaCorrectedValue(B / 255);

  float X = (R * a11 + G * a12 + B * a13);
  float Y = (R * a21 + G * a22 + B * a23);
  float Z = (R * a31 + G * a32 + B * a33);
  //Calculate the xy values from the XYZ values
  float x = (X / (X + Y + Z));
  float y = (Y / (X + Y + Z));



  if ((x >= 0.60) & (x <= 0.75) & (y >= 0.29) & (y <= 0.34)) color = "ROJO RAL VALIDO";
  if ((x >= 0.55) & (x <= 0.61) & (y >= 0.39) & (y <= 0.45)) color = "AMARILLO RAL VALIDO";
  if ((x >= 0.013) & (x <= 0.30) & (y >= 0.38) & (y <= 0.76)) color = "VERDE RAL VALIDO";
  if ((x >= 0.29) & (x <= 0.48) & (y >= 0.27) & (y <= 0.44)) color = "BLANCO RAL VALIDO";
  if (clearPW>80 & ((1-x-y)<0.05) &(x >= 0.250) & (x <= 0.35) ) color = "NEGRO RAL VALIDO";


  /*   if ((color == "Green") & (y >= 0.493 - 0.524 * x) & (y >= 0.243 + 0.670 * x))
    color += " VALIDO";

  //if ((color == "Red") & (y <= 0.910 - 0.051 * x) & (y >= 0.314 + 0.047 * x) & (y <= 0.345 - 0.051 * x))
  if ((color == "Red") & (x > 0.65) & (y > 0.29))
    color += " VALIDO"; */

  //FIN TRANSFORMACION A CIE




  // Print output to Serial Monitor

  Serial.print(color);
  Serial.print("         X: ");
  Serial.print(X);
  Serial.print(" Y: ");
  Serial.print(Y);
  Serial.print(" Z: ");
  Serial.print(Z);
  Serial.print("  -   x:");
  Serial.print(x);
  Serial.print(" y:");
  Serial.print(y);
  Serial.print(" z:");
  Serial.print(1 - x - y);
  Serial.println();
}


// Function to read Red Pulse Widths
int getRedPW() {

  // Set sensor to read Red only
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;
}

// Function to read Green Pulse Widths
int getGreenPW() {

  // Set sensor to read Green only
  digitalWrite(S2, HIGH);
  digitalWrite(S3, HIGH);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;
}

// Function to read Blue Pulse Widths
int getBluePW() {

  // Set sensor to read Blue only
  digitalWrite(S2, LOW);
  digitalWrite(S3, HIGH);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;
}

// Function to read CLEAR Pulse Widths
int getClearPW() {

  // Set sensor to read Blue only
  digitalWrite(S2, HIGH);
  digitalWrite(S3, LOW);
  // Define integer to represent Pulse Width
  int PW;
  // Read the output Pulse Width
  PW = pulseIn(sensorOut, LOW);
  // Return the value
  return PW;
}

float getGammaCorrectedValue(float value) {
  if (value > 0.04045) {
    return pow((value + 0.055) / (1.0 + 0.055), 2.4);
  } else
    return (value / 12.92);
}

Proximamente incluiré fotos, resultados así como información más detallada.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *