Advertisement
Guest User

Pano-XY-4-Button_V-1.0.4.ino

a guest
Mar 23rd, 2022
643
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //////////////////////////////////
  2. //   PANO-XY 4 BUTTON V-1.0.4   //
  3. /////////////////////////////////
  4.  
  5. /*
  6.     Pano-XY is the program for controlling a servo-motor driven
  7.     panorama camera-mount that allows panoramas with multiple rows of
  8.     images. The photographer is prompted to enter the focal length of the
  9.     camera's lens, the width of the panorama (in degrees), the number
  10.     of rows of images, and whether the camera is in landscape or
  11.     portrait orientation.
  12.  
  13.     The program will then calculate the field of view and the total
  14.     number of images required for the panorama using a 50% overlap for
  15.     horizontal moves and a 65% overlap for vertical moves. The 65%
  16.     vertical overlap is a change from 50% in previous versions.
  17.  
  18.     The program will then automatically move the camera to the correct position
  19.     and fire the shutter for each image. At the completion of the panorama, the
  20.     camera will return to its home position.
  21. */
  22.  
  23. /* Pano-XY-4-Button_V-1.0.4
  24.   Changed default lens focal length to 50mm and the default pano width to 50 degrees.
  25. */
  26.  
  27. /* Pano-XY-4-Button_V-1.0.3
  28.   Shortened the delay times for settling after camera moves and the shutter time by 25%.
  29. */
  30.  
  31. /* Pano-XY-4-Button_V-1.0.2
  32.   Corrected rows algorithm when there is more than 1 row. For 2 row panos, neither row will be at horizontal.
  33.   For 3 or more rows, only one row will below horizontal. All other rows will be horizontal or above.
  34. */
  35.  
  36. /* Pano-XY-4-Button_V-1.0.1a
  37.   Changed the method for calculating the start position for the vertical camera
  38.   movement
  39.   Removed the serial.print commands used for debugging
  40. */
  41.  
  42. /*  Pano-XY-4-Button_V-1.0.1
  43.     Changed the amount of movement in the Home Camera exercise during the set-up routine from 30º swing each way to
  44.     15º swing each way (30º total) for both servos
  45. */
  46.  
  47. /*  Previous versions (PANO-XY V-1.1.a, V-1.1.b, & V-1.1.c) utilized a
  48.     4x4 keypad and a 20 x 4 display. This version uses 4 momentary
  49.     contact buttons and a 16 x 2 display. The change allows for a
  50.     considerably smaller case for the electronics and the controls. The
  51.     original case was 6-1/2" x 6-1/2" x 4-1/2".
  52. */
  53.  
  54. /*  PANO-XY V-1.1.a
  55.     Corrected starting position of horizontal arm.
  56. */
  57.  
  58. /*  PANO-XY V-1.1.b
  59.     Changed image overlap to 50% from previous 35%.
  60. */
  61.  
  62. /*  PANO-XY V-1.1.c
  63.     Corrected starting position of vertical arm, and corrected display
  64.     to read PANO-XY rather than Pano-Riffic.
  65. */
  66.  
  67.  
  68. //LIBRARIES USED
  69. #include <LiquidCrystal_I2C.h>
  70. #include <Servo.h> // servo motor library
  71. #include <wire.h>  //
  72.  
  73.  
  74. /*** Set Servos ***/
  75. Servo imageServo;  // create servo object to control the horizontal servo
  76. Servo rowServo;    // create servo object to control the vertical servo
  77.  
  78. /*** Servo Variables ***/
  79. int imageServoMin = 833;     // microseconds = to 0 degrees for a specific servomotor – NOTE: You will have to test your particular servos and set accordingly
  80. int imageServoMax = 2167;    // microseconds = to 180 degrees for a specific servomotor
  81. int imageServoHome = 1500;   // ((servoRange) / 2) + imageServoMin; the midpoint or 90º
  82.  
  83. int rowServoMin = 985;       // microseconds = to 0 degrees for a specific servomotor – NOTE: You will have to test your particular servos and set accordingly
  84. int rowServoMax = 1995;      // microseconds = to 180 degrees for a specific servomotor
  85. int rowServoHome = 1500;     // ((servoRange) / 2) + imageServoMin; the midpoint or 90º
  86.  
  87.  
  88. /*** LCD Display ***/
  89. // display i2c address & size
  90. LiquidCrystal_I2C myLcd(0x27, 16, 2);  // 0x27 & 0x3F are typical addresses for the I2C. If either of these do not work, read this: https://lastminuteengineers.com/i2c-lcd-arduino-tutorial/
  91.  
  92.  
  93. /*** LCD Arrows ***/
  94. byte RtArrow[8] =
  95. {0b00000, 0b00100, 0b00010, 0b11111, 0b00010, 0b00100, 0b00000, 0b00000};  // create right arrow character for display
  96.  
  97. byte LtArrow[8] =
  98. {0b00000, 0b00100, 0b01000, 0b11111, 0b01000, 0b00100, 0b00000, 0b00000}; // create left arrow character for display
  99.  
  100. byte DnArrow[8] =
  101. {0b00000, 0b00100, 0b00100, 0b00100, 0b10101, 0b01110, 0b00100, 0b00000}; // create down arrow character for display
  102.  
  103. byte UpArrow[8] =
  104. {0b00000, 0b00100, 0b01110, 0b10101, 0b00100, 0b00100, 0b00100, 0b00000}; // create up arrow character for display
  105.  
  106.  
  107. /*** assign button pins ***/
  108. const int buttonPinLeft = 4;    // left button (back arrow)
  109. const int buttonPinRight = 5;   // right button (forward arrow)
  110. const int buttonPinUp = 6;      // up button (up or increase arrow)
  111. const int buttonPinDown = 7;    // down button (down or decrease arrow)
  112.  
  113.  
  114. /***state of buttons un-pressed ***/
  115. int buttonStateLeft = 0;
  116. int buttonStateRight = 0;
  117. int buttonStateUp = 0;
  118. int buttonStateDown = 0;
  119.  
  120.  
  121. /*** menu arrays ***/
  122. const int FrameNum = 12;
  123. int CurrentFrame = 0;
  124. int Inputs[FrameNum] = {85, 75, 1, 1, 0};
  125.  
  126.  
  127. /*** variables ***/
  128. // utilities
  129. int x;                      // used as a counting tool
  130. int y;                      // used as a counting tool
  131.  
  132. int buttonBounce = 200;     // bounce time for buttons
  133. int shutterPin = 12;        // Pin for camera shutter release relay
  134.  
  135. // photo variables
  136. int focLength = 50;         // default focal length (mm) – NOTE: Set your default according to the lens lengths you typically use
  137. bool camVal = 1;            // Camera orientation
  138. char camOrient = 'P';       // identify camera orientation - NOTE: Set your default according to the camera orientation you typically use
  139. bool startVal = 0;          // start the panorama
  140.  
  141. // calculation varibles
  142. float sensorWidth = 23.6;   // width of Pentax APS-C camera sensor – NOTE: Change according to your camera
  143. float sensorHeight = 15.7   // height of Pentax APS-C camera sensor – NOTE: Change according to your camera
  144. float fovSens;              // calculated horizontal field of view
  145. float camFov;               // actual field of view - landscape or portrait
  146. float fovHeight;            // vertical field of view in degrees
  147. float imageWidth;           // width of image after lap factor
  148. float imageHeight;          // height of image after lap factor
  149. float hLapFactor = 0.50;    // percentage of actual horizontal FOV used for image // NOTE - change to suit (0.35 is common)
  150. float vLapFactor = 0.35;    // percentage of actual vertical FOV used for image   // NOTE - change to suit
  151.  
  152. // row variables
  153. int rowCount = 1;           // default number of rows - NOTE: Set your default according to the number of rows you typically shoot
  154. int rowMoves;               // # of moves
  155. float rowTravel;            // amount of travel for each row move (degrees)
  156. float rowPos;               // position of the camera center for a row (degrees)
  157. int rowPosMicros;           // position of the camera center for a row (micros)
  158. int rowHome = 90;           // sets the camera to a "zeroed" vertical posiiton
  159. float rowStart;             // a panorama's starting vertical position
  160.  
  161. // image variables
  162. int imageCount;             // number of images in panorama (not including initial centered image)
  163. int cameraMoves;            // number of moves between images
  164. int cameraTravel;           // degrees camera travels from one position to the next
  165.  
  166. // pano size variables
  167. int panoWidth = 50;         // default desired panorama width in degrees - NOTE: Set your default according to the panorama width you typically want
  168. int panoHeightActual;       // overall height of a panorama
  169. int panoWidthActual;        // actual width of panorama after calculations
  170. float aspectRatio;          // width:height of panorama
  171.  
  172. // camera position variables
  173. float panoPosDegrees;       // position of the camera center for an image (degrees)
  174. int panoPosMicros;          // position of the camera center for an image (microseconds)
  175. int panoHome = 90;          // center of the panorama in degrees
  176. int panoStart;              // position of camera center for first image of panorama (not including initial centered image)
  177.  
  178. // time variables to use to estimate required time for pano
  179. // set time to zero
  180. long panoTime = 0;
  181. long panoMinutes = 0;
  182. long panoSeconds = 0;
  183.  
  184. /******************************************************************************************************/
  185.  
  186. /*********************************************** SETUP ***********************************************/
  187.  
  188. void setup() {
  189.   // begin serial
  190.   Serial.begin(9600);
  191.  
  192.   // initiate LCD
  193.   myLcd.init();   // initializing the LCD
  194.   myLcd.backlight(); // Enable or Turn On the backlight
  195.  
  196.   // creating the LCD arrows for display
  197.   myLcd.createChar(0, RtArrow);
  198.   myLcd.createChar(1, LtArrow);
  199.   myLcd.createChar(2, DnArrow);
  200.   myLcd.createChar(3, UpArrow);
  201.  
  202.   // set buttons
  203.   pinMode(buttonPinLeft, INPUT_PULLUP);
  204.   pinMode(buttonPinDown, INPUT_PULLUP);
  205.   pinMode(buttonPinUp, INPUT_PULLUP);
  206.   pinMode(buttonPinRight, INPUT_PULLUP);
  207.  
  208.   // Initialize Shutter Relay
  209.   pinMode(shutterPin, OUTPUT); // specifies output pin for activating camera shutter
  210.  
  211.   // Set up the servos and set positions to 90º
  212.   imageServo.attach(9, imageServoMin, imageServoMax);  // attaches the horizontal servo on pin 9 & sets the limits
  213.   rowServo.attach(10, rowServoMin, rowServoMax);       // attaches the vertical servo on pin 10 & sets the limits
  214.   imageServo.writeMicroseconds(imageServoHome);        // centers the horizontal servo
  215.   rowServo.writeMicroseconds(rowServoHome);            // centers the vertical servo
  216.  
  217.   OpeningScreen(); // opening screen & exercise servos
  218. } // end setup
  219.  
  220. /******************************************************************************************************/
  221.  
  222.  
  223. /*********************************************** LOOP ************************************************/
  224.  
  225. void loop() {
  226.   InputMenu(); // container for all screens and activities
  227. } // end loop
  228.  
  229. /******************************************************************************************************/
  230.  
  231.  
  232. /**********************************************************************************************************************
  233.                                                          FUNCTIONS
  234. **********************************************************************************************************************/
  235.  
  236. /************************************************ BUTTON DISPLAY FUNCTIONS *******************************************/
  237.  
  238. // GO ON ARROW DISPLAY
  239. void GoOnArrowDisplay()
  240. {
  241.   myLcd.setCursor(0, 1);
  242.   myLcd.setCursor(9, 1);
  243.   myLcd.print("Go On ");
  244.   myLcd.write(0); // right arrow
  245. } // end function
  246.  
  247.  
  248. // FOUR ARROWS DISPLAY
  249. void FourArrowsDisplay()
  250. { myLcd.setCursor(0, 1);
  251.   myLcd.write(1); // left arrow
  252.   myLcd.setCursor(5, 1);
  253.   myLcd.write(3); // up arrow
  254.   myLcd.setCursor(10, 1);
  255.   myLcd.write(2); // down arrow
  256.   myLcd.setCursor(15, 1);
  257.   myLcd.write(0); // right arrow
  258. } // end function
  259.  
  260.  
  261. // YES/NO ARROW DISPLAY
  262. void YesNoArrowDisplay()
  263. {
  264.   myLcd.setCursor(0, 1);
  265.   myLcd.write(1); // left arrow
  266.   myLcd.setCursor(2, 1);
  267.   myLcd.print("NO");
  268.   myLcd.setCursor(11, 1);
  269.   myLcd.print("YES");
  270.   myLcd.setCursor(15, 1);
  271.   myLcd.write(0); // right arrow
  272. } // end function
  273.  
  274. /************************************************ BUTTON ACTION FUNCTIONS ********************************************/
  275. // These actions create the different button actions to be used with the arrow displays
  276.  
  277. // INPUT FORWARD/BACK ACTION
  278. void MenuForwardBackAction()
  279. {
  280.   buttonStateLeft = digitalRead(buttonPinLeft);
  281.   buttonStateRight = digitalRead(buttonPinRight);
  282.  
  283.   // left button pressed
  284.   if (buttonStateLeft == LOW) {
  285.     delay(buttonBounce);
  286.     myLcd.clear();
  287.     if (CurrentFrame == 0) {
  288.       CurrentFrame = FrameNum - 1;
  289.     }
  290.     else {
  291.       CurrentFrame--;
  292.     }
  293.   }
  294.  
  295.   // right button pressed
  296.   else if (buttonStateRight == LOW) {
  297.     delay(buttonBounce);
  298.     myLcd.clear();
  299.     if (CurrentFrame == FrameNum - 1) {
  300.       CurrentFrame = 0;
  301.     }
  302.     else {
  303.       CurrentFrame++;
  304.     }
  305.   }
  306. } // end function
  307.  
  308.  
  309. // RIGHT TO CONTINUE BUTTON
  310. void RightToContinueAction()
  311. {
  312.   buttonStateRight = digitalRead(buttonPinRight);
  313.   while (digitalRead(buttonPinRight) == HIGH) {} // wait for right button push
  314.   delay(buttonBounce);
  315. } // end function
  316.  
  317.  
  318. // RIGHT TO CONTINUE BUTTON
  319. void GoRightAction()
  320. {
  321.   buttonStateRight = digitalRead(buttonPinRight);
  322.   // right button pressed
  323.  
  324.   if (buttonStateRight == LOW) {
  325.     delay(buttonBounce);
  326.     myLcd.clear();
  327.     if (CurrentFrame == FrameNum - 1) {
  328.       CurrentFrame = 0;
  329.     }
  330.     else {
  331.       CurrentFrame++;
  332.     }
  333.   }
  334. } // end function
  335.  
  336.  
  337. // RUN/RESET BUTTON
  338. void RunResetAction()
  339. {
  340.   buttonStateRight = digitalRead(buttonPinRight);
  341.   buttonStateLeft = digitalRead(buttonPinLeft);
  342.   // right button pressed
  343.   if (buttonStateRight == LOW) {
  344.     delay(buttonBounce);
  345.     CurrentFrame = 10;
  346.   } // end if
  347.  
  348.   // left button pressed
  349.   else if (buttonStateLeft == LOW) {
  350.     delay(buttonBounce);
  351.     ResetMenu();
  352.   } // end if
  353. } // end function
  354.  
  355.  
  356. // RUN/QUIT BUTTON
  357. void PanoQuitAction()
  358. {
  359.   buttonStateRight = digitalRead(buttonPinRight);
  360.   buttonStateLeft = digitalRead(buttonPinLeft);
  361.   // right button pressed
  362.   if (buttonStateRight == LOW) {
  363.     delay(buttonBounce);
  364.     ResetMenu();
  365.   } // end if
  366.  
  367.   // left button pressed
  368.   else if (buttonStateLeft == LOW) {
  369.     delay(buttonBounce);
  370.     QuitPano();
  371.   } // end if
  372. } // end function
  373.  
  374.  
  375. // DO PANO BUTTON
  376. void DoPanoAction()
  377. {
  378.   buttonStateLeft = digitalRead(buttonPinLeft);
  379.   buttonStateRight = digitalRead(buttonPinRight);
  380.  
  381.   // left button pressed
  382.   if (buttonStateLeft == LOW) {
  383.     delay(buttonBounce);
  384.     myLcd.clear();
  385.     if (CurrentFrame == 0) {
  386.       CurrentFrame = FrameNum + 1;
  387.     } // end if
  388.     else {
  389.       CurrentFrame++;
  390.     } // end else
  391.   } // end if
  392.  
  393.   // right button pressed
  394.   else if (buttonStateRight == LOW) {
  395.     delay(buttonBounce);
  396.     myLcd.clear();
  397.     //   DoPano();
  398.   } // end  if
  399. } // end function
  400.  
  401.  
  402. // PORTRAIT/LANDSCAPE BUTTON
  403. void PortLandButtonAction()
  404. {
  405.   buttonStateUp = digitalRead(buttonPinUp);
  406.   buttonStateDown = digitalRead(buttonPinDown);
  407.  
  408.   // up button pressed
  409.   if (buttonStateUp == LOW) {
  410.     delay(buttonBounce);
  411.     camOrient = 'P';
  412.   }
  413.   // down button pressed
  414.   if (buttonStateDown == LOW) {
  415.     delay(buttonBounce);
  416.     camOrient = 'L';
  417.   }
  418. } // end function
  419.  
  420.  
  421. // 1 INCREMENT UP/DOWN BUTTON - adjusts values by an increment of 1
  422. void UpDownAction1()
  423. {
  424.   buttonStateUp = digitalRead(buttonPinUp);
  425.   buttonStateDown = digitalRead(buttonPinDown);
  426.  
  427.   // up button pressed
  428.   if (buttonStateUp == LOW) {
  429.     delay(buttonBounce);
  430.     Inputs[CurrentFrame] = Inputs[CurrentFrame] + 1;
  431.     if (Inputs[CurrentFrame] > 9) { // keeps value from being above 9
  432.       Inputs[CurrentFrame] = 9;
  433.     } // end if
  434.     myLcd.clear();
  435.   } // end if
  436.  
  437.   // down button pressed
  438.   else if (buttonStateDown == LOW) {
  439.     delay(buttonBounce);
  440.     Inputs[CurrentFrame] = Inputs[CurrentFrame] - 1;
  441.     if (Inputs[CurrentFrame] < 0) {  // keeps value from being below zero
  442.       Inputs[CurrentFrame] = 0;
  443.     } // end if
  444.     myLcd.clear();
  445.   } // end else if
  446. } // end function
  447.  
  448.  
  449. // 5 INCREMENT UP/DOWN BUTTON - adjusts values by an increment of 5
  450. void UpDownAction5()
  451. {
  452.   buttonStateUp = digitalRead(buttonPinUp);
  453.   buttonStateDown = digitalRead(buttonPinDown);
  454.  
  455.   // up button pressed
  456.   if (buttonStateUp == LOW) {
  457.     delay(buttonBounce);
  458.     Inputs[CurrentFrame] = Inputs[CurrentFrame] + 5;
  459.     if (Inputs[CurrentFrame] > 360) { // keeps value from being above 360
  460.       Inputs[CurrentFrame] = 360;
  461.     } // end if
  462.     myLcd.clear();
  463.   } // end if
  464.  
  465.   // down button pressed
  466.   else if (buttonStateDown == LOW) {
  467.     delay(buttonBounce);
  468.     Inputs[CurrentFrame] = Inputs[CurrentFrame] - 5;
  469.     if (Inputs[CurrentFrame] < 0) {  // keeps value from being below zero
  470.       Inputs[CurrentFrame] = 0;
  471.     } // end if
  472.     myLcd.clear();
  473.   } // end else if
  474. } // end function
  475.  
  476. /************************************************ DATA ENTRY FUNCTIONS ********************************************/
  477.  
  478. // MENU FRAME HANDLER
  479. void InputMenu()
  480. {
  481.   switch  (CurrentFrame) {
  482.     case 0:
  483.       FocalFrame();
  484.       break;
  485.     case 1:
  486.       PanoFrame();
  487.       break;
  488.     case 2:
  489.       RowFrame();
  490.       break;
  491.     case 3:
  492.       CamFrame();
  493.       break;
  494.     case 4:
  495.       AllPanoCalcs();
  496.       break;
  497.     case 5:
  498.       ReviewOne();
  499.       break;
  500.     case 6:
  501.       ReviewTwo();
  502.       break;
  503.     case 7:
  504.       ReviewThree();
  505.       break;
  506.     case 8:
  507.       ReviewFour();
  508.       break;
  509.     case 9:
  510.       RunOrReset();
  511.       break;
  512.     case 10:
  513.       PanoRun();
  514.       break;
  515.     case 11:
  516.       RunQuit();
  517.       break;
  518.   }
  519. } // end function
  520.  
  521.  
  522. // FOCAL LENGTH MENU – FRAME 0
  523. void FocalFrame()
  524. {
  525.   focLength = Inputs[CurrentFrame];
  526.   UpDownAction5();                    // adjusts focal length by increments of 5
  527.   FourArrowsDisplay();
  528.   myLcd.setCursor(0, 0);
  529.   myLcd.print("Focal Len (mm)  ");
  530.   myLcd.setCursor(7, 1);
  531.   myLcd.print(focLength);             // displays the default focal length
  532.   MenuForwardBackAction();
  533. } // end function
  534.  
  535.  
  536. // PANORAMA WIDTH MENU – FRAME 1
  537. void PanoFrame()
  538. {
  539.   panoWidth = Inputs[CurrentFrame];
  540.   UpDownAction5();                    // adjusts focal length by increments of 5
  541.   FourArrowsDisplay();
  542.   myLcd.setCursor(0, 0);
  543.   myLcd.print("Pano Width ( )  ");
  544.   myLcd.setCursor(12, 0);
  545.   myLcd.print((char)223);               //degree symbol
  546.   myLcd.setCursor(7, 1);
  547.   myLcd.print(panoWidth);             // displays the default pano width
  548.   MenuForwardBackAction();
  549. } // end function
  550.  
  551.  
  552. // NUMBER OF ROWS MENU – FRAME 2
  553. void RowFrame()
  554. {
  555.   rowCount = Inputs[CurrentFrame];
  556.   UpDownAction1();                    // adjusts focal length by an increment of 1
  557.   FourArrowsDisplay();
  558.   myLcd.setCursor(0, 0);
  559.   myLcd.print("Number of Rows  ");    // displays the default number of rows
  560.   myLcd.setCursor(7, 1);
  561.   myLcd.print(rowCount);              // displays the default number of rows
  562.   MenuForwardBackAction();
  563. } // end function
  564.  
  565.  
  566. // CAMERA POSITION MENU – FRAME 3
  567. void CamFrame()
  568. {
  569.   camVal = Inputs[CurrentFrame];
  570.   UpDownAction1();                    // adjusts focal length by an increment of 1
  571.   FourArrowsDisplay();
  572.   myLcd.setCursor(0, 0);
  573.   myLcd.print("Camera Position  ");
  574.   myLcd.setCursor(7, 1);
  575.   myLcd.print(camOrient);             // displays camera orientation (landscape/portrait)
  576.   PortLandButtonAction();
  577.   MenuForwardBackAction();
  578. } // end function
  579.  
  580.  
  581. // CALCULATE PANO - FRAME 4
  582. void AllPanoCalcs()
  583. {
  584.   //UpDownAction1();
  585.   GoOnArrowDisplay();
  586.   myLcd.setCursor(0, 0);
  587.   myLcd.print("Pano Calcs  ");
  588.  
  589.   // FOV Calcs
  590.   // calculate horizontal FOV (degrees) based on lens focal length
  591.   fovSens = round(2 * atan(sensorWidth / (2 * focLength)) * (180 / PI));
  592.   if (camOrient == 'L') // sets FOV values for landscape-mounted camera
  593.   {
  594.     camFov = fovSens; // sets the calculated width image FOV
  595.     fovHeight = round(fovSens * (0.67 )); // sets the calculated height image FOV
  596.   }
  597.  
  598.   // calculate portrait FOV (degrees) based on lens focal length
  599.   if (camOrient == 'P') // sets FOV values for portrait-mounted camera
  600.   {
  601.     camFov = round(fovSens * (0.67 )); // adjusts the camera FOV to the calculated portrait FOV
  602.     fovHeight = fovSens;
  603.   }
  604.  
  605.   // serial print statements for debugging only
  606.   // all serial print statements are cureently commented out with "//"
  607.   // remove "//" to print info to monitor
  608.   // feel free to competely remove serial print statements when all testing complete
  609.  
  610.   //Serial.print("Cam Orient: "); Serial.println(camOrient);
  611.   //Serial.print("Focal Len: "); Serial.println(focLength);
  612.  
  613.   //Serial.print("FOV Width: "); Serial.println(camFov);
  614.   //Serial.print("FOV Height: "); Serial.println(fovHeight);
  615.   //Serial.print("Pano Width: "); Serial.println(panoWidth);
  616.   //Serial.print("Row Count: "); Serial.println(rowCount);
  617.   //Serial.print("Horizontal Lap Factor: "); Serial.println(hLapFactor);
  618.   //Serial.print("Vertical Lap Factor: "); Serial.println(vLapFactor);
  619.  
  620.  
  621.   //calculate actual FOV after image overlap (rounded up)
  622.   imageWidth = (round(camFov * hLapFactor));
  623.   // Serial.print("Image Width: "); Serial.println(imageWidth);
  624.  
  625.   imageHeight = (round(fovHeight * vLapFactor));
  626.   //Serial.print("Image Height: "); Serial.println(imageHeight);
  627.  
  628.   rowTravel = imageHeight;
  629.   // calculate the number of images for the panorama (rounded)
  630.   imageCount = (round(panoWidth / imageWidth));
  631.   // Serial.print("# images "); Serial.println(imageCount); Serial.println();
  632.  
  633.   if ((imageCount % 2) != 1)
  634.   {
  635.     imageCount = imageCount + 1;  // test for odd; if even, add 1
  636.   }
  637.  
  638.   // Pano Calcs
  639.   // calculate camera moves
  640.   cameraMoves = imageCount - 1;
  641.   // Serial.print("camera moves "); Serial.println(cameraMoves);
  642.  
  643.   // calculate the degrees between images (rounded up)
  644.   cameraTravel = (round((panoWidth / imageCount) + 0.5));
  645.   // Serial.print("camera travel "); Serial.println(cameraTravel);
  646.  
  647.   // calculate the actual width of the panorama
  648.   panoWidthActual = cameraTravel * cameraMoves;
  649.   // Serial.print("actual pano width "); Serial.println(panoWidthActual); Serial.println();
  650.  
  651.   // calculate the horizontal starting position of the panorama
  652.   panoStart = panoHome - (panoWidthActual / 2);
  653.   // Serial.print("start position "); Serial.println(panoStart);
  654.  
  655.   // calculate actual height of the panorama
  656.   panoHeightActual = rowCount * rowTravel;
  657.   // Serial.println(rowCount);
  658.   // Serial.println(rowTravel);
  659.   // Serial.print("pano height "); Serial.println(panoHeightActual); Serial.println();
  660.  
  661.   // calculate pano aspect ratio
  662.   aspectRatio = ((panoWidthActual * 100.0) / (panoHeightActual)) / 100.0;
  663.   //  Serial.print("pano aspect ratio "); Serial.println(aspectRatio);
  664.  
  665.   // calculate row moves
  666.   rowMoves = rowCount - 1;
  667.   // Serial.print("row moves "); Serial.println(rowMoves); Serial.println();
  668.  
  669.   // calculate the vertical starting position of the panorama
  670.   if (rowCount == 1) {
  671.     rowStart = rowHome;
  672.   }
  673.   else if (rowCount == 2) {
  674.     rowStart = rowHome + (imageHeight / 2);
  675.   }
  676.   else if (rowCount > 2) {
  677.     rowStart = rowHome + imageHeight;
  678.   }
  679.  
  680.   // Serial.print("row start position "); Serial.println(rowStart);
  681.  
  682.   // calculate approximate time required
  683.   panoTime = (15000L + (8000L * cameraMoves * rowCount) ) + (4500L * rowCount);
  684.   panoMinutes = (panoTime / 60000);
  685.   panoSeconds = ((panoTime - (60000 * panoMinutes)) / 1000);
  686.   MenuForwardBackAction();
  687. } // end function
  688.  
  689.  
  690. // INFORMATION REVIEW SCREENS
  691. // Screens preview all info about the pano
  692.  
  693. // PANO SIZE REVIEW – FRAME 5
  694. void ReviewOne()
  695. {
  696.  
  697.   myLcd.setCursor(0, 0);
  698.   myLcd.print("Pano Size ");
  699.   myLcd.setCursor(10, 0);
  700.   myLcd.print(panoWidthActual);
  701.   myLcd.write(223);
  702.   myLcd.print("x");
  703.   myLcd.print(panoHeightActual);
  704.   myLcd.write(223);
  705.   GoOnArrowDisplay();
  706.   GoRightAction();
  707. }
  708.  
  709.  
  710. // PANO RATIO REVIEW – FRAME 6
  711. void ReviewTwo()
  712. {
  713.   // myLcd.clear();
  714.   myLcd.setCursor(0, 0);
  715.   int aspect = aspectRatio;
  716.   myLcd.print("Pano Ratio  "); myLcd.print(aspect, 1); myLcd.print(":1");
  717.   GoOnArrowDisplay();
  718.   GoRightAction();
  719. }
  720.  
  721.  
  722. // IMAGE COUNT REVIEW – FRAME 7
  723. void ReviewThree()
  724. {
  725.   myLcd.setCursor(0, 0);
  726.   myLcd.print(imageCount); myLcd.print(" Images "); myLcd.print(rowCount); myLcd.print(" Rows");
  727.   GoOnArrowDisplay();
  728.   GoRightAction();
  729. }
  730.  
  731.  
  732. // EST TIME REVIEW – FRAME 8
  733. void ReviewFour()
  734. {
  735.   //  myLcd.clear();
  736.   myLcd.setCursor(0, 0);
  737.   myLcd.print("Est Time ");
  738.   myLcd.setCursor(9, 0);
  739.   myLcd.print(panoMinutes);
  740.   myLcd.print("m ");
  741.   myLcd.print(panoSeconds);
  742.   myLcd.print("s");
  743.   GoOnArrowDisplay();
  744.   GoRightAction();
  745. } // end function
  746.  
  747.  
  748. // RUN OR RESET MENU - FRAME 9
  749. void RunOrReset()
  750. {
  751.   //resetAll = Inputs[CurrentFrame];
  752.   myLcd.setCursor(0, 0);
  753.   myLcd.print("RUN PANO?       ");
  754.   YesNoArrowDisplay();
  755.   RunResetAction();
  756. } // end function
  757.  
  758.  
  759. // RUN PANORAMA - FRAME 10
  760. void PanoRun()
  761. {
  762.   rowPos = rowStart;
  763.   myLcd.clear();
  764.   myLcd.setCursor(0, 0);
  765.   myLcd.print("Begin pano images");
  766.   delay(1125); // was 1500
  767.   myLcd.setCursor(0, 1);
  768.   myLcd.print("Move to Start");
  769.  
  770.   // move to row start position
  771.   for (int y = 0; y <= rowMoves; y = y + 1)
  772.   {
  773.     rowPosMicros = map(rowPos, 0, 180, rowServoMin, rowServoMax);
  774.     rowServo.writeMicroseconds(rowPosMicros);
  775.     delay(1500); // was 2000
  776.     rowPos = rowPos - rowTravel;
  777.  
  778.     // move to pano start position & begin images
  779.     panoPosDegrees = (panoStart);     // sets the camera position in degrees
  780.     panoPosMicros = map(panoPosDegrees, 0, 180, imageServoMin, imageServoMax);     //change degrees to microseconds (truncated)
  781.     imageServo.writeMicroseconds(panoPosMicros);     // moves camera to start position
  782.     delay(4500); // was 6000
  783.  
  784.     // begin the pano imaging sequence (settle-photo-settle-move)
  785.     x = 0;
  786.     for ( x = 0; x <= cameraMoves; x++) { //
  787.       myLcd.clear();
  788.       myLcd.setCursor(0, 0);
  789.       myLcd.print("Row "); myLcd.print(y + 1); myLcd.print(" of "); myLcd.print(rowCount);
  790.       myLcd.setCursor(0, 1);
  791.       myLcd.print("Image "); myLcd.print(x + 1); myLcd.print(" of "); myLcd.print(imageCount);
  792.  
  793.       panoPosMicros = map(panoPosDegrees, 0, 180, imageServoMin, imageServoMax);     //change degrees to microseconds (truncated)
  794.       imageServo.writeMicroseconds(panoPosMicros);     // move camera to next image stop
  795.       delay(3300);  // settle camera // was 4500
  796.       digitalWrite(12, HIGH);     // shutter on
  797.       delay(75); // was 100
  798.       digitalWrite(12, LOW);     // shutter off
  799.       delay(2250); // was 3000
  800.       panoPosDegrees = (panoPosDegrees + cameraTravel);     // increment to next camera position
  801.     }
  802.   }
  803.   delay(1125); // was 1500
  804.   imageServo.writeMicroseconds(imageServoHome);
  805.   rowServo.write(rowServoHome);
  806.  
  807.   delay(3000); // was 4000
  808.   myLcd.clear();
  809.   myLcd.setCursor(1, 0);
  810.   myLcd.print("PANO COMPLETED!");
  811.   delay(1125); // was 1500
  812.   GoOnArrowDisplay();
  813.  
  814.   if (buttonStateRight = digitalRead(buttonPinRight))
  815.   {
  816.     while (digitalRead(buttonPinRight) == HIGH) {} // wait for right button push
  817.     delay(buttonBounce);
  818.     CurrentFrame = 11;
  819.     myLcd.clear();
  820.   }
  821. } // end function
  822.  
  823.  
  824. //  ANOTHER PANO OR QUIT - FRAME 11
  825. void RunQuit()
  826. {
  827.   myLcd.setCursor(0, 0);
  828.   delay(buttonBounce);
  829.   myLcd.print("Another Pano?   ");
  830.   YesNoArrowDisplay();
  831.   PanoQuitAction();
  832. } // end function
  833.  
  834. // RESET MENU & VARIABLES
  835. void ResetMenu()
  836. {
  837.   Inputs[0] = 50;
  838.   Inputs[1] = 50;
  839.   Inputs[2] = 1;
  840.   camOrient = 'P';
  841.   CurrentFrame = 0; // resets frame count
  842.   myLcd.clear();
  843.   myLcd.print("Resetting       ");
  844.   delay(1125); // was 1500
  845.   InputMenu();
  846. } // end function
  847.  
  848.  
  849. // QUIT PANORAMA AND SHUT DOWN
  850. void  QuitPano()
  851. {
  852.   myLcd.clear();
  853.   myLcd.setCursor(0, 0);
  854.   myLcd.print("Remove camera   ");    // prompt to remove camera before storing camera arm
  855.   delay(3000); // was 4000
  856.   GoOnArrowDisplay();
  857.   RightToContinueAction();
  858.   myLcd.setCursor(0, 0);
  859.   myLcd.print("Stow camera arm ");    // store camera arm in vertical position
  860.   myLcd.setCursor(0, 1);
  861.   myLcd.print("                ");
  862.   rowServo.writeMicroseconds(rowServoMin);
  863.   delay(3000); // was 4000
  864.   GoOnArrowDisplay();
  865.   RightToContinueAction();
  866.   myLcd.clear();
  867.   myLcd.setCursor(0, 0);
  868.   myLcd.print("Remove Power   ");     // prompt to remove power
  869.   myLcd.setCursor(0, 1);
  870.   myLcd.print("Good Bye");
  871.   delay(15000); // no change
  872.   OpeningScreen();
  873.   myLcd.clear();
  874. } // end function
  875.  
  876. /************************************************ OPENING FUNCTIONS ********************************************/
  877.  
  878. void OpeningScreen()
  879. {
  880.   // reset key variables
  881.   Inputs[0] = 50;                     // resets default lens focal length
  882.   Inputs[1] = 50;                     // resets default pano width
  883.   Inputs[2] = 1;                      // resets default number of rows
  884.   camOrient = 'P';                    // resets default camera orientation
  885.   CurrentFrame = 0;                   // resets frame count
  886.   // opening screen
  887.   myLcd.clear();
  888.   myLcd.setCursor(0, 0);
  889.   myLcd.print("PANO-XY 4-BUTTON");
  890.   GoOnArrowDisplay();
  891.   RightToContinueAction();
  892.   myLcd.clear();
  893.   // exercise servos
  894.   CameraHome();
  895. }
  896.  
  897. //HOME CAMERA
  898. void CameraHome()
  899. {
  900.   delay(500); // no change
  901.   myLcd.clear();
  902.   delay(500); // no change
  903.   myLcd.setCursor(0, 0);
  904.   myLcd.print("Exercise Servo");      // exercise servos and return to home position
  905.   myLcd.setCursor(0, 1);
  906.   myLcd.print("& Set Camera");
  907.   delay(1000); // no change
  908.  
  909.   // both servos
  910.   rowPosMicros = map(75, 0, 180, rowServoMin, rowServoMax);
  911.   rowServo.writeMicroseconds(rowPosMicros);
  912.   panoPosMicros = map(75, 0, 180, imageServoMin, imageServoMax);   //change degrees to microseconds (truncated)
  913.   imageServo.writeMicroseconds(panoPosMicros);                     // moves camera to 1st exercise position
  914.   delay(2250); // was 3000
  915.  
  916.   rowPosMicros = map(105, 0, 180, rowServoMin, rowServoMax);
  917.   rowServo.writeMicroseconds(rowPosMicros);
  918.   panoPosMicros = map(105, 0, 180, imageServoMin, imageServoMax);  //change degrees to microseconds (truncated)
  919.   imageServo.writeMicroseconds(panoPosMicros);                     // moves camera to 2nd exercise position
  920.   delay(3300); // was 4500
  921.  
  922.   rowPosMicros = map(90, 0, 180, rowServoMin, rowServoMax);
  923.   rowServo.writeMicroseconds(rowPosMicros);
  924.   panoPosMicros = map(90, 0, 180, imageServoMin, imageServoMax);   //change degrees to microseconds (truncated)
  925.   imageServo.writeMicroseconds(panoPosMicros);                     // moves camera to HOME position
  926.   delay(2700); //was 3500
  927.   myLcd.clear();
  928. } // end function
Advertisement
RAW Paste Data Copied
Advertisement