Keyword:

Jumping spider

Oct 14, 2020

Another jumping spider I found in front of my daughter’s condo. Taken with my iPhone 11pro and highly cropped B8DD0ABD-5F52-4254-B7AE-555B7FB8C4E3.jpeg


keywords: photography


Water droplet photography

Aug 28, 2020

Bored during the 2020 pandemic, I tried my hand at water droplet photography. This is where you freeze action using a flash trying to catch two water droplets colliding. I captured some pretty good images before my solenoid valve got gummed up. I built the controller myself using an Arduino UNO and some transistors. This allowed me to precisely control the timing of the water droplets, the camera and the flash. The timing took a lot of experimentation which I adjusted through an interface to my laptop. A rough schematic of my setup is below.
schematic.jpg
Here is my Arduino sketch code:
// control sketch for camera trigger, solenoid valve and flash
int cameraPin = 3; // arduino pin that controls camera
int dropPin = 5; // arduino pin that controls solenoid
int flashPin = 9;  // arduino pin that controls flash
int val = 0;
int exposureCnt = 0;
int maxExposureCnt = 1;
unsigned long dropTime1;
unsigned long dropTime2;

boolean bArmCamera   = true; // true if camera shutter should be opened before drop execution

int times[6] = {0, 20, 150, 0, 0, 0}; // trigger time, drop time, next drop time, next 3 are us additions to these times

boolean bExecuteDrop = false; // After test drop loop until serial parameters are loaded then set to true

void setup() {
  Serial.begin(9600);
  pinMode(dropPin, OUTPUT);
  pinMode(flashPin, OUTPUT);
  pinMode(cameraPin, OUTPUT);
  digitalWrite(cameraPin, LOW);
  //flag = false;
  
  // Test droplet
  executeDrop(20, 0);
  executeDrop(20, 150);
  Serial.println("Setup complete");
}

void loop() {
  
  if (bExecuteDrop) {
    // load new times from serial input
    int timeTrigger = times[0];
    int timeDrop    = times[1];
    int timeNext    = times[2];
    
     if (bArmCamera) {
      triggerCamera(); // arm the camera (assuming a shutter open time for 2 seconds)
      delay(500);
    }
    
    executeDrop(timeDrop, 0);  // trigger the first drop
    dropTime1 = millis();
    executeDrop(timeDrop, timeNext); // trigger the second drop
    dropTime2 = millis();
    int tbd = dropTime2 - dropTime1;
    Serial.print("time between drops: ");
    Serial.println(tbd);

    triggerFlash(timeTrigger - timeDrop*2 - timeNext); // timeTrigger should be measured from first drop point
    
    exposureCnt++; // increment the exposure cnt
    Serial.print("Exposure count: ");
    Serial.println(exposureCnt);
    Serial.println(" ----- ");
    // Check to see if more photos should be taken or not
    if (exposureCnt >= maxExposureCnt) {
      bExecuteDrop = false;
      exposureCnt = 0;
    } else {
      delay(3000);
    }
  }

  
   // Check for an input
  if (Serial.available() > 0) {
    char buff[32];
    int returned = Serial.readBytesUntil('\n', buff, 32);
    buff[31] = 0;
    char *values = strtok(buff, ","); // read first token from the input string
    // Check data and convert to int
    if (returned == 0) {
      Serial.println("no valid data sent");
    } else {
      Serial.println("data recieved");
      int i = 0;
      while (values != NULL) {
        int val = atoi(values);
        Serial.println(val);
        times[i] = val;
        if (i == 3) {
          maxExposureCnt = val;
        }
        i++;
        values = strtok(NULL, ",");
      }
      // check if a valid number of inputs was found
      if (i == 4) {
        bExecuteDrop = true;
      } else {
        Serial.println("invalid number of inputs");
      }
    }
  } // if serial
  
} // loop

// Helpers

void delayExact(int timeMs, int timeUs) {
  if (timeMs > 0) {
    delay(timeMs);
  }
  if (timeUs > 0) {
    delayMicroseconds(timeUs);
  }
}

void executeDrop(int timeOn, int timeDelay) {
  if (timeDelay > 0) {
    delayExact(timeDelay, times[5]);
  }
  digitalWrite(dropPin, HIGH); // turn on the MOSFET to drive the solenoid
  delayExact(timeOn, times[4]); // this determines the size of the drop
  digitalWrite(dropPin, LOW);
}

// Function to trigger flashes
void triggerFlash(int triggerTime, int triggerTimeus) {
  if (triggerTime > 0) {
    delayExact(triggerTime, triggerTimeus);
  }
  digitalWrite(flashPin, HIGH); //turn on transistor to short the flash and trigger it
  int deltaTime1 = millis() - dropTime1;
  Serial.print("drip to flash: ");
  Serial.println(deltaTime1);
 delay(10); 
  digitalWrite(flashPin, LOW);
}

void triggerFlash(int triggerTime) {
  triggerFlash(triggerTime, 0);
}

void triggerCamera() {
         Serial.println("trigger camera");
         digitalWrite(cameraPin, LOW); // send low signal through optocoupler
         delay(100);
         digitalWrite(cameraPin, HIGH);
         Serial.println("camera triggered");
 }

Even before I got the timing correct, I managed to get some interesting images.
2020-08-29_20_15_56.jpg
2020-08-29_20_13_09.jpg
2020-08-29_20_10_44.jpg
2020-08-29_20_09_22.jpg
2020-08-29_20_09_14.jpg
2020-08-29_20_18_36.jpg
More to come after I clean the solenoid valve and set my rig back up.


keywords: photography


CPA Reptile Macro

Oct 16, 2019

These photos were taken at a macro photography session at the Creative Photo Academy (associated with Paul's photo). The session was free but donations were accepted in support for breast cancer research. As you can see in the last few photos, these guys can be very friendly. I hope you enjoy my new friends.
thumb_1399.jpg
thumb_1400.jpg
thumb_1401.jpg
thumb_1402.jpg
thumb_1403.jpg
thumb_1404.jpg
thumb_1405.jpg
thumb_1406.jpg
thumb_1407.jpg
thumb_1408.jpg
thumb_1409.jpg
thumb_1410.jpg
thumb_1411.jpg
thumb_1412.jpg
thumb_1413.jpg
thumb_1414.jpg
thumb_1415.jpg
thumb_1416.jpg
thumb_1417.jpg
thumb_1418.jpg


keywords: photography