Apr 062014
 

Topic: This project is about making photos of a sunset with a Nikon D200. Starting with full daylight photos will be taken until astronomical sunset (sun is at -18 degrees below horizon).

This requires constant adaptation of the cameras settings (ISO / aperture and time) due to the diminishing light.

I will record the luminosity with the Arduino, so I can set the average brightness of the single images afterwards accordingly.

For this I bought several luminosity sensors from Watterott:

  • Sparkfun Weather Shield
  • TSL2561 light sensor (digital) (0.1 to 40,000 Lux)
  • TSL45315 light sensor Breakout (3 Lux bis 220k Lux)
  • CoreLight (0.015 lux to 64,000 lux)

I will try which one is the best, measure some sunsets and gauge the camera against it.

In order to better understand what I am doing, I am developing some small tool, which tells me some astronomical data – as the position of the sun by time and date and some star positions.

For this I will look for a better tool than Excel and VBA… :)

 

First I downloaded a data base of star positions:

And an OpenGL-Sample containing the pattern of the earth:

  • http://www.ziyoo.com/

A website containing C-code for positions of planets, the moon and the sun (based on the book “Astronomie mit dem Personal Computer” von Oliver Montenbruck und Thomas Pfleger):

Using the TSL2561 light sensor:

Using the TSL45315 light sensor:

Using the CoreLight light sensor:

  • http://soldercore.com/products/sensecore/corelight/
  • Connect as follows:

corelight

Picture 1 of 1

 Posted by at 8:43 pm
Nov 242013
 

Topic: How to scan color transparencies.

 

I bought an old Heidelberg Linoscan 1450 scanner together with VueScan and would like to scan my 4×5″ negatives/slides. There are several problems to solve:

1. The scanner has some bad pixels, so I get stripes in the scanned image (solved by downloading and installing the newest version and clicking on “calibrate”).

2. How to get rid of newton rings?

 

I started with a dry scan and asked myself what side should be up: The base or the emulsion?

The first thing I noted was that the film bends. According to my observation it bends the edges upwards, when the emulsion side is up. Since I don’t have a film holder, I put the emulsion side down. This enables me to fix the film with tesa film on the scanner, where the tesa touches only the base side. This apparently solved already the Newton ring problem – at least for some photos. There were still some showing up newton rings.

So I tried a wet scan: With a normal spray bottle I sprayed some water on the glass surface of the scanner and placed the slide (emulsion side up = not touching the water) on the scanner. I tried to remove all air bubbles under the film, but was quite unsuccessful as I saw on the scan. Next try will be wo put the emulsion side down and use a roller (from linol-cutting) to squeeze out the bubbles. But for that I should buy a clean one first… :)

My overall impression comparing the dry scan with the wet scan was, that there is only a very slight improvement of the sharpness in the wet scan. If the water is applied to the upper side (base), it had some effect on the color of the image: the scan comes out darker in comparison with the dry scan.

After washing the image, it dried normally having no visible effect on the color nor leaving some marks behind.

 

 

 

 Posted by at 3:48 pm
Nov 162013
 

Topic: This post is about the application of the MF522-AN RFID reader and the Arduino for cards-magic (current stage: Proof-of-concept).

 

Effect: A randomly picked spectator shuffles a deck of cards, picks out a card of his choice and puts it into an envelope, which he places on a table. The magician is able to tell which card he has chosen, just by concentration – never having touched the card not the deck.

 

Setup:

Getting the MF522-AN RFID reader working was pretty straightforward based on a script by Dr.Leong (http://www.b2cqshop.com/), which was sent to me after I purchased the hardware at ebay.

 

Pin on RFID reader Meaning Connect with Arduino Colour of the cable on the   photo
8 SS Pin 10 Yellow
7 SCK Pin 13 Orange
6 MOSI Pin 11 Green
5 MISO Pin 12 Blue
4 Nothing
3 M-GND Grnd Black
2 RST Pin 5 White
1 M+3.3V 3.3V Red

 

Wiring the MF522-AN RFID reader with the Arduino

Picture 1 of 2

 

In order to place a RFID chip into every card, I had to find rather thin ones (not built in plastic), which I found at ebay:

“NFC tag sticker label RFID IC 13.56MHz ISO14443A Mifare1k S50 Compatible” sold by zillashop: http://www.ebay.de/usr/zillashop

 

I then placed the RFID chip between two cards, glued them together (see photo 2). The RFID reader was able to read out the chip through my working desk: I placed the Arduino with the RFID under the desk and placed the envelope above it (on the desk).

 

I modified the script by Dr. Leong such that it would print the cards name (in case the RFID tag was known, otherwise it would use the standard output of Dr. Leong (as the Chinese characters will not show up here, I deleted the comments).

/* Arduino-program: I will only quote the modified "loop" statement here */
void loop() {
   uchar i,tmp;
   uchar status;
   uchar str[MAX_LEN];
   uchar RC_size;
   uchar blockAddr;
   String mynum = "";
   status = MFRC522_Request(PICC_REQIDL, str);
   if (status == MI_OK) {
       /*
      Serial.println("Card detected");
      Serial.print(str[0],BIN);
      Serial.print(" , ");
      Serial.print(str[1],BIN);
      Serial.println(" ");
      */
   }
   status = MFRC522_Anticoll(str);
   memcpy(serNum, str, 5);
   if (status == MI_OK){
      char* cardName=new char[200];
      cardName = "";
      if (serNum[0]==75) cardName = "Ace of diamonds";
      if (serNum[0]==219) cardName = "Ace of hearts";
      if (serNum[0]==43) cardName = "Ace of spades";
      if (serNum[0]==59) cardName = "Ace of clubs";
      if (serNum[0]==235) cardName = "Queen of hearts";
      if (cardName=="") {
          Serial.println("Unknown card! The card's number is : ");
          Serial.print(serNum[0]);
          Serial.print(" , ");
          Serial.print(serNum[1],BIN);
          Serial.print(" , ");
          Serial.print(serNum[2],BIN);
          Serial.print(" , ");
          Serial.print(serNum[3],BIN);
          Serial.print(" , ");
          Serial.print(serNum[4],BIN);
          Serial.println(" ");
      } else {
          Serial.println(cardName);
      } 
      delay(1000);
   )   
   //Serial.println(" ");
   MFRC522_Halt();
}

 

In order to do something with the output I wrote a small processing script to run on my PC, which had the Arduino attached to it. This is definitely why its currently only a “proof of concept”. In the final stage I will have to find a different method to transfer the information to the magician :)…

I used a modified code from D. Shiffman (http://shiffman.net/2007/11/13/e-mail-processing/). Unfortunately it took me quite some time to get it running, as some class definitions were missing and I needed to download the javax.mail first. I found the solution here: http://hamletbon.wordpress.com/2012/10/08/multithreaded-email-class-in-processing/

 

import processing.serial.*; 
import javax.mail.*; 
import javax.mail.internet.*; 
import java.util.Properties;

final int LINE_FEED = 10;
Serial arduinoPort;

import javax.mail.Authenticator; 
import javax.mail.PasswordAuthentication;

public class Auth extends Authenticator {
  public Auth() {     super();   }
  public PasswordAuthentication getPasswordAuthentication() {
     String username, password;
     username = "<INSERT YOUR EMAIL USERNAME HERE>";
     password = "<INSERT YOUR EMAIL PASSWORD HERE>";
     //System.out.println("authenticating. . ");
     return new PasswordAuthentication(username, password);
   }
}

void setup() {
   println(Serial.list());
   String arduinoPortName = Serial.list()[2];
   arduinoPort = new Serial(this, arduinoPortName, 9600);
   arduinoPort.bufferUntil(LINE_FEED); 
}

void draw() {
   if (arduinoPort.available() > 0) {
     final String arduinoOutput = arduinoPort.readStringUntil(LINE_FEED);
     println(arduinoOutput);

             // Create a session
       String host="smtp.gmail.com";
       Properties props=new Properties();
             // SMTP Session
       props.put("mail.transport.protocol", "smtp");
       props.put("mail.smtp.host", host);
       props.put("mail.smtp.port", "25");
       props.put("mail.smtp.auth", "true");
             // We need TTLS, which gmail requires
       props.put("mail.smtp.starttls.enable","true");

             // Create a session
       Session session = Session.getDefaultInstance(props, new Auth());
       try       {
             // Make a new message
         MimeMessage message = new MimeMessage(session);
             // Who is this message from
         message.setFrom(new InternetAddress("<INSERT YOUR EMAIL USERNAME HERE>", "<INSERT YOUR EMAIL USERNAME HERE>"));
             // Who is this message to (we could do fancier things like make a list or add CC's)
         message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("<INSERT TARGET EMAIL ADRESS HERE>", false));
             // Subject and body
         message.setSubject(arduinoOutput);
         message.setText(arduinoOutput);
             // We can do more here, set the date, the headers, etc.
         Transport.send(message);
         println("Mail sent!");
       }
       catch(Exception e)       {
         e.printStackTrace();
       }
  }
}

 

Putting it all together it resulted in an e-mail to my iPad with subject (and body) being the name of the card, which was in the envelope put on my desk under which I put the RFID unit (wired to the Arduino, which was on USB cable attached to my desktop PC)…  :)

 

 

 Posted by at 1:17 pm
Oct 052013
 

Topic: In order to display the measured voltage values graphically, the data need to be transferred to the computer.

 

Sample for measuring the light intensity

Picture 1 of 1

 

The Arduino sketch:

In order to transmit the data as quickly as possible (for having a good time resolution of the measurements),

the Arduino sketch has to be reduced to a minimum. All the evaluations are done on the main computer.

/* Measures and transmits the Voltage to the external computer. */
// the setup routine runs once when you press reset: 
void setup() {     
    // initialize serial communication at maximum 115200 bits per second:     
    Serial.begin(115200); 
}

// the loop routine runs over and over again forever: 
void loop() {       
    /* Read the voltage over the photo sensistive resistor */     
    int sensorValue = analogRead(A0);     
    Serial.print("I: ");     
    Serial.println(sensorValue);  
}

 The Processing sketch on the main computer.

This is a modified sketch of a sketch written by Maik Schmidt.

import processing.serial.*;

final int WIDTH = 1000; 
final int HEIGHT = 600; 
final int xCenter = WIDTH / 2; 
final int yCenter = HEIGHT / 2; 
final int LINE_FEED = 10;

Serial arduinoPort; 
int time = 0; 
float voltage = 0;

void setup() {   
   size(WIDTH, HEIGHT);
   println(Serial.list());
   String arduinoPortName = Serial.list()[2]; // modify this according to your system environment
   println("Arduino is at : "+arduinoPortName);
   arduinoPort = new Serial(this, arduinoPortName, 115200);
   arduinoPort.bufferUntil(LINE_FEED);
   init_screen(); 
}

void serialEvent(Serial port) {
   voltage = getSensorData();
   if (voltage != 0) {
     println("Voltage: " + voltage);
   } 
}

float getSensorData() {
   if (arduinoPort.available() > 0) {
     final String arduinoOutput = arduinoPort.readStringUntil(LINE_FEED);
     println(arduinoOutput);
     int result = parseArduinoOutput(arduinoOutput);
     return result * (5.0 / 1023.0);
   } else {      
      return 0;   
   } 
}

int parseArduinoOutput(final String arduinoOutput) {
   int number = 0;
   if (arduinoOutput != null) {
     final int[] data = int(split(trim(arduinoOutput), ' '));
     //print("Data length "); println(data.length);
     if (data.length == 2) {
       number = data[1]; // Integer.parseInt(data[1]);
       //println(number);
     }
   } else {
      number = 0;
   }
   return number; 
}

void init_screen() {
   background(255);
   stroke(0);
   strokeWeight(1);
   line(1,HEIGHT,WIDTH,HEIGHT);
   line(1,1,1,HEIGHT);
   strokeWeight(10); 
}

void draw() {
    int yValue;   
    yValue=round((1-voltage/5.0)*HEIGHT);
    point(time, yValue);
    if (++time == WIDTH) {
       init_screen(); time = 0;
    }
}
 Posted by at 5:15 pm
Sep 102013
 

Topic: How to install a browser that allows practically anonymous browsing in the web.

Search for “TOR Browser” and read the manual.

(The computer magazine “chip” has a free TOR browser package).

 Posted by at 10:50 pm
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
}