The Second Night of Waterdrop Photography

Today, I spent time upgrading my software including the capability to change the sensitivity and time delays from the serial communication between the computer and Arduino board. The code is shown in the previous post. I also switched to my 105mm macro lens to get closer to the action. The electronics, optics, and software seem to work great. I think the next bit of effort will be improving the mechanical setup including the mount and having a more consistent dripper.

This is my favorite image from the night. This occurred by accident. A second drop hit the upward ejection from the first drop causing this splayed pattern. It was a lucky shot.


Here’s a slideshow of the other photos I got tonight.

Code for my Waterdrop Light Trigger

Here’s the code for my waterdrop light trigger. I included an ability to change the operating values using the serial communication between the Arduino and my computer. I can get and set various parameters from the Arduino board.

LED Trigger for Waterdrop Photography
Garret Bonnema
September 19, 2010

Thanks to for many
of the basics and ideas behind my waterdrop trigger.

 // Setting up the pinouts
 const int irLEDPin = 12;
 const int flashTriggerPin = 10;
 const int triggerIndicatorPin = 13;
 const int lightMonitorPin = 1;

 // Setting up some variables
 int lightValue = 0;
 int baseValue = 0;
 boolean setBaseValue = true;
 int threshold = 5;

 // The delay (in msec) between the drop signal and the flash trigger
 // This is based on the separation between the detection area and the
 // impact surface (e.g. the bowl of water)
 int theDelay = 500;

void setup() {       

  // Begin the serial communication back to the computer
  // 9600 baud rate

  // Initialize the digital pins as outputs:
  pinMode(irLEDPin, OUTPUT);
  pinMode(flashTriggerPin, OUTPUT);
  pinMode(triggerIndicatorPin, OUTPUT); 

  // Set the flash trigger to low
  digitalWrite(flashTriggerPin, LOW);

  // Turn on the infrared LED (set irLEDPin to high)
  digitalWrite(irLEDPin, HIGH);   // set the LED on

  // Set the base value based on the current value at
  // the analog input.


void resetBaseline()
  baseValue = analogRead(lightMonitorPin);

void commandCenter()
    // Check if the user has sent a command to the device
  if (Serial.available()>0)

    // Set up an array for the input
    char theInput[20];

    // Read the input from the serial buffer (include a 10msec delay
    // to wait if new bytes are still arriving)
    int i = 0;
    while (Serial.available()>0)
      theInput[i] =;

    // Terminate the next element in the array with the null string.
    theInput[i] ='\0';


    // Print the user command followed by the result

    // Split theInput string using a space delimiter
    char* command = strtok(theInput," ");

    // Check the first word (command) from theInput to see if it matches
    // a list of acceptable commands.

    // RESET - takes a measurement from the analog channel and uses this
    // as the baseline value. Sends the base value back to the computer.
    if (strcmp(command,"reset")==0)

    // GETDETECT - gets current reading from the infrared detector and sends
    // the value back to the computer.
    if (strcmp(command, "getdetect")==0)

    // GETTHRESH - gets the current threshold. The threshold is difference
    // between the base value and the level that causes the flash to trigger.
    if (strcmp(command, "getthresh")==0)

    // SETTHRESH - set the current threshold. The threshold is the difference
    // between the base value and the level that causes the flash to trigger.
    if (strcmp(command, "setthresh")==0)
      command = strtok(NULL, " ");
      threshold = atoi(command);

    // GETDELAY - gets the current delay between the light trigger and the
    // camera flash (in msec).
    if (strcmp(command, "getdelay")==0)

    // SETDELAY = sets the current delay between the light trigger and the
    // camera flash (in msec).
    if (strcmp(command, "setdelay")==0)
      command = strtok(NULL, " ");
      theDelay = atoi(command);

void loop() {

  // Check serial communication buffer for commands from the user and performs
  // the requested operations.

  // Read from the infrared detector
  lightValue = analogRead(1);

  // Look for a water droplet (a larger value means the light level at the
  // detector is smaller).
  if (lightValue > baseValue + threshold)
    // illuminate LED for visual indication
    digitalWrite(triggerIndicatorPin, HIGH);

    // send flash trigger
    digitalWrite(flashTriggerPin, HIGH);

    // Turn off trigger signal
    digitalWrite(flashTriggerPin, LOW);

    // Turn off LED indicator
    digitalWrite(triggerIndicatorPin, LOW);


My First Attempt at Waterdrop Photography

I spend all day building my light trigger for waterdrop photography. I made about four or five trips to various electronics stores and Target during the day. I ended up buying a digital oscilloscope and multimeter.  I have always wanted one but could never afford it. As I haven’t made any large purchases recently (like camera lenses), I figured I could justify the purchase of the $700 oscilloscope.

I’ll write a post on how I built the light trigger later. It’s the basic idea I wrote earlier this week. Anyhow, I wanted to share my first night of pictures. I think I can improve on these too. I feel like I didn’t have a really good focus for a lot of these. Anyhow, here’s a few photos. The color was added in post-processing in Photoshop.

For a preview of the technical stuff, here’s a picture of my assembly from earlier in the day..