Introduction: Raspberry Pi Cam Pan-Tilt Control Over Local Internet

On previous tutorials we explored:

How to stream to the internet a video captured by a camera: VIDEO STREAMING Spider web SERVER

and,

How to position a photographic camera (or anything) using: PAN-TILT MULTI SERVO CONTROL

In this tutorial, we will combine what nosotros have learned before, controlling our photographic camera position thru internet, equally shown in the example:

The in a higher place gif shows the camera controlled by buttons, pre-programmed with fixed Pan/Tilt angles. In this tutorial, nosotros will besides explore other alternatives to control the photographic camera position thru internet.

Below the block diagram of our project:

Step 1: BoM - Neb of Material

    Principal parts:

    1. Raspberry Pi V3 - U.s.a.$ 32.00
    2. 5 Megapixels 1080p Sensor OV5647 Mini Photographic camera Video Module - US$ 13.00
    3. TowerPro SG90 9G 180 degrees Micro Servo (2 Ten)- The states$ 4.00
    4. Mini Pan/Tilt Camera Platform Anti-Vibration Camera Mount w/ 2 Servos (*) - United states$ viii.00
    5. Resistor 1K ohm (2X) - Optional
    6. Miscellaneous: metal parts, bands, etc (in instance you volition construct your Pan/Tilt mechanism)

    (*) you tin purchase a complete Pan/Tilt platform with the servos or build your own.

    Step two: Installing the PiCam

    one. With your RPi turned-off, install the Camara on its special port as shown below:

    2. Plough on your Pi and go to Raspberry Pi Configuration Tool at principal menu and verify if Camera Interface is enabled:

    If you needed to Enabled information technology, press [OK] and reboot your Pi.

    Make a simple test to verify if everything is OK:

    raspistill -o /Desktop/image.png            

    You volition realize that an image icon appears on your Rpi desktop. Click on it to open up. If an prototype appears, your Pi is ready to stream video! If you want to know more than about the camera, visit the link: Getting started with picamera.

    Footstep 3: Instaling Flask

    There are several ways to stream video. The all-time (and "lighther") way to do it that I found was with Flask, as adult by Miguel Grinberg. For a detailed explanation about how Flask does this, delight see his bully tutorial: flask-video-streaming-revisited.

    On my tutorial: Python WebServer With Flask and Raspberry Pi, we learned in more details how Flask works and how to implement a web-server to capture information from sensors and prove their status on a spider web folio. Here, on the first role of this tutorial, we will exercise the same, only that the data to exist sent to our front cease, will exist a video stream.

    Creating a spider web-server environment:

    The first affair to do is to install Flask on your Raspberry Pi. If you practise non have it yet, become to the Pi Last and enter:

    sudo apt-go install python3-flask            

    The best when you start a new projection is to create a folder where to accept your files organized. For case:

    from habitation, go to your working directory:

    cd Documents

    Create a new folder, for example:

    mkdir camWebServer

    The above command will create a folder named "camWebServer", where we will salve our python scripts:

    /habitation/pi/Documents/camWebServer

    Now, on this binder, let's create 2 sub-folders: static for CSS and eventually JavaScript files and templates for HTML files. Go to your newer created folder:

    cd camWebServer

    And create the ii new sub-folders:

    mkdir static            

    and

    mkdir templates            

    The final directory "tree", will look like:

    ├── Documents        ├── camWebServer                ├── templates                └── static

    OK! With our environment in place allow's create our Python WebServer Application to stream video.

    Step 4: Creating the Video Streaming Server

    Beginning, download Miguel Grinberg'south picamera parcel: camera_pi.py and relieve it on created directory camWebServer. This is the heart of our project, Miguel did a fantastic job!

    Now, using Flask, allow's change the original Miguel's spider web Server application (app.py), creating a specific python script to render our video. We will telephone call information technology appCam.py:

    from flask import Flask, render_template, Response  # Raspberry Pi photographic camera module (requires picamera package, developed by Miguel Grinberg) from camera_pi import Camera  app = Flask(__name__)  @app.route('/') def index():     """Video streaming dwelling house page."""     render render_template('index.html')  def gen(camera):     """Video streaming generator function."""     while Truthful:         frame = camera.get_frame()         yield (b'--frame\r\n'                b'Content-Type: paradigm/jpeg\r\n\r\north' + frame + b'\r\n')  @app.route('/video_feed') def video_feed():     """Video streaming route. Put this in the src attribute of an img tag."""     render Response(gen(Camera()),                     mimetype='multipart/10-mixed-supersede; boundary=frame')  if __name__ == '__main__':     app.run(host='0.0.0.0', port =80, debug=True, threaded=Truthful)            

    The in a higher place script streams your camera video on an index.html folio as below:

    <html>   <head>     <title>MJRoBot Lab Live Streaming</title>     <link rel="stylesheet" href='../static/style.css'/>   </caput>   <torso>     <h1>MJRoBot Lab Live Streaming</h1>     <h3><img src="{{ url_for('video_feed') }}" width="90%"></h3>     <hour>     <p> @2018 Developed by MJRoBot.org</p>   </body> </html>            

    The most important line of index.html is:

    <img src="{{ url_for('video_feed') }}" width="fifty%">            

    There is where the video will be "feed" to our spider web page.

    You must too include the way.css file on the static directory to go the to a higher place result in terms of manner.

    All the files can be downloaded from my GitHub: camWebServer

    Simply to be sure that everything is in the right location, let's cheque our environment later on all updates:

    ├── Documents        └── camWebServer                ├── camera_pi.py                ├── appCam.py                ├── templates                |     └── index.html                └── static                      └── style.css            

    At present, run the python script on the Terminal:

    sudo python3 appCam.py

    Become to whatsoever browser in your network and enter with http://YOUR_RPI_IP (for example, in my case: x.0.1.27)

    NOTE: If you are not sure almost your RPi Ip address, run on your terminal:

    ifconfig            

    at wlan0: section you will find it.

    The results:

    That'southward it! From at present information technology is only a matter to sophisticate a page, embedded your video on some other page etc.

    Step 5: The Pan Tilt Mechanism

    Now that we have the camera working and our Flask WebServer streaming its video, let's install our Pan/tilt mechanism to position the camera remotely.

    For details, please visit my tutorial: Pan-Tilt-Multi-Servo-Control

    The servos should be connected to an external 5V supply, having their data pivot (in my instance, their yellow wiring) connect to Raspberry Pi GPIO as below:

    • GPIO 17 ==> Tilt Servo
    • GPIO 27 ==> Pan Servo

    Exercise not forget to connect the GNDs together ==> Raspberry Pi - Servos - External Power Supply)

    You can accept equally an pick, a resistor of 1K ohm in serie, between Raspberry Pi GPIO and Server data input pin. This would protect your RPi in instance of a servo trouble.

    Let's too use the opportunity and examination our servos inside our Virtual Python Environment.

    Allow's use Python script to execute some tests with our drivers:

    from time import slumber import RPi.GPIO equally GPIO GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)  def setServoAngle(servo, angle): 	pwm = GPIO.PWM(servo, l) 	pwm.start(8) 	dutyCycle = angle / 18. + 3. 	pwm.ChangeDutyCycle(dutyCycle) 	sleep(0.3) 	pwm.cease()  if __name__ == '__main__': 	import sys 	servo = int(sys.argv[ane]) 	GPIO.setup(servo, GPIO.OUT) 	setServoAngle(servo, int(sys.argv[2])) 	GPIO.cleanup()            

    The core of above lawmaking is the part setServoAngle(servo, angle). This function receives equally arguments, a servo GPIO number, and an angle value to where the servo must be positioned. In one case the input of this office is "bending", we must convert it to an equivalent duty bicycle.

    To execute the script, you lot must enter equally parameters, servo GPIO, and angle.

    For example:

    sudo python angleServoCtrl.py 17 45

    The above control will position the servo connected on GPIO 17 ("tilt") with 45 degrees in "meridian". A similar control could be used for Pan Servo control (position to 45 degrees in "azimuth":

    sudo python angleServoCtrl.py 27 45

    The file angleServoCtrl.py can be downloaded from my GitHub

    Pace half-dozen: Controlling Photographic camera Position Via Web - Using Buttons

    Allow'south kickoff creating a new directory calling information technology:

    mkdir PanTiltControl1

    On this directory we should have the following environs and files:

    ├── Documents        └── PanTiltControl1                ├── camera_pi.py 	       ├── angleServoCtrl.py                ├── appCamPanTilt1.py                ├── templates                |     └── index.html                └── static                      └── style.css            

    The file camera_pi.py is Miguel's script and angleServoCtrl.py, both used before. You can download both from my GitHub, clicking on contributor links.

    At present we need the appCamPanTilt1.py, the index.html and way.css. You can download those files from my GitHub, clicking on correspondent links. Pay attending to its right position on your directory.

    Allow's see the index.html:

    <html>   <head>     <title>MJRoBot Lab Live Streaming</title>     <link rel="stylesheet" href='../static/style.css'/>   </caput>   <body>     <h1>MJRoBot Lab Live Streaming</h1>     <h3><img src="{{ url_for('video_feed') }}" width="80%"></h3> 	<hr> 	<h4> PAN:   		<a href="/pan/30"course="button">30</a> 		<a href="/pan/45"course="button">45</a> 		<a href="/pan/60"class="push">60</a> 		<a href="/pan/75"form="push">75</a> 		<a href="/pan/90"grade="button">90</a> 		<a href="/pan/105"form="button">105</a> 		<a href="/pan/120"form="button">120</a> 		<a href="/pan/135"class="push">135</a> 		<a href="/pan/150"form="push button">150</a> 		==> Angle: [ {{ panServoAngle }} ] 	</h4> 		<h4> TILT:  		<a href="/tilt/30"form="button">thirty</a> 		<a href="/tilt/45"grade="button">45</a>		 		<a href="/tilt/60"class="button">60</a> 		<a href="/tilt/75"grade="button">75</a>		 		<a href="/tilt/xc"course="push button">ninety</a> 		<a href="/tilt/105"class="button">105</a>		 		<a href="/tilt/120"class="button">120</a> 		<a href="/tilt/135"class="button">135</a>		 		<a href="/tilt/150"class="push button">150</a> 		==> Angle: [ {{ tiltServoAngle }} ] 	</h4> 	<hr> 	<p> @2018 Developed by MJRoBot.org</p>   </body> </html>            

    The index.html was created from the previous file, used when nosotros streamed our video. The new bunch of lines on this new file is related to each one of the buttons that appear on the page.

    Let's analyze one of them:

    <a href="/pan/30"course="push button">thirty</a>            

    This is a uncomplicated HTML hyperlink TAG, that we accept styled as a push (the button style is described in style.css). When we click on this link, we generate a "GET /<servo>/<angle>", where <servo> is "pan" and <angle> is "30 degrees". Those parameters will be passed to the Web Server App (appCamPanTilt1.py).

    Permit's see this part of code on appCamPanTilt1.py:

    @app.route("/<servo>/<bending>") def motility(servo, angle): 	global panServoAngle 	global tiltServoAngle 	if servo == 'pan': 		panServoAngle = int(angle) 		bone.system("python3 angleServoCtrl.py " + str(panPin) + " " + str(panServoAngle)) 	if servo == 'tilt': 		tiltServoAngle = int(bending) 		os.system("python3 angleServoCtrl.py " + str(tiltPin) + " " + str(tiltServoAngle)) 	 	templateData = {       'panServoAngle'	: panServoAngle,       'tiltServoAngle'	: tiltServoAngle 	} 	render render_template('index.html', **templateData)            

    In this instance, "servo" is equal to "pan", and the 2 lines beneath will be executed:

    panServoAngle = int(bending) os.system("python3 angleServoCtrl.py " + str(panPin) + " " + str(panServoAngle))            

    What we are doing hither is the same as nosotros did when we tested the servo position on Pi Last. PanPin volition be translated by "27" and panServoAngle to "30". The app volition generate the command:

    python3 angleServoCtrl 27 30
    Note that we practise not demand utilise "sudo" in this case, because the app was already started using "sudo".

    The video shows the projection working and how the Go requests announced on Pi Terminal:

    Stride 7: Using Incremental - Decremental Angle Buttons

    Sometimes what we just need is a few buttons to movement our servos in steps:

    • Pan: Left / Right
    • Tilt: Up / Down

    We can also utilise +/- buttons (Incremental - decremental angle), your choice. Permit's create a new directory:

    mkdir PanTiltControl2

    On this directory we should accept the following environment and files:

    ├── Documents        └── PanTiltControl2                ├── camera_pi.py 	       ├── angleServoCtrl.py                ├── appCamPanTilt2.py                ├── templates                |     └── index.html                └── static                      └── style.css            

    The files camera_pi.py and angleServoCtrl.py are the aforementioned used before. You can download both from my GitHub, clicking on correspondent links or use the ones that you lot have downloaded before.

    Now we need the appCamPanTilt2.py, the index.html and fashion.css. You can download those files from my GitHub, clicking on correspondent links. Pay attention to its right position on your directory.

    Let'due south see the NEW alphabetize.html:

    <html>   <caput>     <title>MJRoBot Lab Live Streaming</title>     <link rel="stylesheet" href='../static/style.css'/>   </head>   <torso>     <h1>MJRoBot Lab Live Streaming</h1>     <h3><img src="{{ url_for('video_feed') }}" width="80%"></h3> 	<hr> 	<h4> PAN Angle: <a href="/pan/-"grade="button">-</a> [ {{ panServoAngle }} ] <a href="/pan/+"class="button">+</a> </h4> 	<h4> TILT Angle: <a href="/tilt/-"grade="button">-</a> [ {{ tiltServoAngle }} ] <a href="/tilt/+"class="button">+</a> </h4>  	<hr> 	<p> @2018 Adult past MJRoBot.org</p>   </body> </html>            

    The index.html is very similar to the previous one. The bunch of lines used on the last index.html was replaced by just 2 lines, where we will only have at present four buttons Pan [+], Pan [-], Tilt [+] and Tilt [-].

    Let'due south analyze i of the 4 buttons:

    <a href="/pan/-"grade="button">-</a>            

    This is likewise a unproblematic HTML hyperlink TAG, that nosotros have styled every bit a button (the push style is described in style.css). When we click on this link, nosotros generate a "GET /<servo>/<Increase or decrement angle>", where <servo> is "pan" and <-> is "decrease angle". Those parameters will be passed to the Spider web Server App (appCamPanTilt2.py).

    Let'southward see this part of code on appCamPanTilt2.py:

    @app.road("/<servo>/<angle>") def move(servo, bending): 	global panServoAngle 	global tiltServoAngle 	if servo == 'pan': 		if bending == '+': 			panServoAngle = panServoAngle + x 		else: 			panServoAngle = panServoAngle - 10 		os.system("python3 angleServoCtrl.py " + str(panPin) + " " + str(panServoAngle)) 	if servo == 'tilt': 		if angle == '+': 			tiltServoAngle = tiltServoAngle + 10 		else: 			tiltServoAngle = tiltServoAngle - 10 		os.system("python3 angleServoCtrl.py " + str(tiltPin) + " " + str(tiltServoAngle)) 	 	templateData = {       'panServoAngle'	: panServoAngle,       'tiltServoAngle'	: tiltServoAngle 	} 	return render_template('index.html', **templateData)            

    In this example, "servo" is equal to "pan", the lines below will be executed:

    if bending == '+': 	panServoAngle = panServoAngle + 10 else: 	panServoAngle = panServoAngle - 10 os.system("python3 angleServoCtrl.py " + str(panPin) + " " + str(panServoAngle))            

    Once the "angle" is equal to "-", nosotros will decrease x from panServoAngle and pass this parameter to our command. Suppose that the actualpanServoAngle is 90. The new parameter will be 80.

    So, PanPin volition be translated by "27" and panServoAngle to "80". The app will generate the command:

    python3 angleServoCtrl 27 80
    Note that we do not need utilize "sudo" in this case, because the app was already started using "sudo".

    The gif shows the webpage working :

    Step 8: Using "POST" Approach

    Sometimes could be interesting to send specific angle commands like:

    • Pan Angle ==> 35 degrees
    • Tilt Angle ==> 107 degrees

    What means that or you will ascertain your increase to "1" on the terminal pace, what will take a lot of time to achieve the required position, or you create a Post from your webpage. Let's explore this concluding possibility.

    Let's once again create a new directory:

    mkdir PanTiltControl3

    On this directory we should accept the following surround and files:

    ├── Documents        └── PanTiltControl3                ├── camera_pi.py 	       ├── angleServoCtrl.py                ├── appCamPanTilt3.py                ├── templates                |     └── index.html                └── static                      └── manner.css            

    The files camera_pi.py and angleServoCtrl.py are the same used before. You lot can download both from my GitHub, clicking on contributor links or apply the ones that you have downloaded before.

    Now we need the appCamPanTilt3.py, the index.html and fashion.css. Yous can download those files from my GitHub, clicking on correspondent links. Pay attending to its correct position on your directory.

    Let's run across the NEW alphabetize.html:

    <html>   <head>     <title>MJRoBot Lab Live Streaming</title>     <link rel="stylesheet" href='../static/style.css'/>   </head>   <body>     <h1>MJRoBot Lab Live Streaming</h1>     <h3><img src="{{ url_for('video_feed') }}" width="fourscore%"></h3>     <p> Enter Pan Tilt Servo Angle: 	<grade method="POST"> 		PAN:  <input type="text" proper noun="panServoAngle" value= {{panServoAngle}} size="3"> 		TILT: <input type="text" name="tiltServoAngle" value= {{tiltServoAngle}} size="three"> 		<input type="submit"> 	</grade>    </p>    <hr> 	<p> @2018 Developed by MJRoBot.org</p>   </trunk> </html>            

    The index.html now is a niggling bit different from the previous one. We will create here a "Grade", which method will be POST. An HTML form input TAG, will be used to pass as parameters the Pan/Tilt bending values digited by users. Those parameters will be passed to the Web Server App (appCamPanTilt3.py) when the push "submit" is pressed.

    Allow's come across this function of code on appCamPanTilt3.py:

    @app.route('/', methods=['POST']) def my_form_post(): 	global panServoAngle 	global tiltServoAngle  	panNewAngle = int(asking.grade['panServoAngle']) 	if (panNewAngle != panServoAngle): 		panServoAngle = panNewAngle 		bone.organization("python3 angleServoCtrl.py " + str(panPin) + " " + str(panServoAngle))  	tiltNewAngle = int(request.form['tiltServoAngle']) 	if (tiltNewAngle != tiltServoAngle): 		tiltServoAngle = tiltNewAngle 		bone.system("python3 angleServoCtrl.py " + str(tiltPin) + " " + str(tiltServoAngle))  	templateData = {       'panServoAngle'	: panServoAngle,       'tiltServoAngle'	: tiltServoAngle 	} 	return render_template('index.html', **templateData)

    What we volition practise is to check which bending was changed generating the contributor control like what were washed before.

    Step 9: Conclusion

    As always, I hope this project tin can help others observe their way into the heady world of electronics!

    For details and final code, delight visit my GitHub depository: WebCam-Pan-Tilt-Control-via-Flask

    For more projects, please visit my weblog: MJRoBot.org

    Below a glimpse of my side by side tutorial, where we will explore how to command our Pan-Tilt, but non with buttons, only with our face! ;-)

    Saludos from the south of the world!

    See you in my adjacent instructable!

    Give thanks y'all,

    Marcelo

    Exist the Beginning to Share

    Recommendations