Using Arduino and a Digital Color Sensor for an optical oxygen probe

I am in the middle of a summer project which entails my trying to use an Arduiono Uno to control a Hamamatsu Digital Color Sensor (Red, Green, Blue). We are trying to build an optical oxygen/pH probe. I have never programmed before so there has been a lot of trial and error and accessing various tutorials. However, I am stuck!

At this point I am working on calibrating the sensor for 0% oxygen levels (maximum emission). We want the Red emission to be at about 3,000 nm, which will be the maximum as it will decrease when oxygen is present as oxygen-quenching occurs.

To get the emission at this 3,000 nm value I am calibrating the gate time of the digital color sensor using the gatetimeCALIBRATION function. This seems to work great; however when I run back through the rtogRATIO function, using this calibrated gate time (gtc), I do not get a new, higher red, green or blue emission. The new (correct) gate time (gtc) is successfully printed as though it is being used by this function, but I seem to get the same red, green and blue emission values as when the gatetimeCALIBRATION function is used (and the gate time delay is 2 ms instead of over 100 ms). *This is supposed to all occur in the set_ZERO function.

Any ideas and help are much appreciated!

Here is my code:

#include <SoftwareSerial.h>



/*Color Sensor Read (print out results)
 * obtained from https://github.com/warpling/Chameleon-Chair/blob/master/Adrunio%20Programs/ColorSensorRead/ColorSensorRead.ino
 * June, 30, 2015
 * Adapted for Hamamatsu Digital Color Sensor S11012-01CR
  */
  
int ColorArray[12][3];  //columns: O-Red, 1-Green, 2-Blue  Rows: 0-LSB..11-MSB
int Red = 0;
int Green = 1;
int Blue = 2;

//Assign digital addresses for communication

int LEDflash = 13;
int Range = 6;
int Gate = 7;
int CK = 8;
int DataIn = 9;
int RedV; //actual values of Red emission after first trial
unsigned long gtc; //gate time calibration-initialize to 2 ms
float slope;
float RG;
float RG0;



// the setup routine runs once when you press reset:
void setup()
{
  Serial.begin(9600);  // initialize serial communication at 9600 bits per second 
  pinMode(DataIn, INPUT);
  pinMode(Range, OUTPUT);
  pinMode(Gate, OUTPUT);
  pinMode(CK, OUTPUT);
  pinMode (LEDflash, OUTPUT);
  
}




void loop (){
  
   calibrate();
 
}


void calibrate()

{ 

Serial.println("When you are ready to begin calibrating your oxygen sensor at 0% oxygen, press any key ");//Prompt User for Input

  while(Serial.available()==0) { // Wait for User to Input Data  
     }

   RG0=set_zero(); //call set_zero function

    delay(1000);
    Serial.available()==0;
    flush_buffer();

  
}



float set_zero() {
 
 gtc = gatetimeCALIBRATION();
 delay (500);
 RG0 = rtogRATIO ();
     {
   Serial.print("RG0:  ");
   Serial.println(RG0);
   Serial.println("");
   Serial.println("");
    }
  return RG0;
  }



unsigned long gatetimeCALIBRATION(){  //Operating sequence 1 - preparation
 

  digitalWrite (Range, HIGH); //set sensitivity: High = high sensitivity
  delay (5); //hold time t4-datasheet
  digitalWrite (CK, LOW);
  digitalWrite (Gate, HIGH); //turn on Hamamatsu chip
  digitalWrite (LEDflash, HIGH);  //turn on illuminating LEDs
  delay (2);   //default time for LED is 2 ms *this is the gate time which is being calibrated
  digitalWrite (LEDflash, LOW);  //turn off illuminating LEDs
  digitalWrite (Gate, LOW); //turn off Hamamatsu chip
  


   //Operating sequence 2 - data transfer
 
{
  for (int m=0; m<3; m++){  //loop through Red, Green, Blue color
    for (int n=0; n<12; n++){  //loop through data bits, LSB first
      // read the input pin:
      digitalWrite(CK, HIGH);  //clock rising edge (data change at rising edge)
      delay(1);     //clock high state

      ColorArray[n][m] = digitalRead(DataIn);  //read bit from sensor
      //    ColorArray[n][m] = bitRead(analogRead(1),0);  //read LSB bit from analog input as random data for testing purposes
      digitalWrite(CK, LOW); //clock falling edge
      delay(1);        //clock low state
    }

    
  }

}

  //collect bits from array to ints for each color
{
  for (int n=0; n<12; n++)

  {
    bitWrite(Red, n, ColorArray[n][0]);
    bitWrite(Green, n, ColorArray[n][1]);
    bitWrite(Blue, n, ColorArray[n][2]);
  } 
}

  //print array data
 {
  for (int n=0; n<12; n++){  //loop through data bits
    for (int m=0; m<3; m++){  //loop through Red, Green, Blue color

        Serial.print(ColorArray[n][m]);
      Serial.print("");
    }
    Serial.println(ColorArray[n][2]);
  }
 }
{
  
  Serial.println("");  //spacer

  //print out the results
  Serial.print("Red: ");
  Serial.println(Red);
  Serial.print("Green: ");
  Serial.println(Green);
  Serial.print("Blue: ");
  Serial.println(Blue);
}
{

  //print color data array in binary
 
  Serial.println("");  //spacer

  Serial.print("Red_BIN: ");
  Serial.println(Red, BIN);
   Serial.print("Green_BIN: ");
  Serial.println(Green, BIN);
  Serial.print("Blue_BIN: ");
  Serial.println(Blue, BIN);

  Serial.println("");  //spacer
  Serial.println("--------------------");  //spacer
  Serial.println("");  //spacer
}
{ //calibrate gate time 
gtc = ((3000.0 * 2.0)/(Red));

  
//print gate time (gtc)
Serial.println("");
Serial.print("Set Gate Time at:  ");
Serial.println(gtc);
}
return gtc;
}




 float rtogRATIO() {//float function to set red to green emission ratio
   digitalWrite (Range, HIGH); //set sensitivity: High = high sensitivity
  delay (5); //hold time t4-datasheet
  digitalWrite (CK, LOW);
   digitalWrite (Gate, HIGH); //turn on Hamamatsu chip
  digitalWrite (LEDflash, HIGH);  //turn on illuminating LEDs
  delay (gtc);   //gtc calculated in gatetimecalibration()
  digitalWrite (LEDflash, LOW);  //turn off illuminating LEDs
  digitalWrite (Gate, LOW); //turn off Hamamatsu chip
 Serial.print ("gtc: ");
  Serial.println (gtc);
  
 {
  for (int n=0; n<12; n++){  //loop through data bits
    for (int m=0; m<3; m++){  //loop through Red, Green, Blue color

        Serial.print(ColorArray[n][m]);
      Serial.print("");
    }
    Serial.println(ColorArray[n][2]);
  }
 }
{
  
  Serial.println("");  //spacer

  //print out the results
  Serial.print("Red: ");
  Serial.println(Red);
  Serial.print("Green: ");
  Serial.println(Green);
  Serial.print("Blue: ");
  Serial.println(Blue);

   



float RtoG = float(Red)/float(Green);
 Serial.print("RedtoGreen emission ratio: ");
  Serial.println(RtoG);
  Serial.print("gtc value:  ");
  Serial.println(gtc);
  Serial.println("");
  Serial.println("");
  return RtoG;
   }
   }

void flush_buffer(void)

{ int num;

  while(1)

  {num = Serial.available();

    if (num == 0)

    { break;}

    else

    {Serial.read();    }

  }
}

the Red emission to be at about 3,000 nm

3000 nm is in the far infrared region, whereas visible red light wavelengths are roughly in the range of 600-800 nm. Is that what you meant? Note that the Hamatsu S11012-01CR sensor response range for red is stated to be 590 to 1000 nm, so it is unlikely to detect 3000 nm radiation.

What is the physical principle behind your proposed method of oxygen content measurement?

Thank you for responding. You're right, the "3000" value should be intensity not nm. I did figure out my problem-I left out the part of my code for setting the rtog ratio.

Regarding my larger project and your second question, I have made a "paint" that contains a platinum porphyrin. The molecule is excited at about 405 nm (wavelength of our LED). It then emits radiation at about 651 nm. With oxygen present, oxygen readily absorbs that energy and therefore reduces the emission intensity picked up by the digital color sensor. We will calibrate the intensity with a reference dye that is not sensitive to the presence of oxygen. Our ultimate goal is to build a very inexpensive dual pH-oxygen sensing probe that various high school and college programs can readily use and even build themselves.

Considering that lots of small molecules quench fluorescence, how specific to oxygen is the quenching of platinum-porphyrin?

Great question! Actually one advantage of using an optical oxygen sensor (like the one we're making), is that the porphyrin will only interact with paramagnetic compounds. It will react with oxygen, which is paramagnetic and Cu and Fe ions, but other molecules are selected out. Optical sensors can be used in more extreme environments (stagnant sulfur pools) where Clark Electrodes would not work. Of course there are some ways that Clark Electrodes out perform optical oxygen sensors as well (quicker response time for one).