We will learn in this tutorial how to control the webcam using a servo motor and the raspberry pi.
Our goal is to follow an object with the webcam which is moved by the servo motor like in the image below.

In this tutorial I will cover only the Opencv and Python part, but not the technical side about configuring and using the servo motor.
Keep in mind that to run the servo motor with the raspberry pi you need an extra board (like the one on the image below).

The important thing to know is that the characteristic of the servo motor I’m using is that moves with an angle of 180 degrees and we simply need to give the angle to the servo to move.
On the lines 1 and 2 we import the libraries Opencv and Numpy.
On line 3 we import the library to run the servo motor.
import cv2 import numpy as np from PCA9685 import PCA9685
Then we create an object to run and configure the settings of the servo motor.
First two lines are technical details regaring my specific configuration while in the thirt line we set the position of the servo with index 0 to 90° which is the center in my case.
pwm = PCA9685(0x40, debug=False) pwm.setPWMFreq(50) pwm.setServoPosition(0, 90)
We then load the cap with opencv to take the frames from the screen and also we set a small camera resolution so that the raspberry pi can process the image much faster and the movement of the servo will be smoother.
cap = cv2.VideoCapture(0) # Set camera resolution cap.set(3, 480) cap.set(4, 320) _, frame = cap.read() rows, cols, _ = frame.shape
At this point we define the default values that are the center position of the object to track, the center of the screen and the starting position of the servo motor.
x_medium = int(cols / 2) center = int(cols / 2) position = 90 # degrees
Now it’s everything ready to run the while loop and start detecting the red object.
So we detect the red object with the HSV Color space.
while True:
_, frame = cap.read()
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# red color
low_red = np.array([161, 155, 84])
high_red = np.array([179, 255, 255])
red_mask = cv2.inRange(hsv_frame, low_red, high_red)
_, contours, _ = cv2.findContours(red_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=lambda x:cv2.contourArea(x), reverse=True)
Once the object is detected by its color we need to find its center position. An easy way will be to bound the contours with a rectangle and then find the center of that rectangle.
We will find the center only of the x as we are interested to move the camera only horizontally and not vertically.
for cnt in contours:
(x, y, w, h) = cv2.boundingRect(cnt)
x_medium = int((x + x + w) / 2)
break
cv2.line(frame, (x_medium, 0), (x_medium, 480), (0, 255, 0), 2)
Now using these values we can finally move the servo motor.
How do we now where and when to move it?
Simple. We know the center of the screen, we know that the center of the servo is 90° and we know the position of the object.
If the object is on the left side of the center we change the position by adding a degree and if it’s on the right of the center we remove a degree.
# Move servo motor
if x_medium < center -30:
position += 1
elif x_medium > center + 30:
position -= 1
pwm.setServoPosition(0, position)
We then show everything on the screen.
cv2.line(frame, (x_medium, 0), (x_medium, 480), (0, 255, 0), 2)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1)
if key == 27:
break
cap.release()
cv2.destroyAllWindows()

Hi there, I’m the founder of Pysource.
I’m a Computer Vision Consultant, developer and Course instructor.
I help Companies and Developers to build efficient computer vision software.
Excellent tutorial, thanks for doing these really appreciate your time and effort going into these videos.
Don’t forget to put
#!/usr/bin/env python
# -*- coding: utf-8 -*-
at the start, as ive had issues in the past running scripts on the pi
HI
Will you be able to point out where to get PCA9685 library..? I just get the Adafruit library which seems to be different.
Cheers
Vivek
Hi Sergio,
What steps do we have to follow in order to install CV2 and NUMPY in our Raspberry Pi 3?
Also, how can I get the coordinates of the center of the object to the center of the scree? Lets say that the center of the screen is the origin (point 0,0) and the software provides the the pixels coordinates of the center of the object.
Thanks bro!!!
Max
hi sir
thank you for your tutorial it was very good.
I have problem during writing your codes.
_, contours, _ = cv2.findContours(red_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)
[ WARN:0] terminating async callback
I don’t know what is wrong. can you help me out ?
thanks
IF YOU CAN’T USE THIS:
_, contours, _ = cv2.findContours(red_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
TRY TO USE THIS:
contours, _ = cv2.findContours(red_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Worked for me Thanks a lot
thank you
Hello sir. I’m Riski from Indonesia. I’m a student. I need a tutorial how to install PCA9685 library. Can you show me for that sir? Or can you give a link address? Thankyou… Sorry for this.
hi sir
I tried to build it. I used the 5-megapixel raspberry pi camera module.
I just copied your code, but it’s not working well.
can you tell what is wrong with running code with camera module
For those wondering about “from PCA9685 import PCA9685”, if you watch the video you will note that at minute marker 17:00 Sergio specifically calls that library out as proprietary. That said, the problem is easily remedied via the Adafruit PCA9685 Circuit Python libraries. Look at the examples in that library and you should be able to figure it out as it supports a full range of servo types and setting angles is as easy as pwm.angle = 90. Also, if you are using 2 servos in a pan/tilt setup its super easy to extend Sergio’s code to support the y axis for a greater range of motion. Thanks Sergio.
hey im stuck on this importing library part i installed the adafruit library
but im not able to figure out the from and import part
i get a error cannot import name pca9685 from pca9685
i tried to change it with same command in example but it sill shows the same error
It was very helpful, thank you sir
What if we want to do this in two directions at the same time with two servo motors?
I now have the line in the vertical direction. Do I want to have the horizontal direction at the same time?
Can you help me?
Is that what you are using in the video? https://learn.adafruit.com/adafruit-16-channel-pwm-servo-hat-for-raspberry-pi I’m looking forward to buying the gear.
Yes it’s the same one from adafruit
This is awesome! good job – how can i adapt this for face tracking ?
I also have pan and tilt, is it possible to do somethign similar with my tilt motor