{"id":381,"date":"2014-11-03T19:42:23","date_gmt":"2014-11-03T13:42:23","guid":{"rendered":"http:\/\/markwheeler.com\/wordpress\/?p=381"},"modified":"2014-11-03T19:42:23","modified_gmt":"2014-11-03T13:42:23","slug":"diy-arduino-timelapse-panner-for-gopro","status":"publish","type":"post","link":"https:\/\/www.markwheeler.com\/?p=381","title":{"rendered":"DIY Arduino TimeLapse Panner for GoPro"},"content":{"rendered":"<p>Code updated: 02\/23\/2018 for bug fixes.<\/p>\n<p><a href=\"http:\/\/markwheeler.com\/wordpress\/wp-content\/uploads\/2014\/11\/DIYTP_Finished.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-medium wp-image-382\" src=\"http:\/\/markwheeler.com\/wordpress\/wp-content\/uploads\/2014\/11\/DIYTP_Finished-203x300.jpg\" alt=\"DIYTP_Finished\" width=\"203\" height=\"300\" \/><\/a><\/p>\n<p>I needed to create a panner that would make 1 rotation over 5 minutes.<\/p>\n<p>I discovered two other projects to base mine on. Construction is pretty much the same as the source projects below.<\/p>\n<p>I rewrote some of the code. My TimeLapse Panner prompts for # of Rotations and Duration in minutes<\/p>\n<p>You may need to update your <a href=\"https:\/\/github.com\/PaulStoffregen\/Time\" target=\"_new\" rel=\"noopener\">Time libraries<\/a>. <\/p>\n<p>Project Sources<br \/>\n<a href=\"http:\/\/www.instructables.com\/id\/Timelapse-Panning-controller-for-GoPro-Cameras\/?ALLSTEPS\">Time_Lapse_Panner<\/a><br \/>\n<a href=\"http:\/\/www.bethnchris.com\/wp-content\/uploads\/2014\/01\/Time_Lapse_Panner_PUBLIC_v2.zip\">Time_Lapse_Panner_PUBLIC_v2<\/a><br \/>\n<br clear=\"all\" \/><br \/>\n<strong>Here are a list of Parts from V2<\/strong>.<\/p>\n<p><a href=\"http:\/\/www.servocity.com\">Servocity<\/a><\/p>\n<p>1 (<a href=\"http:\/\/www.servocity.com\/html\/servo_power_gearbox_arms.html\">SG804A<\/a> &#8211; 4 inch Gearbox Arm<br \/>\n3 (<a href=\"http:\/\/www.servocity.com\/html\/flanged_ball_bearings.html\">535044<\/a> &#8211; .250 inch ID x .500 inch OD Flanged Ball Bearing<br \/>\n* I found this at <a href=\"https:\/\/www.sparkfun.com\/\">SparkFun<\/a><br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/1_4__preicision_d-shafting.html\">634074<\/a>) 1\/4 inch x 2.500 inch D-Shaft<br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/0_770__clamping_hubs.html\">545588<\/a>) (06.11.03) 1\/4 inch Bore Clamping Hub<br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/32_pitch_acetal_hub_gears__3_1.html\">RHA32-36-84<\/a>) 84 Tooth, 32 Pitch Hub Gear (3\/16 inch Face)<br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/channel_bracket_a__585484_.html\">585484<\/a>) (03.11.03) 90 Degree Channel Bracket A<br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/attachment_blocks.html\">585400<\/a>) (09.12.02) Attachment Blocks (12 pack)<br \/>\n* I did not use these.<br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/flat_single_channel_bracket__5.html\">585468<\/a>) (04.11.01) Flat Single Channel Bracket<br \/>\n* I did not use this.<br \/>\n1 (<a href=\"http:\/\/www.servocity.com\/html\/abs_sheets.html\">ABS250-625-725<\/a>) 6.25 inch x 7.25 inch ABS Sheet (1\/4 inch Thick)<br \/>\n* I used .220 thick Acrylic sheet from HomeDepot.<br \/>\n4 (<a href=\"http:\/\/www.servocity.com\/html\/6-32_aluminum_standoffs__round.html\">534-1857<\/a>) 6-32x 2.50 inch Aluminum Standoffs (Round)<br \/>\n* I did not use these. I used 4 x 6-32 3-inch bolts.<\/p>\n<p>EBAY<br \/>\n1 <a href=\"http:\/\/www.ebay.com\/sch\/uln2003%205v%20stepper%20motor\">ULN2003 5v stepper motor<\/a><br \/>\n1 <a href=\"http:\/\/www.ebay.com\/itm\/330755920098?ssPageName=STRK:MEWNX:IT&amp;amp;amp;amp;_trksid=p3984.m1439.l2649\">Axial Pinion Gear 32P 12T Steel 5mm Motor Shaft AX30838 NIB<\/a><\/p>\n<p>HomeDepot<br \/>\nMisc 6-32 flat head screws and bolts (I used 1\/2 lengths)<\/p>\n<p>Amazon<br \/>\n1 <a href=\"http:\/\/www.amazon.com\/gp\/product\/B0076FWAH8\/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B0076FWAH8&amp;linkCode=as2&amp;tag=markwheelercom&amp;linkId=FW3GPEHE5JGSRWXG&quot;\">SainSmart LCD 1602 Keypad Shield with Mega 2560 Arduino board<\/a><br \/>\n* The Mega board is probably overkill for this project.<\/p>\n<p><span style=\"color: #000000;\"><strong>Video<\/strong><\/span><\/p>\n<p><iframe loading=\"lazy\" src=\"\/\/www.youtube.com\/embed\/x0CIUuFZv-M\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p><span style=\"color: #000000;\"><strong>Wiring Diagram<\/strong><\/span><\/p>\n<p><a href=\"http:\/\/markwheeler.com\/wordpress\/wp-content\/uploads\/2014\/11\/Wiring.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-medium wp-image-386\" src=\"http:\/\/markwheeler.com\/wordpress\/wp-content\/uploads\/2014\/11\/Wiring-260x300.png\" alt=\"Wiring\" width=\"260\" height=\"300\" \/><\/a><br clear=\"all\"><\/p>\n<p><span style=\"color: #000000;\"><strong>Sketch Code<\/strong><\/span><br \/>\n<code><br \/>\n\/\/ http:\/\/markwheeler.com\/wordpress\/?p=381 <\/p>\n<p>#include &lt;LiquidCrystal.h&gt;<br \/>\n#include &lt;Stepper.h&gt;<br \/>\n#include &lt;TimeLib.h&gt; \/\/ Updates 2\/23\/2018<br \/>\n#define STEPS  2048   \/\/Number of steps per revolution<\/p>\n<p>LiquidCrystal lcd(8, 9, 4, 5, 6, 7);<br \/>\nStepper small_stepper(STEPS, 1, 3, 2, 12);<br \/>\nint lcd_key     = 0;<br \/>\nint adc_key_in  = 0;<br \/>\nint endStep = 1;<br \/>\nint startPos = 0;<br \/>\nint curPos = 0;<br \/>\nfloat endPos = 14333;<br \/>\nint minutes = 0; \/\/ Duration<br \/>\nint endtime = 0;<br \/>\nint timeNow = 0;<br \/>\nfloat rotations = 0; \/\/ How many rotations?<br \/>\nfloat runtime = 0;<br \/>\nfloat span = 0;<br \/>\nfloat stepDelay = 0;<br \/>\nfloat spanRemain = 0;<br \/>\nint motorPWR = 15; \/\/ was 13<br \/>\nint time = 0; \/\/ clock holder<br \/>\nint runlength = 0;<br \/>\nint countdown = 10; \/\/ Seconds until program runs<\/p>\n<p>#define btnRIGHT  0<br \/>\n#define btnUP     1<br \/>\n#define btnDOWN   2<br \/>\n#define btnLEFT   3<br \/>\n#define btnSELECT 4<br \/>\n#define btnNONE   5<\/p>\n<p>int read_LCD_buttons()<br \/>\n{<br \/>\n adc_key_in = analogRead(0);      \/\/ read the value from the sensor<br \/>\n \/\/ my buttons when read are centered at these valies: 0, 144, 329, 504, 741<br \/>\n \/\/ we add approx 50 to those values and check to see if we are close<br \/>\n if (adc_key_in > 1000) return btnNONE; \/\/ We make this the 1st option for speed reasons since it will be the most likely result<br \/>\n \/\/ For V1.1 us this threshold<br \/>\n if (adc_key_in < 50)   return btnRIGHT;  \n if (adc_key_in < 250)  return btnUP; \n if (adc_key_in < 450)  return btnDOWN; \n if (adc_key_in < 650)  return btnLEFT; \n if (adc_key_in < 850)  return btnSELECT;  \n  \n return btnNONE;  \/\/ when all others fail, return this...\n}\n\nvoid setup(){\nlcd.begin (16,2);\npinMode(motorPWR, OUTPUT);\n  \n}\n\nvoid loop(){\n  digitalWrite(motorPWR, HIGH);\n    while(endStep){\n      \/\/ I do this for no reason.\n    lcd.setCursor(0,0);\n    lcd.print(\"TimeLapse Panner\");\n    lcd.setCursor(0,1);\n    lcd.print(\"v3.11282014\");\n    delay(2000);\n    time_t timeNow = now(); \/\/ What time is it right now?\n     endStep = 0;\n  \n  }\n  endStep = 1; \/\/ Ask for Rotations\n  lcd.setCursor(0,0);\n  lcd.print(\"Rotations:      \");\n  lcd.setCursor(0,1);\n  lcd.print(\"(L\/R) then SEL\");\n\n  \n\n  while(endStep){\n     lcd_key = read_LCD_buttons();  \/\/ read the buttons\n     switch (lcd_key)               \/\/ depending on which button was pushed, we perform an action\n     {\n       case btnRIGHT:\n       {\n         \n          rotations = rotations + 1;           \n   \n         lcd.setCursor(0,1);\n         lcd.print(\"Rotations:     \");\n         lcd.setCursor(11,1);\n         lcd.print(rotations);\n         delay(175);\n         break;\n       }\n     case btnLEFT:\n       {\n    \n          rotations = rotations - 1;           \n         \n\n         lcd.setCursor(0,1);\n         lcd.print(\"Rotations:     \");\n         lcd.setCursor(11,1);\n         lcd.print(rotations);\n         delay(175);\n         break;\n       }\n       case btnSELECT:\n       {\n         endStep = 0;\n         delay(175);\n         break;\n       }\n         case btnNONE:\n       {\n         break;\n       }\n     }\n  }\n  endStep = 1;\n  \/\/ Ask for Duration\n  lcd.setCursor(0,0);\n  lcd.print(\"Duration:   \");\n  lcd.setCursor(0,1);\n  lcd.print(\"(L\/R) then SEL\");\n\n  while(endStep){\n     lcd_key = read_LCD_buttons();  \/\/ read the buttons\n     switch (lcd_key)               \/\/ depending on which button was pushed, we perform an action\n     {\n       case btnRIGHT:\n       {\n          minutes = minutes + 1;\n         \n         lcd.setCursor(0,1);\n         lcd.print(\"Minutes:      \");\n         lcd.setCursor(11,1);\n         lcd.print(minutes);\n         delay(175);\n         break;\n       }\n     case btnLEFT:\n       {\n           minutes = minutes - 1;\n       \n         lcd.setCursor(0,1);\n         lcd.print(\"Minutes:      \");\n         lcd.setCursor(11,1);\n         lcd.print(minutes);\n         delay(175);\n         break;\n       }\n       case btnSELECT:\n       {\n\n          endStep = 0;\n   \/\/ Countdown\n        while (countdown) {\n         lcd.clear();\n         lcd.setCursor(0,1);\n         lcd.print(\"Countdown:      \");\n         lcd.setCursor(12,1);\n         lcd.print(countdown);\n         delay (1000);\n         countdown = countdown - 1;\n       }\n         delay(150);\n         break;\n       }\n         case btnNONE:\n       {\n         break;\n       }\n     }\n  }\n\n\n  \n\n  runtime = (minutes * 60000);\n\n  lcd.setCursor(0,0); \n  lcd.print(\"Rot \");\n  lcd.print(rotations);\n  lcd.print(\"x - \");\n  lcd.print(minutes);\n  lcd.print(\"mins\");\n  lcd.setCursor(0,1);\n  lcd.print(\"       secs left\");\n\n  if (rotations > 0) {<br \/>\n    span = (endPos * rotations) - curPos;<br \/>\n    spanRemain = span;<br \/>\n    stepDelay = (runtime \/ span);<br \/>\n    \/\/ small_stepper.step(span * -1);<br \/>\n    while (spanRemain) {<br \/>\n      \/\/ small_stepper.step(1); \/\/ Counterclockwise<br \/>\n      small_stepper.step(-1); \/\/ Clockwise<\/p>\n<p>      runtime = (runtime - stepDelay);<br \/>\n      \/\/ test for seconds left length<br \/>\n      runlength = ((runtime \/ 1000) + 1);<br \/>\n     if (runlength >= 100) {<br \/>\n      lcd.setCursor(0,1);<br \/>\n     } if (runlength >= 10 and runlength <= 99) {\n       lcd.setCursor(0,1);\n       lcd.print(\" \");\n       lcd.setCursor(1,1);\n     } else {\n     lcd.setCursor(0,1);\n       lcd.print(\"  \");\n       lcd.setCursor(2,1);\n     }\n     \n      lcd.print((runtime \/ 1000) + 1  );\n   \/\/   time = millis();\n   \/\/   lcd.print( ( (minutes*60000) - (time) ) \/ 1000); \/\/ Not totally accurate. Fix me.\n   \/\/   lcd.print(endtime - second(now()));\n        \n      spanRemain--;\n      \/\/ curPos = curPos + 1;\n      delay(stepDelay);\n    }\n  rotations = rotations - 1;\n }\n \n  endStep = 0;\n  while(1){\n    lcd.setCursor(0,0);\n    lcd.print(\"                \");\n    lcd.setCursor(0,1);\n    lcd.print(\"Program Complete\");\n    delay(500);\n    lcd.setCursor(0,0);\n    lcd.print(\"Program Complete\");\n    lcd.setCursor(0,1);\n    lcd.print(\"                \");\n    delay(500);\n  }\n\n}\n  \n<\/code><br \/>\nDownload <a href=\"http:\/\/www.markwheeler.com\/binaries\/Time_Lapse_Panner_V3.zip\">Time_Lapse_Panner_v3.zip<\/a><\/p>\n<p>\n<script async src=\"\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js\"><\/script><br \/>\n<!-- BlogPost --><br \/>\n<ins class=\"adsbygoogle\"\n     style=\"display:inline-block;width:728px;height:90px\"\n     data-ad-client=\"ca-pub-8044093881751830\"\n     data-ad-slot=\"2275850500\"><\/ins><br \/>\n<script>\n(adsbygoogle = window.adsbygoogle || []).push({});\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Code updated: 02\/23\/2018 for bug fixes. I needed to create a panner that would make 1 rotation over 5 minutes. I discovered two other projects to base mine on. Construction is pretty much the same as the source projects below. I rewrote some of the code. My TimeLapse Panner prompts [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[14,2,4,8],"tags":[24,52,114],"class_list":["post-381","post","type-post","status-publish","format-standard","hentry","category-arduino","category-computer","category-hardware","category-projects","tag-arduino","tag-gopro","tag-timelapse-panner"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=\/wp\/v2\/posts\/381","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=381"}],"version-history":[{"count":0,"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=\/wp\/v2\/posts\/381\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=381"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=381"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=381"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}