/* Modified from SkySweep 2.07.13 by C. Fastie XI/9/2015 (Nadir tilt position = 4°) For Canon EOS M with 22mm lens on a Saturn V Rig. For SkyShield v 2.x with a 3-switch DIP A sketch to operate the SkyShield, a custom shield for the Arduino Nano which allows autonomous control of a kite aerial photography rig. The sketch controls servos for tilting and panning the camera and a signal is sent to trigger the camera shutter during pauses in servo motion. The pan servo is a continuous rotation servo, the tilt servo is a standard servo. Both are micro servos. Tilt positions are set in arrays, and the number of pan positions at each tilt angle is set in arrays (or variables for non-360° modes). The number of pan positions varies with the tilt angle of the camera (for 360° modes with pans nested within tilts). Eight modes (regimes of pan/tilt/shoot) can be selected in the field with a 3-switch DIP switch. To activate a new mode, press reset or power off/on. Timing will depend on the particular servos and battery strength and can be adjusted by changing the delay values in this sketch. Includes 360° modes for lenses of 24mm, 28mm, and 37mm focal length. Modes should be tested and adjusted for particular battery strength and lens focal length. One mode (mode 7) is a non-360° mode. It pans back and forth covering about 180°at each of four tilt angles. Mode 6 has 4 second interval between shots. Most of the modes trigger Canon cameras with an IR remote sensor. A pattern of quick pulses are sent to flash an NIR LED in front of the IR sensor on the camera. I use Mode 4 for a Canon EOS M with 22mm pancake lens. */ #include // Include the servo library // For tilt control Servo tiltServo; // Assign tilt servo // ***Modify*** the following arrays if you want different tilt angles. The last value in the array is the nadir angle. int tiltAngle5[]= {110, 82, 55, 30, 4}; // Establish an array for five tilt positions upper to lower int tiltAngle4[]= {110, 72, 40, 4}; // Establish an array for four tilt positions upper to lower int tiltAngle3[]= {60, 32, 4}; // Establish an array for three tilt positions upper to lower int tiltPos; // a variable to hold the number of tilt positions in the specified tilt array. // For pan control for 360° modes Servo panServo; // Assign pan servo // ***Modify*** the following arrays if you want different numbers of pan positions at each tilt angle. // The elements of the arrays are the number of pan positions at each tilt angle (from uppermost to lowermost tilt angle). int panPos3[]= {8, 8, 3}; // int panPos8[]= {8, 8, 6, 3}; // For 24mm lens. Establish an array for decreasing number of pan positions. int panPos9[]= {9, 9, 8, 6, 3}; // For 28mm lens. Establish an array for decreasing number of pan positions. int panPos10[]= {10, 10, 9, 7, 4}; // For 37mm lens. Establish an array for decreasing number of pan positions. int fullPan = 2130; // ***Modify*** this number to tune the pan angles. A variable for how long (milliseconds) it takes to pan 360 degree int sweepTime; // variable for the number of milliseconds to pan int panPos; // variable for how many pan positions at this tilt angle int pan; // variable for pan position counter // For pan control for non-360° modes int panIncr; // variable for the speed and direction of the continuous rotation pan servo (only for non-360° modes) int panSpeed; // The speed of panning for non-360° modes (0 = full speed, 90 = stationary) int panCount; // variable for the number of pan positions for non-360° modes (the number of photos to take at each tilt angle) #define arr_len(x) (sizeof(x)/sizeof(*x)) // macro to find the number of elements in an array (used to get the number of tilt positions in the tiltAngleX array) // For camera control int LEDPin = 13; // Assign LEDPin on the Nano to a pin number int shutterPin0 = A0; // Assign ShutterPin0 to a pin number int shutterPin1 = A1; // Assign ShutterPin1 to a pin number (this second camera shutter control is not used in this sketch) // For mode selection int mode = 0; // variable: which of the modes is active int switchPin1 = A2; // Each DIP switch is connected to a different analog pin int switchPin2 = A3; // int switchPin3 = A4; // int pinStatus1; // variable for reading the pin status (HIGH or LOW) int pinStatus2; // int pinStatus3; // void setup() { pinMode(switchPin1, INPUT_PULLUP); // sets the pin named switchPinX as an INPUT_PULLUP pin (uses resistor on Nano) pinMode(switchPin2, INPUT_PULLUP); // pinMode(switchPin3, INPUT_PULLUP); // pinMode(shutterPin0, OUTPUT); // sets the pin named shutterPinx as an output pin pinMode(shutterPin1, OUTPUT); // shutterPin1 is not used in this sketch pinMode(LEDPin, OUTPUT); // sets the pin named LEDPin as an output pin tiltServo.attach(9); // attaches the servo named tiltServo to pin D9 panServo.attach(6); // attaches the servo named panServo to pin D6 // Read the user selected mode from the positions of the DIP switch: pinStatus1 = digitalRead(switchPin1); // read the state of SwitchPinX and store it in pinStatusX pinStatus2 = digitalRead(switchPin2); // pinStatus3 = digitalRead(switchPin3); // // parse the DIP switch positions: if (pinStatus1 == LOW) // if DIP switch 1 is ON (for pull up resistor)... mode = 4; // the mode is at least 4 else mode = 0; // if DIP switch 1 is OFF, the mode is < 4 if (pinStatus2 == LOW) // if DIP switch 2 is ON (for pull up resistor)... mode = mode + 2; // the mode is at least 2 if (pinStatus3 == LOW) // if DIP switch 3 is ON (for pull up resistor)... mode = mode + 1; // the mode is at least 1 // The variable "mode" now contains the number of the mode selected using the DIP switch. tiltServo.write(tiltAngle4[1]); // tilt to first angle in the array panServo.write(90); // stop the servo and hold its position } void loop() { if(mode == 0) // // Mode 0 For SFM. (Slow 360°): 4 to 10 pan positions nested within the lower 2 tilt positions for 37 mm lens { // Tilt Control: for(int a = 2; a <=4 ; a++) // run through the array of tilt angles (a is the counter variable used as the index in two arrays) { tiltServo.write(tiltAngle5[a]); // tilt to next angle in the array delay(1200); // wait after tilt servo motion to take a photo if(a < 1) delay(500); // wait longer during the big tilt back up to the first position // Pan Control: pan = 0; // initialize the pan position counter panPos = panPos10[a]; // fill a variable panPos (how many pan positions) from an array. Depends on the current tilt angle. while(pan < panPos) // pan to each position { // delay(2000); // wait for the camera settle // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano { for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } delayMicroseconds(7330); for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } } digitalWrite(LEDPin, LOW); // turn LED off delay(2000); // wait for the camera to finish taking photo before next servo motion // Do the pan move: sweepTime = fullPan/panPos; // Compute the pan increment time. fullPan is the time for a full 360° pan. pan++; // increment pan position counter panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(sweepTime); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position delay(1000); // wait for the rig to settle before triggering the shutter } // end while } // end for } // end if if(mode == 1) // Mode 1 (Fast 360°): 3 to 8 pan positions nested within 4 tilt positions for 24 mm lens { // Tilt Control: for(int a = 0; a <=3 ; a++) // run through the array of 4 tilt angles (a is the counter variable used as the index in two arrays) { tiltServo.write(tiltAngle4[a]); // tilt to next angle in the array delay(700); // wait after tilt servo motion to take a photo if(a < 1) delay(300); // wait longer during the big tilt back up to the first position // Pan Control: pan = 0; // initialize the pan position counter panPos = panPos8[a]; // fill a variable panPos (how many pan positions) from an array. Depends on the current tilt angle. while (pan < panPos) // pan to each position { // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano { for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } delayMicroseconds(7330); for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } } digitalWrite(LEDPin, LOW); // turn LED off delay(2000); // wait for the camera to finish taking photo before next servo motion // Do the pan move: sweepTime = fullPan/panPos; // Compute the pan increment time. fullPan is the time for a full 360° pan. pan++; // increment the pan position counter panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(sweepTime); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position delay(1000); // wait for the rig to settle before triggering the shutter } // end while } // end for } // end if if(mode == 2) // Mode 2 (Slow 360°): 3 to 9 pan positions nested within 5 tilt positions for 28 mm lens { // Tilt Control: for(int a = 0; a <=4 ; a++) // run through the array of 5 tilt angles (a is the counter variable used as the index in two arrays) { tiltServo.write(tiltAngle5[a]); // tilt to next angle in the array delay(1200); // wait after tilt servo motion to take a photo if(a < 1) delay(500); // wait longer during the big tilt back up to the first position // Pan Control: pan = 0; // initialize the pan position counter panPos = panPos9[a]; // fill a variable panPos (how many pan positions) from an array. Depends on the current tilt angle. while (pan < panPos) // pan to each position { // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano digitalWrite(shutterPin0, HIGH); // start to send current to the camera USB port delay(250); // send current to the USB port for this long digitalWrite(shutterPin0, LOW); // drop the current to the USB port to zero digitalWrite(LEDPin, LOW); // turn LED off delay(1300); // wait for the camera to finish taking photo before next servo motion // Do the pan move: sweepTime = fullPan/panPos; // Compute the pan increment time. fullPan is the time for a full 360° pan. pan++; // increment pan position counter panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(sweepTime); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position delay(1300); // wait for the rig to settle before triggering the shutter } // end while } // end for } // end if if(mode == 3) // Mode 3 (Fast 360°): 3 to 9 pan positions nested within 5 tilt positions for 28 mm lens { for(int a = 0; a <=4 ; a++) // run through the array of tilt angles (a is the counter variable used as the index in two arrays) { // Tilt Control: tiltServo.write(tiltAngle5[a]); // tilt to next angle in the array delay(900); // wait after tilt servo motion to take a photo if(a < 1) delay(400); // wait longer during the big tilt back up to the first position // Pan Control: pan = 0; // initialize the pan position counter panPos = panPos9[a]; // fill a variable panPos (how many pan positions) from an array. Depends on the current tilt angle. while (pan < panPos) // pan to each position { // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano digitalWrite(shutterPin0, HIGH); // start to send current to the camera USB port delay(250); // send current to the USB port for this long digitalWrite(shutterPin0, LOW); // drop the current to the USB port to zero digitalWrite(LEDPin, LOW); // turn LED off delay(900); // wait for the camera to finish taking photo before next servo motion // Do the pan move: sweepTime = fullPan/panPos; // Compute the pan increment time. fullPan is the time for a full 360° pan. pan++; // increment pan position counter panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(sweepTime); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position delay(900); // wait for the rig to settle before triggering the shutter } // end while } // end for } // end if if(mode == 4) // Mode 4 (Slow 360° 5x9): 5 tilt positions nested within 9 pan positions { panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(230); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position for(int a=0; a<=4; a++) // run through the array of tilt angles (a is the counter variable used as the index in an array) { tiltServo.write(tiltAngle5[a]); // tilt to next angle in the array delay(1000); // wait (1 second) after tilt servo motion to take a photo if(a<1) delay(300); // wait longer during the big tilt back up to the first position // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano { for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } delayMicroseconds(7330); for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } } digitalWrite(LEDPin, LOW); // turn LED off delay(2500); // wait for the camera to finish taking photo before next servo motion } // end for } // end if if(mode == 5) // Mode 5 (Fast 360° 5x9): 5 tilt positions nested within 9 pan positions { panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(230); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position for(int a=0; a<=4; a++) // run through the array of tilt angles (a is the counter variable used as the index in an array) { tiltServo.write(tiltAngle5[a]); // tilt to next angle in the array delay(900); // wait after tilt servo motion to take a photo if(a<1) delay(300); // wait longer during the big tilt back up to the first position // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano { for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } delayMicroseconds(7330); for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } } digitalWrite(LEDPin, LOW); // turn LED off delay(2000); // wait for the camera to finish taking photo before next servo motion } // end for } // end if if(mode == 6) // Mode 6 (Slow 360°): 4 to 10 pan positions nested within 5 tilt positions for 37 mm lens { // Tilt Control: for(int a = 0; a <=4 ; a++) // run through the array of 5 tilt angles (a is the counter variable used as the index in two arrays) { tiltServo.write(tiltAngle5[a]); // tilt to next angle in the array delay(1200); // wait after tilt servo motion to take a photo if(a < 1) delay(500); // wait longer during the big tilt back up to the first position // Pan Control: pan = 0; // initialize the pan position counter panPos = panPos10[a]; // fill a variable panPos (how many pan positions) from an array. Depends on the current tilt angle. while (pan < panPos) // pan to each position { // delay(2000); // wait for the camera settle // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano { for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } delayMicroseconds(7330); for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } } digitalWrite(LEDPin, LOW); // turn LED off delay(2000); // wait for the camera to finish taking photo before next servo motion // Do the pan move: sweepTime = fullPan/panPos; // Compute the pan increment time. fullPan is the time for a full 360° pan. pan++; // increment pan position counter panServo.write(16); // Start the pan servo turning at the designated speed and direction. delay(sweepTime); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position delay(1000); // wait for the rig to settle before triggering the shutter } // end while } // end for } // end if if(mode == 7) // Mode 7 (non-360° coverage via serpentine). For 24 mm lens. Tilt angles are established in the tiltAngleX array. The number of pan positions, // speed of panning, and duration of panning are established in variables. { // This mode specifies 4 tilt angles and 4 pan positions per tilt angle. These parameters can be changed where it says ***Modify***. panCount = 4; // ***Modify*** The number of pan positions (number of photos to take at each tilt angle). If large enough, 360° can be covered. panSpeed = 16; // ***Modify*** The speed of panning (0 = full speed, 90 = stationary). With sweepTime, this determines the pan angle. sweepTime = 255; // ***Modify*** The time (milliseconds) the pan servo turns during each pan increment. With panSpeed, this determines the pan angle. tiltPos = arr_len(tiltAngle4); // ***Modify*** Find the number of tilt positions in the tilt array specified (uses arr_len macro defined above). Change the name of the tiltAngleX array here (must be the same array as below). for(int a = 0; a < tiltPos; a++) // run through the array of tilt angles (a is the counter variable used as the index in the tiltAngleX array) { tiltServo.write(tiltAngle4[a]); // ***Modify*** Tilt to next angle in the array. Change the name of the tiltAngleX array here (must be the same array as above). delay(1000); // wait (1 second) after tilt servo motion to take a photo if(a < 1) delay(500); // wait longer during the big tilt back up to the first position pan = 0; // initialize the pan position variable if (a % 2 == 0) // if the index for the tilt array is even... (this allows alternating directions every other tilt angle) { panIncr = panSpeed; // ...then the pan increment will rotate clockwise (0 is full-speed in one direction, 180 is full speed in the other, and 90 is no movement) } // end if else panIncr = 180-panSpeed; // ...else the pan increment will rotate counterclockwise (panIncr is between 90 and 180) while (pan < panCount) // pan to each position sequentially { // Shutter Control: digitalWrite(LEDPin, HIGH); // send current to the LED on the Nano { for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } delayMicroseconds(7330); for(int i=0; i<16; i++) { digitalWrite(shutterPin0, HIGH); delayMicroseconds(11); digitalWrite(shutterPin0, LOW); delayMicroseconds(11); } } digitalWrite(LEDPin, LOW); // turn LED off delay(1100); // wait for the camera to finish taking photo before next servo motion if (pan < (panCount-1)) // if another pan movement is needed { panServo.write(panIncr); // Start the pan servo turning at the designated speed and direction delay(sweepTime); // let the servo turn for a number of milliseconds. This determines how much the rig rotates (pans). panServo.write(90); // stop the servo and hold its position delay(1200); // wait for the rig to settle before triggering shutter } // end if pan++; // increment the pan position variable } // end while } // end for } // end if } // end void loop