This is a fantastic video camera! However, to make this webcam work required way too much research time and effort so I thought I would take a few moments to provide my lessons learned with the hope it will help make the lives of other novices, like myself, a little better. This is the easiest way to enjoy excellent live HD video from anywhere in the world from your laptop, Android or iDevice without any service fees.

    The goal of the project was to view live weather conditions from hundreds of miles away. Click this link for a video on how the project turned out: https://vimeo.com/157247877

    Short Falls Of Most Old Tutorials
    Many of the old Raspberry web cam tutorials found on the web were created with older configurations and fell apart as new revisions hit the market that left out key software components, rendering the tutorial useless for today’s projects. Many others explain how to create live video with Local Area Networks (LAN which is restricted inside your home) which is of no use to me. Still others would let you access your web cam over the Wide Area Network (WAN provides access from anywhere in the world) but would disconnect the camera from the web cam when you logged off the computer you were making changes from; this option put your web cam on the same network as your computer somewhere else in the world and shut down the cam when you closed your computer down since it lost the internet connection. Other solutions required Linux be loaded on my laptop but my computer is old and very memory challenged so that was not an option for me.

    Still, others solutions required knowledge that I simply don’t have at the moment but may be “standard operating procedure” for many of you more advanced readers. For example, “simply download and cross compile the software form this link”. I don’t know how to do that and could not find a tutorial to explain it (but I have a hunch it requires Linux on my laptop).

    Now, Create A Live Web Cam Accessible From Anywhere In the World
    The following 3 step solution works great! However, I cannot take credit for any of the technical content of what I am about to provide; that credit goes to the people who spent the time creating the websites referenced. A suggestion would be to open the following links in your Raspberry Pi browser so you can copy and paste most of the commands.

    Step 1. Basic Raspberry Pi 2 Startup
    If you have not done it yet, here is a good video to get the latest upgrades, updates, enable your camera, enable SSH, and more.
    https://www.youtube.com/watch?v=qLo-0Tmmlrc by Peter Oakes

    Step 2. YouTube Live Account
    Create your own YouTube Live account since we will need information from that account later. From your YouTube Live Stream page, get the encoder information provided at the bottom left of the YouTube Live page to enter into your Raspberry launch command later, and later you will see it go live using the Share link also provided at the bottom of the YouTube Live page. This should get you started: https://support.google.com/youtube/answer/2474026?hl=en

    Step 3. Install FFMPEG
    Many tutors on the internet complain that FFMPEG takes 9 hours to download but it only took me a little over an hour and a half (very reasonable to me, just go do something else for 1.5 hours). My Verizon FiOS internet speed is about 50 to 75 Mbps upload and download as a reference. Mr. Mueller’s link worked flawlessly for me and provided good explanations along the way, including much needed definitions of segments of the syntax. Except Mr. Mueller’s actual syntax used to stream to my YouTube Channel was close, but didn’t quite work (perhaps too much for YouTube to handle). Between Mr. Mueller and Schlatter I was able to make it work…These links are provided by Val Mueller and Wolfgang Schlatter.

    Load FFMPEG from Mr. Mueller’s site:
    http://www.valmueller.net/stream-video- … o-youtube/

    But use the syntax command from Mr. Schlatter’s site to launch the video to YouTube Live:
    https://plus.google.com/+wolfgangschlat … L5fRou17AX

    EXCEPT on Mr. Schlatter’s command line, remove the “http://” and the “./” infront of ffmpeg from the command so it looks like this:

    raspivid -o - -t 0 -w 1280 -h 720 -fps 25 -b 4000000 -g 50 | ffmpeg -re -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -f h264 -i - -vcodec copy -acodec aac -ab 128k -g 50 -strict experimental -f flv rtmp://a.rtmp.youtube.com/live2/

    Don’t put the brackets around the words: Your_YouTube_Live_Stream_Name_Key, just cut and paste the long alpha numeric Stream Name Key from your YouTube account and place it right after… live2/.

    Remember to launch this syntax from this directory: cd /usr/src/ffmpeg and you don’t need “sudo” in front of the syntax command to launch the video.

    Once you enter the syntax you should now see live streaming on your YouTube Live account and then be able to view it from anywhere in the world from your YouTube Live “Share” link (from lower right of the Stream Now page)! Note there is about a 17 second delay from what goes on in front of the camera until it goes live, but otherwise you get a clean, crisp picture without a lot of buffering. You don’t need to worry about creating a New Live Event or using any of YouTube’s suggested software. Just launch and enjoy your live view.

    Other Useful Key Items
    You might find it desirable to: 1) Work with your Raspberry Pi desktop with a wireless internet connection, 2) View the Rpi2 desktop on your own laptop rather than another monitor, 3) Create a Static IP so the camera doesn’t stop working when the Dynamic IP changes, 4) Have the ability to turn of the camera light so it doesn’t reflect into the camera in low light conditions, and 5) Make the router changes that allow you to work on the camera from miles away using your Windows Remote Desktop Connection. Here is how to accomplish those items…

    Remote Desktop with Raspberry Pi
    Using the xrdp with Windows Remote Desktop Connection is the best solution. It allows you to view your Raspberry Pi desktop and make changes to your camera from anywhere in the world and not have camera shut down when you close you remote laptop (as happens using other tutorials and free services).
    https://www.jeremymorgan.com/tutorials/ … pberry-pi/

    How To Use Remote Desktop Connection anywhere in the world through the internet!
    Here is how to make changes to your router to accomplish this. Working inside the router sounded complex but the tutorial explained it so well that I could even understand it.
    http://www.circuitbasics.com/access-ras … onnection/

    Create a static IP address for your Raspberry Pi
    Note: Your internet cord plugged in during this process
    https://thepihut.com/blogs/raspberry-pi … spberry-pi

    How to turn off the raspberry pi cam red led light
    At first I would recommend using this tutorial http://thepihut.com/blogs/raspberry-pi- … camera-led
    However, it appears that the latest software version again has disabled this simple command. So my solution is to just resort to a hardware change: simply put a drop of silicone on top of the led 

    Wireless Internet Connection
    From the Raspberry Pi Desktop, just click on the icon of two computers in the upper right hand corner, find your internet from the drop down and enter the password for your internet connection. Then you should see the familiar radial internet signal at which time you can unplug the internet cord.

    Read more of my helpful lessons learned on my Wordpress site (click this link and scroll down to “Additional Lessons Learned” to bypass the redundant information just read above in this RPi forum): http://wp.me/pEL3n-3y.

    Below is the code used to control two stepper motors, two photo resistors and two LED’s to perform the pan/tilt function for the camera. The photo resistors and LED’s are used to optically find home after each reboot (figured this is better on the motors than a hard stop the motors run into and stall). I fashioned a crude pan/tilt assembly that spins one stepper motor on top of another stepper motor with their spin axis 90 degrees apart. I tried to keep the centre of gravity over the lower motor axle as best as practical. A solid thin black plastic shade (with a slit cut in it to allow light to pass) rotates with each axle which separates each photo resistor and LED pair. When the LED light is sensed, home position is established and the pan/tilt routine can start. I used double backed mounting tape to secure the camera to the arm attached to the top

    I would recommend against buying the pan/tilt brackets sold online for $6 since they are rather poor quality and designed for an older motor configuration; making your own is pretty easy and less frustrating than trying to force the purchased unit to work. I am using the 28BYJ-48 5VDC stepper and the supplied circuit board. I found a package of 5 motors for about $14 on Amazon.

    Code: Select all

    1. import RPi.GPIO as gpio # import library RPi.GPIO gpio=use general purpose input output pin names
    2. import time # import time library
    3. PINSh = [27,10,18,23] # variable 'PINS' holds a list of gpio pin numbers
    4. SEQAh = [(27,),(10,),(18,),(23,)]
    5. PINSv = [4,17,22,24] # variable 'PINS' holds a list of gpio pin numbers
    6. SEQAv = [(4,),(17,),(22,),(24,)]
    7. LED_Pinh = 12
    8. LED_Pinv = 26
    9. #gpio.setwarnings(False) # Disable screen print warnings
    10. DELAY = 0.01 # time between motor steps (too small of a number then the motor stalls)
    11. alpha = 140 # horizontal full scale viewing angle in motor counts 128 counts = 360 degrees
    12. beta = 25 # was 15 vertical full scale viewing angle in motor counts 128 counts = 360 degrees
    13. beta2 = 35 # was 26 beta2 must be greater than beta.
    14. adjusth = 10 # compensates horizontal home for packaging errors using motor counts
    15. adjustv = 10 # compensates vertical home for packaging errors using motor counts
    16. timeh = 100 # RCtimeh (how much light is sensed; lower number = more light)
    17. timev = 100 # RCtimev (how much light is sensed; lower number = more light)
    18. gpio.setmode(gpio.BCM) # tells RPi.GPIO we want to use pin names (BCM is the mfg)
    19. for pin in PINSh: # pin is a variable name assigned a new value each loop; PINS is a list
    20. gpio.setup(pin, gpio.OUT) # this says we want to use 'pin' as an output
    21. for pin in PINSv: # pin is a variable name assigned a new value each loop; PINS is a list
    22. gpio.setup(pin, gpio.OUT)
    23. gpio.setup(LED_Pinv, gpio.OUT)
    24. gpio.setup(LED_Pinh, gpio.OUT)
    25. gpio.output(LED_Pinh, False)
    26. gpio.output(LED_Pinv, False)
    27. def stepper(sequence, pins): # def says 'stepper' is the function name (like a variable), then parameters are inside ()
    28. for step in sequence:
    29. for pin in pins:
    30. if pin in step:
    31. gpio.output(pin, gpio.HIGH)
    32. else:
    33. gpio.output(pin, gpio.LOW)
    34. time.sleep(DELAY)
    35. def RCtimeh (PiPinh):
    36. measurementh = 0
    37. gpio.setup(PiPinh, gpio.OUT)
    38. gpio.output(PiPinh, gpio.LOW)
    39. time.sleep(0.02)
    40. gpio.setup(PiPinh, gpio.IN)
    41. while (gpio.input(PiPinh) == gpio.LOW):
    42. measurementh += 1
    43. return measurementh
    44. def RCtimev (PiPinv):
    45. measurementv = 0
    46. gpio.setup(PiPinv, gpio.OUT)
    47. gpio.output(PiPinv, gpio.LOW)
    48. time.sleep(0.02)
    49. gpio.setup(PiPinv, gpio.IN)
    50. while (gpio.input(PiPinv) == gpio.LOW):
    51. measurementv += 1
    52. return measurementv
    53. #gpio.output(LED_Pinh, True)
    54. #gpio.output(LED_Pinv, True)
    55. #time.sleep(30)
    56. #FIND HOME AT POWER UP:
    57. # But first undo the adjustment from the previous 'power up' so it can't start up past the LED position (see pictures of normal operating area of shade).
    58. counter = 0
    59. while counter < adjusth:
    60. stepper(SEQAh[::-1], PINSh)
    61. counter = counter + 1
    62. print "initializing position; counter horizontal = ", counter, "RCtimeh = ", RCtimeh(6)
    63. counter = 0
    64. while counter < adjustv: # Proives adjustment to correct home packaging error glueing photoresistor
    65. stepper(SEQAv, PINSv) # stepper(SEQAv, PINSv) lowers home vertical angle with a positive adjustv factor
    66. counter = counter + 1
    67. print "initializing position; counter vertical = ", counter, "RCtimeh = ", RCtimev(5)
    68. # Now find home:
    69. counter = 0
    70. counterh = 0
    71. gpio.output(LED_Pinh, True) # Key Point: Size photosensor shade to keep left side always in dark
    72. while RCtimeh(6) > timeh: # but position the shade so it will expose the sensor to light when sweeping right.
    73. stepper(SEQAh, PINSh) # otherwise it will get out of sink and wrap the wires up and make a mess of things.
    74. counterh = counterh + 1 # LED provides adequate light for photo resistors to work in low ambient light conditions
    75. print "Finding Horz. Home ", counterh, "RCtimeh = ", RCtimeh(6) # Measure RC timing of photoresistor using only GPIO06 with 3.3VDC and gnd circuit inputs
    76. if RCtimeh(6) < timeh:
    77. print "Horizontal Home found,", " counter", counter, "RCtimeh = ", RCtimeh(6) # Found home horizontally
    78. time.sleep(0.1)
    79. if counterh > alpha * 1.5: # Protects unit from damage hunting past home position; blinking light = needs attention.
    80. #print "Horizonal home out of range"
    81. for _ in range(9999999):
    82. gpio.output(LED_Pinh, True)
    83. time.sleep(0.5)
    84. gpio.output(LED_Pinh, False)
    85. time.sleep(0.5)
    86. gpio.output(LED_Pinh, True)
    87. time.sleep(0.5)
    88. gpio.output(LED_Pinh, False)
    89. time.sleep(5)
    90. while counter < adjusth: # Provides adjustment to correct home packaging error glueing photoresistor
    91. stepper(SEQAh, PINSh)
    92. counter = counter + 1
    93. print "Adjust Horz. Home = ", counter, "RCtimeh = ", RCtimeh(6)
    94. time.sleep(0.1) # Discharge capacitor in photoresistor circuit
    95. gpio.output(LED_Pinh, False) # Turn off LED used by photoresistor
    96. counter = 0
    97. counterv = 0
    98. gpio.output(LED_Pinv, True) # LED provides adequate light for photo resistors to work in low ambient light conditions
    99. while RCtimev(5) > timev: # Key Point: Size photosensor shade to keep left side always in dark
    100. stepper(SEQAv, PINSv) # but position the shade so it will expose the sensor to light when sweeping right.
    101. counterv = counterv + 1 # otherwise it will get out of sink and wrap the wires up and make a mess of things.
    102. print "Finding Vert. Home ", counterv, "RCtimev = ", RCtimev(5) # Measure RC timing of photoresistor using only GPIO06 with 3.3VDC and gnd circuit inputs
    103. if RCtimev(5) < timev:
    104. print "Vert. Home found", " counter", counter, "RCtimev = ", RCtimev(5) # Found home vertically
    105. time.sleep(0.1) # Discharge Capacitor for 0.1 seconds but the 3.9 seconds is viewing time from home position
    106. if counterv > beta * 1.5: # Protects unit from damage hunting past home position; blinking light = needs attention.
    107. for _ in range(9999999):
    108. gpio.output(LED_Pinv, True)
    109. time.sleep(0.5)
    110. gpio.output(LED_Pinv, False)
    111. time.sleep(0.5)
    112. gpio.output(LED_Pinv, True)
    113. time.sleep(0.5)
    114. gpio.output(LED_Pinv, False)
    115. time.sleep(5)
    116. gpio.output(LED_Pinv, False) # Turn off LED used by photoresistor
    117. while counter < adjustv: # Provides vertical adjustment to home position for correction of packaging error glueing photoresistor
    118. stepper(SEQAv[::-1], PINSv)
    119. counter = counter + 1
    120. print "Adjust vertical home = ", counter, "RCtimev = ", RCtimev(5)
    121. time.sleep(0.1) # Discharge capacitor in photoresistor circuit
    122. # CONTINUAL PAN AND TILT OPERATION (box pattern):
    123. try:
    124. while True:
    125. counterh = 0
    126. counterv = 0
    127. for _ in range(beta): # From home position move down full beta
    128. stepper(SEQAv[::-1], PINSv)
    129. counterv = counterv + 1
    130. if counterv == beta:
    131. # print "view"
    132. time.sleep(12)
    133. for _ in range(alpha): # Move to the lower left in 2 horz viewing steps
    134. stepper(SEQAh[::-1], PINSh)
    135. counterh = counterh + 1
    136. # print "Horz R", counterh, "Vert R", counterv
    137. if counterh == alpha / 2:
    138. # print "view"
    139. time.sleep(10)
    140. if counterh == alpha:
    141. # print "view"
    142. time.sleep(10)
    143. for _ in range(beta): # Move up in 1 beta viewing step
    144. stepper(SEQAv, PINSv)
    145. counterv = counterv - 1
    146. # print "Horz R", counterh, "Vert R", counterv
    147. if counterv == 0:
    148. # print "view"
    149. time.sleep(8)
    150. for _ in range(alpha): # Move upper right in 2 horz viewing steps
    151. stepper(SEQAh, PINSh)
    152. counterh = counterh - 1
    153. # print "Horz R", counterh, "Vert R", counterv
    154. if counterh == alpha / 3:
    155. # print "view"
    156. time.sleep(8)
    157. if counterh == alpha * 2 / 3:
    158. # print "view"
    159. time.sleep(8)
    160. if counterh == 0:
    161. # print "view"
    162. time.sleep(8)
    163. # This second pan/tilt circuit looks a little higher in the sky:
    164. for _ in range(beta): # From home position move down full beta
    165. stepper(SEQAv[::-1], PINSv)
    166. counterv = counterv + 1
    167. if counterv == beta:
    168. # print "view"
    169. time.sleep(12)
    170. for _ in range(alpha): # Move to the left in 2 horz viewing steps
    171. stepper(SEQAh[::-1], PINSh)
    172. counterh = counterh + 1
    173. # print "Horz R", counterh, "Vert R", counterv
    174. if counterh == alpha / 2:
    175. # print "view"
    176. time.sleep(10)
    177. if counterh == alpha:
    178. # print "view"
    179. time.sleep(10)
    180. for _ in range(beta2): # Move up in 1 viewing step to the top level one beta2
    181. stepper(SEQAv, PINSv)
    182. counterv = counterv - 1
    183. # print "Vert R", counterv
    184. if counterv == (beta - beta2):
    185. # print "view"
    186. time.sleep(8)
    187. for _ in range(alpha): # Move to top right in 2 horz viewing steps
    188. stepper(SEQAh, PINSh)
    189. counterh = counterh - 1
    190. # print "Horz R", counterh, "Vert R", counterv
    191. if counterh == alpha / 3:
    192. # print "view"
    193. time.sleep(8)
    194. if counterh == alpha * 2 / 3:
    195. # print "view"
    196. time.sleep(8)
    197. if counterh == 0:
    198. # print "view"
    199. time.sleep(8)
    200. for _ in range(beta2-beta): # Move back down to home in one (beta2 - beta) step
    201. stepper(SEQAv[::-1], PINSv)
    202. counterv = counterv + 1
    203. if counterv == 0:
    204. # print "Start again", "Horz R", counterh, "Vert R", counterv
    205. # print "view"
    206. time.sleep(10)
    207. except KeyboardInterrupt:
    208. gpio.cleanup() # Puts GPIO pins to LOW so you don't damage board with shorts