Timo Kellmann

Jun 012013
 

Topic: This post is about measuring the reaction time of a (digital) camera. More precisely: The time difference between the trigger by cable release and the moment when the photo is taken.

What is this for? Precise timing for the water drop photography. Implementation of the time delay using different camera settings (without flash, with manual flash, with TTL-flash) in the code for taking the photo after the water drop passes through a light barrier.

 

dsc_3025

Picture 1 of 5

 

The idea:

An object falls through the light barrier (like the water drop later on). This is measured by the voltage increase over the light sensitive resistor. The Arduino then immediately triggers the camera and a photo is made of actual position of the object. From the distance between light barrier and position of the object on the photo (and the speed of the object when passing the light barrier) the reaction time of the camera can be calculated, based on standard mechanics:

s = 1/2 g t^2   <=>  t = ( 2 s / g ) ^ 1/2

with s: distance from the height from which the object is dropped to a) the light barrier and b) the position on the photo.

The difference in the times for a) and b) is the reaction time of the camera.

 

I found that the results I got were astonishing reliable (see the standard deviation) and ended up with the following values:

D700:

  • Without flash (camera set to M and ISO was preset): 40,3ms  (1.1ms standard deviation)
  • With flash (preset to 1/8 strength) (camera set to M and ISO was preset): 46.1ms (1.1 ms standard deviation)
  • With flash (TTL), camera was set to ISO auto and “P” program: 85,8ms (3.1ms standard deviation)

D200:

  • Without flash, camera set to M, ISO was preset: 57.8ms (I just made 2 photos with exactly the same result, so I don’t give any standard deviation here)
  • With flash (preset to 1/8 strength) (camera set to M and ISO was preset): 222,5ms (7,5 ms standard deviation)

The D200 with flash is significantly slower and cannot be used for my setup.

 

Required material:

Light source (see picture DSC_3027):

  • 650nm Laser Diode Module: 5.99EUR at ebay. I bought mine at ether.deal. This diode uses 5V input. (I used an Arduino board to provide the voltage, since I had two of them).
  • Arduino UNO (just because I was lazy. You can easily build up your own 5V power supply for the diode).
  • 9V Battery block + power supply for the Arduino (from Conrad)
  • a breadboard (from Conrad)
  • 2 cables (from Conrad)
  • several filters (colored plastic)  in order to decrease the light intensity by the laser diode.

Central steering unit (see picture DSC_3025):

  • Arduino UNO
  • Light sensitive resistor (I used VT 83 N2 (THT) from Watterott). It had a resistance of 1.5kOhm in darkness and about 0 Ohm when the laser diode was directed at it.
  • A 1.5kOhm resistance (as the light sensitive resistor in darkness).
  • An optocoupling device  (PC817). I had one in an Arduino Starterset.
  • A cheap cable release for my camera. I bought mine at ebay from China for about 5EUR. As you are going to cut it, it should be cheap…
  • 6 cables
  • a breadboard
  • USB cable

Other equipment (see picture “gauging”):

  • lightning stands, clamps etc. to hold the laser diode, the photo resistor, a multivitamin tube and the filters to decrease the light intensity of the laser diode.
  • a plastic tube from multivitamin pills (in order to release the object from a definite height and hit the light barrier below)
  • glass beads (or any other small, but visible object to be dropped)
  • laptop (as the interface to the Arduino program)
  • Folding rule (Zollstock) (I attached mine to the ceiling)

Photographic equipment:

  • Cameras & flashes you want to measure
  • White background
  • Tripod

 

 

 Arduino sketch for the control unit (for the connections see  in the Water drop photography section):

 

/*

Arduino program to measure the voltage over a photo sensitive resistor and trigger a digital camera.

Intention: Target is to measure the reaction time of the camera (i.e. time difference between trigger signal and moment, when the photo is taken).

Some physics of the light barrier:
 Resistance in darkness: 1.5kOhm
 Resistance with laser diode pointing at it: ca 0 Ohm
 => use another 1.5kOhm resistance in serial.
 Use filters to descrease the light intensity until
 the voltage over the photo sensitive resistance is about 2V.
*/

const int pinCamera = 11; // Pin for triggering the camera
float maxVmeasured;       // maximum voltage measured during gauging time
int   cntiLoops;          // counter for inactive time < 0s / gauging time 0s-3s / measuring time > 3s
float triggerDeltaV;      // offset to trigger the camera in V (over maximum voltage observed within gauging period)

// the setup routine runs once when you press reset:
void setup() {
   // initialize serial communication at 9600 bits per second:
   Serial.begin(9600);
   pinMode(pinCamera, OUTPUT);
   cntiLoops = -3;      // first 3 seconds: inactive, then 3 seconds gaugingm after that: measurements
   triggerDeltaV = 0.2; // trigger level in V about maximum voltage measured within gauging time
}

// the loop routine runs over and over again forever:
void loop() {
   int   currMillis = millis();
   int   duration   = 1000;
   int   lastMillis = millis();
   int   cnti = 0;
   float maxV = 0;
   float minV = 10;
   float sumV = 0;
   int   cntV = 0;

   cntiLoops++;    // < 0: inactive / 0-3: gauging / >3 measurements

   while (currMillis < lastMillis+duration) { // 1 seconds loop step

      // any input from the computer to steer the behaviour?
      while (Serial.available() > 0) {
         char h = Serial.read();
         if (h=='p') triggerDeltaV = triggerDeltaV+0.05; // increase trigger level by 0.2V
         if (h=='m') triggerDeltaV = triggerDeltaV-0.05; // decrease trigger level by 0.2V
         if (h=='x') maxVmeasured = 20.0; // switch off
         if (h=='.') { cntiLoops = 0; maxVmeasured = 0;} // gauge yourself
      }

      /* Read the voltage over the photo sensistive resistor */
      int sensorValue = analogRead(A0);

      // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
      float voltage = sensorValue * (5.0 / 1023.0);

      if ((voltage>maxVmeasured+triggerDeltaV) and (cntiLoops>3)) {
         digitalWrite(pinCamera, HIGH); // trigger the camera
         delay(200); // this delay has no influence on the reaction time
         digitalWrite(pinCamera, LOW); // reset the camera trigger to 0

         // print out the value you read:
         Serial.print("TRIGGERED!");
         Serial.print(", Trigger=");
         Serial.print(maxVmeasured);
         Serial.println(".");

         cntiLoops = -3; // <0: inactive / 0-3: gauging / >3: measurement
         maxVmeasured = 0; // reset maximum voltage level for gauging
      }

      if (voltage>maxV) maxV = voltage;
      if (voltage<minV) minV = voltage;

      /* first 3 seconds: gauge yourself by finding the maximum voltage over the restistor */
      if ((cntiLoops<=3) and (cntiLoops>=0)) {
         if (maxVmeasured < maxV) maxVmeasured = maxV;
      }

      sumV = sumV+voltage; // OLD
      cntV = cntV + 1; // OLD

      currMillis = millis();
   }

   // print out the value you read:
   if (cntiLoops<0) {
      Serial.print("INACTIVE... ");
   }

   if ((cntiLoops>=0) and (cntiLoops<3)) {
      Serial.print("GAUGING... ");
   }

   Serial.print(", max=");
   Serial.print(maxV);
   Serial.print(", Trigger=");
   Serial.print(maxVmeasured+triggerDeltaV);

   Serial.println(".");
   Serial.println("");
 }

 

The (dummy) Arduino sketch for the laser diode:

/*   The Arduino is just needed as a 5V power source.    */
int led = 5; // The 650nm Laser Diode Laserdiode Module is connected to Pin 5.

// the setup routine runs once when you press reset:
void setup() { 
   // initialize the digital pin as an output.
   pinMode(led, OUTPUT);
   digitalWrite(led, HIGH);   
   // turn the LED on (HIGH is the voltage level)
}

// the loop routine runs over and over again forever:
void loop() {
   delay(1000);               // wait for a second
}
May 312013
 

My photos of water drops (and the “making of” the photos)…

 

DSC_3133

Picture 1 of 60

Arduino triggered.

 

I was fascinated about the photos of water drops falling into a water surface and creating these crown like structures I saw in the commercials and thought: I want to be able to do these kind of photos.

My first attempt was to program my camera to take a photo every 5 seconds, while I was dropping water into a glass bowl – manually by pressing a wet towel. I just hoped that I was lucky one time that the camera released in the very millisecond the crown was there, when the drop hit the surface. In fact I was able to catch a couple of these crowns (see photos _DSC0322 (2) and the following ones), but the number of photos going to the waste was incredible. I had to change the method.

Searching the web I found light barriers made for my camera for several hundreds of euros. I thought I could do this cheaper myself.

Well… Until I came up with the solution I shown below I tried a couple of different approaches. All of them ended in just spending money for equipment, books and a slight increase in my learning curve. In the end – it would have been cheaper to buy the ready made light barriers. But: It would definitely not have been so much fun!

The basic idea is to measure the water drop by a light barrier. The light is emitted by a laser diode and measured by the voltage over a light sensitive resistance by the Arduino. After a certain time delay it triggers the camera.

 

The following is a short description of the required material, the Arduino code(s) and some hints from my experience.

Required material:

Light source (see picture DSC_3027):

  • 650nm Laser Diode Module: 5.99EUR at ebay. I bought mine at ether.deal. This diode uses 5V input. (I used an Arduino board to provide the voltage, since I had two of them).
  • Arduino UNO (just because I was lazy. You can easily build up your own 5V power supply for the diode).
  • 9V Battery block + power supply for the Arduino (from Conrad)
  • a breadboard (from Conrad)
  • 2 cables (from Conrad)
  • several filters (colored plastic)  in order to decrease the light intensity by the laser diode.

Central steering unit (see picture DSC_3025):

  • Arduino UNO
  • Light sensitive resistor (I used VT 83 N2 (THT) from Watterott). It had a resistance of 1.5kOhm in darkness and about 0 Ohm when the laser diode was directed at it.
  • A 1.5kOhm resistance (as the light sensitive resistor in darkness).
  • An optocoupling device  (PC817). I had one in an Arduino Starterset.
  • A cheap cable release for my camera. I bought mine at ebay from China for about 5EUR. As you are going to cut it, it should be cheap…
  • 6 cables
  • 2 breadboards (can be done with one)
  • USB cable

Other equipment (see picture “Foto”):

  • laboratory stands, clamps etc. to hold the laser diode, the photo resistor, the cone for the water and the filters to decrease the light intensity of the laser diode. This is kind of important. My first trial (see picture DSC_0002 was very unstable and needed lots of time for regauging of the system).
  • a plastic cone from the kitchen (for the water drops to come out)
  • a shot (for supplying the water into the cone)
  • crepe paper (for coloring the water – or use food dye)
  • needle and threat (in order to measure where the water drop falls out of the cone, through the light barrier and hits the water surface)
  • aquarium
  • laptop (as the interface to the Arduino program)

Photographic equipment (see picture “Foto”):

  • Camera: Nikon D-700
  • Nikon Sb-800 flash (separated from the camera)
  • Studio flashes: Elinchrome d-lite 4  (I used it only occasionally)
  • White background
  • Tripod

 

Hints:

  • Try to set up the system as stable as possible. When somebody was moving in my living room, the laser diode was constantly swinging and defocused (and therewith triggered the camera). This led to some extra self-gauging loops in the Arduino code below.
  • Set the camera to manual mode and switch off TTL measurement in your camera. This just increases the required time until the camera releases.
  • Think about switching on the mirror pre-release. This increases the reaction speed and avoids vibrations of the camera.
  • Create drops by dropping with a shot at the same point in the cone, do not drop too quickly. This increases the reproducibility of the result.

 

The Arduino sketch(es):

 

The Arduino sketch for the controller:

/*
Reads the voltage over a photo sensitive resistor and triggers the camera after a 
certain time interval, when certain trigger level is reached 

Some physics of the light barrier: 
Resistance in darkness: 1.5kOhm 
Resistance with laser diode pointing at it: ca 0 Ohm

=> use another 1.5kOhm resistance in serial.

Use filters to decrease the light intensity of the laser beam until the voltage 
over the photo sensitive resistance is about 2V.
*/

const int     pinCamera = 11;   // pin for triggering the camera
float         maxVmeasured;     // maximum voltage measured during gauging time
int           cntiLoops;        // counter for gauging time of measuring time

float         distSourceToSurfaceCM; // distance between water emitting source and water surface in cm
float         distSourceToLaserCM;   // distance between water emitting source and light barrier in cm
const float   gEarth = 9.81;         // earth acceleration in m/s2
float         timeCameraReact;       // time the system (Arduino + camera) needs to react on a trigger event
float         triggerDeltaV;         // voltage offset above maximum voltage measuren during gauging time in order to trigger the camera

float timeToLaser;       // time the drop needs between water emitting source and light barrier
float timeToSurface;     // time the drop needs between water emitting source and water surface
float timeAfterTrigger;  // time between light barrier and water surface
float timeOffset;        // adjustable time offset
float timeDelay;         // resulting full time delay

// the setup routine runs once when you press reset:
void setup() {

   // initialize serial communication at 9600 bits per second:
   Serial.begin(9600);
   pinMode(pinCamera, OUTPUT);

   cntiLoops = -3;                // first 3 seconds: inactive, 0-3: gauging, >3 measuring

   distSourceToSurfaceCM = 27.5; // FILL IN HERE THE MEASURED DISTANCE BETWEEN WATER SOURCE AND SURFACE IN CM
   distSourceToLaserCM   = 1.0;  // FILL IN HERE THE MEASURED DISTANCE BETWEEN WATER SOURCE AND LIGHT BARRIER IN CM

   /* calculate timing */
   timeToLaser      = sqrt(2.0 * distSourceToLaserCM   / 100.0 / gEarth) ;
   timeToSurface    = sqrt(2.0 * distSourceToSurfaceCM / 100.0 / gEarth) ;
   timeAfterTrigger = timeToSurface-timeToLaser;

   /* MEASURE THE REACTION TIME FOR THE SYSTEM ARDUINO AND CAMERA AND ENTER THE CORRECT VALUE HERE      
      THIS CAN BE DONE BY MEASURING THE REQUIRED TIME DELAY AFTER THE TRIGGER EVENT IN ORDER     
      TO CATCH THE WATER DROP JUST ABOVE THE SURFACE */
   timeCameraReact  = 0.195-0.036;

   /* INITIAL TIME OFFSET: AT WHAT STAGE OF THE DEVELOPMENT OF THE WATER DROP HITTING THE SURFACE SHALL THE CAMERA BE RELEASED? */
   timeOffset = 0.0;

   /* SAFETY OFFSET OVER MAXIMUM VOLTAGE MEASURED DURING GAUGING TIME IN ORDER TO TRIGGER THE CAMERA */
   triggerDeltaV = 0.2;

   /* resulting time delay */
   timeDelay = timeAfterTrigger+timeOffset-timeCameraReact;
}

// the loop routine runs over and over again forever:
void loop() {
   int   currMillis = millis();
   int   duration = 1000; /* cycle in 1s units */
   int   lastMillis = millis();
   int   cnti = 0;
   float maxV = 0;
   float minV = 10;   
   float sumV = 0;   
   int   cntV = 0;

   /* resulting time delay in seconds */
   timeDelay = timeAfterTrigger+timeOffset-timeCameraReact;

   /* delays canot be shorter than 0 */
   if (timeDelay < 0) timeDelay = 0;

   /* time delay in milliseconds */
   float timeDelayMS = timeDelay*1000;

   cntiLoops++;

   while (currMillis<lastMillis+duration) {

      // any input from the computer to steer the behaviour?
      while (Serial.available() > 0) {
         char h = Serial.read();

         if (h=='p') triggerDeltaV = triggerDeltaV+0.05;    // increase trigger level by 0.2V
         if (h=='m') triggerDeltaV = triggerDeltaV-0.05;    // decrease trigger level by 0.2

         if (h=='+') timeOffset = timeOffset+0.002;         // increase time delay by 0.01s
         if (h=='-') timeOffset = timeOffset-0.002;         // decrease time delay by 0.01s

         if (h=='x') maxVmeasured = 20.0;                   // safety switch off - if something happened...
         if (h=='.') { cntiLoops = 0; maxVmeasured = 0;}    // re-gauge yourself
      }

      /* read the input from the light sensitive resistor */
      int sensorValue = analogRead(A0);

      // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
      float voltage = sensorValue * (5.0 / 1023.0);

      /* (cntiLoops>3): first 3 seconds used for gauging. */
      /* (voltage>maxVmeasured+triggerDeltaV): water drop was decreasing the light falling upon the light sensitive resistance */
      if ((voltage>maxVmeasured+triggerDeltaV) and (cntiLoops>3))  {
         delay(timeDelayMS); // TIME DELAY BETWEEN WATER DROP BEING MEASURED AND RELEASING THE CAMERA
         digitalWrite(pinCamera, HIGH);   
         delay(100);         // has no influence on the reaction time
         digitalWrite(pinCamera, LOW);

         // print out the value you read:
         Serial.print("TRIGGERED!");
         Serial.print(", Trigger=");
         Serial.print(maxVmeasured);
         Serial.println(".");

         /* be inactive for 3 seconds (as several drops could fall out at once and therewith bias the regauging process */
         /* then regauge for 3 seconds (as something might have happened to the system and the laser is not any longer pointing at the resistor */
         cntiLoops = -3; 
         maxVmeasured = 0;
      }

      if (voltage>maxV)  maxV = voltage;
      if (voltage<minV)  minV = voltage;

      /* first 3 seconds: gauge yourself by finding the maximum voltage over the restistor */
      if ((cntiLoops<=3) and (cntiLoops>=0)) {
         if (maxVmeasured < maxV) maxVmeasured = maxV;
      }

      sumV = sumV+voltage;   // OLD
      cntV = cntV + 1;       // OLD
      currMillis = millis(); 
   } // end of 1s loop

   // print out the value you read:
   if (cntiLoops<0) {     
      Serial.print("INACTIVE... ");   
   }

   if ((cntiLoops>=0) and (cntiLoops<3)) {
      Serial.print("GAUGING... ");   
   }

      Serial.print("max=");   
      Serial.print(maxV);   // output maximum voltage within last second
      Serial.print(", Trigger=");   
      Serial.print(maxVmeasured+triggerDeltaV);      // trigger level

      Serial.print(", Time Delay (ms)=");
      Serial.print(timeDelayMS);
      Serial.println(".");
      Serial.println("");
}// end of void loop

The (dummy) Arduino sketch for the laser diode:

/*   Turns on the Laserdiode.    */
int led = 5; // The 650nm Laser Diode Laserdiode Module is connected to Pin 5.

// the setup routine runs once when you press reset:
void setup() {
   // initialize the digital pin as an output.
   pinMode(led, OUTPUT);
   digitalWrite(led, HIGH);
   // turn the LED on (HIGH is the voltage level)
}

// the loop routine runs over and over again forever:
void loop() {
   delay(1000);               // wait for a second
}