May 312013
 

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

 

DSC_3052

Picture 3 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
}