Raspberry Pi colour-tracking pan-tilt camera with OpenCV: design worksheet and code

A ₹6,990 design worksheet for a Raspberry Pi camera on two servos that follows a coloured object, with the pixel-to-degree maths, a proportional gain that avoids overshoot and a Python OpenCV sketch.

About the author · Sources, testing and AI policy

  • Parts₹6,990
  • Bench time8–12 h
  • LevelAdvanced
  • ReviewedNov 2026

A ₹6,990 camera that turns to keep a coloured ball in the middle of the picture. OpenCV finds the ball by its colour, the code measures how far off-centre it is in pixels, converts that to degrees, and moves a pan servo and a tilt servo by a fraction of the error each frame. The page works out the conversion and why a fraction, not the whole error, is used.

Scope: advanced. This is a design worksheet with illustrative costs. It has not been bench-tested by this site. The table was computed by script using 62.2° horizontal field of view across 640 pixels, which is the figure commonly listed for the Raspberry Pi camera module v2; check the field of view of your own camera. Colour tracking depends heavily on lighting, so thresholds need tuning on site. This page does not cover faces or people, and a camera pointed at people should only be used with their knowledge.

How it works

A 640-pixel-wide frame covering 62.2° gives 0.097° per pixel. An object 100 pixels from the centre is therefore about 9.7° off-axis, and one 320 pixels away, at the frame edge, about 31°. The vertical axis is handled the same way with its own field of view.

Moving the servo by the whole error each frame would overshoot, because the image arrives late and the servo takes time to move. Moving by 40 percent of the error each frame is a simple proportional controller that homes in smoothly; the third column of the table shows the move for each error. If it still oscillates, lower the gain.

Bill of materials

PartQtyUnitTotal
Raspberry Pi 4 Model B 2 GB1₹4,500₹4,500
Pi camera module v2 or compatible with ribbon cable1₹1,200₹1,200
Micro servo (SG90 or MG90S)2₹120₹240
Pan-tilt bracket for two micro servos1₹200₹200
5 V 3 A USB-C power supply1₹500₹500
Separate 5 V supply or battery pack for the servos1₹250₹250
Jumper wires1₹50₹50
Coloured ball or marker for the target1₹50₹50
Parts total₹6,990

Scroll the table sideways to see every column.

Prices checked Nov 2026. Shipping and tools are not included.

Prices are illustrative figures for Indian sellers in November 2026, before shipping, and have not been checked against current listings.

The numbers

Error from centreAngle off-axisMove at 40 percent gain
20 px1.9°0.8°
50 px4.9°1.9°
100 px9.7°3.9°
160 px15.6°6.2°
320 px31.1°12.4°
Angle = pixels × 62.2° / 640. The 40 percent column is the step applied each frame.

At 30 frames per second a 40 percent step closes about 97 percent of an error in six frames, which is roughly a fifth of a second. If you raise the gain to 100 percent, delay in the camera and servo can make the mount swing; lower gains are slower but steadier.

Power and wiring

PartConnects toNote
Pan servo signalGPIO 17Use pigpio for steadier pulses than software PWM
Tilt servo signalGPIO 27
Servo powerSeparate 5 V supplyDo not power servos from the Pi 5 V pin
GroundsServo supply GND to Pi GNDCommon ground
CameraCSI ribbon connectorContacts face the right way for your board
Servos powered from the Pi can brown out the board when they move; use their own supply and join the grounds.

The sketch

# Colour-tracking pan-tilt: Raspberry Pi + camera + 2 servos
# Design worksheet: tune the HSV range for your lighting.
# Needs: opencv-python, gpiozero, pigpio (run: sudo pigpiod)

import cv2
from gpiozero import AngularServo
from gpiozero.pins.pigpio import PiGPIOFactory

W, H = 640, 480
FOV_X, FOV_Y = 62.2, 48.8        # degrees, commonly listed for camera module v2
GAIN = 0.4                       # fraction of the error corrected per frame
DEAD_PX = 12                     # ignore tiny errors
LOW = (35, 90, 60)               # example green range in HSV
HIGH = (85, 255, 255)
MIN_AREA = 300                   # ignore small blobs

factory = PiGPIOFactory()
pan = AngularServo(17, min_angle=-90, max_angle=90, pin_factory=factory)
tilt = AngularServo(27, min_angle=-90, max_angle=90, pin_factory=factory)
pan_angle, tilt_angle = 0.0, 0.0
pan.angle, tilt.angle = pan_angle, tilt_angle

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, W)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, H)

while True:
    ok, frame = cap.read()
    if not ok:
        break
    hsv = cv2.cvtColor(cv2.GaussianBlur(frame, (7, 7), 0), cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, LOW, HIGH)
    mask = cv2.erode(mask, None, iterations=2)
    mask = cv2.dilate(mask, None, iterations=2)
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    if contours:
        c = max(contours, key=cv2.contourArea)
        if cv2.contourArea(c) > MIN_AREA:
            m = cv2.moments(c)
            cx, cy = m["m10"] / m["m00"], m["m01"] / m["m00"]
            err_x, err_y = cx - W / 2, cy - H / 2
            if abs(err_x) > DEAD_PX:
                pan_angle -= GAIN * err_x * FOV_X / W     # sign depends on mounting
            if abs(err_y) > DEAD_PX:
                tilt_angle += GAIN * err_y * FOV_Y / H
            pan_angle = max(-80, min(80, pan_angle))
            tilt_angle = max(-60, min(60, tilt_angle))
            pan.angle, tilt.angle = pan_angle, tilt_angle

    cv2.imshow("mask", mask)
    if cv2.waitKey(1) & 0xFF == 27:                        # Esc to quit
        break

cap.release()
cv2.destroyAllWindows()

The signs of the two corrections depend on how the servos and camera are mounted; if the camera runs away from the target, flip the sign. The camera capture call may need another backend on newer Raspberry Pi OS releases, where the camera is read through its own library, so check the camera documentation for your OS version before debugging the code. The HSV range above is an example only. The sketch has been proofread but not compiled on this site.

Test plan

  1. Camera first: confirm a live picture before adding servos.
  2. Colour mask: hold the target in view and tune the HSV range until only it shows white in the mask window.
  3. Direction: move the target left, right, up and down and check the camera follows, flipping signs if needed.
  4. Gain test: try 0.2, 0.4 and 0.8 and note when it begins to oscillate.
  5. Lighting: repeat near a window, under a lamp and in dim light.
  6. Lost target: hide the target and confirm the mount holds still instead of wandering.

What usually goes wrong

SymptomLikely causeFix
Locks onto the wrong objectHSV range too wideNarrow the range and raise MIN_AREA
Mount oscillatesGain too highLower GAIN
Servos jitterSoftware PWM timingUse pigpio and a separate supply
Runs away from the targetWrong signFlip the sign of the correction
Pi reboots when servos moveServos on the Pi supplyPower servos separately
Slow frame rateResolution too high or no threshold tuningLower the resolution to 320 × 240

Upgrades

  • Search sweep: sweep slowly when the target is lost.
  • Distance estimate: use blob size to estimate range.
  • Mount on a rover: steer the wheels toward the target.
  • Lower resolution: trade picture size for speed.

Cost and parts notes

The ₹6,990 total is an illustration and does not include shipping. Use the cost calculator to compare sellers.

Common questions

Why track by colour?

It is simple, fast and runs on a Pi without extra hardware, though lighting changes it.

Why not move the whole error at once?

Camera and servo delays make full corrections overshoot and swing.

What field of view does my camera have?

It depends on the module; the 62.2° figure is commonly listed for camera module v2 and should be replaced with your own.

Is this a face tracker?

No. It follows a coloured object only.

Last reviewed: November 2026. This is a design worksheet with illustrative costs. It has not been bench-tested by this site; library names, pins and limits must be checked against your board and the current library versions, and measurements from your build are welcome.

More builds

Next builds to try

Free: the final-year project pack

A shortlist with BOMs, a report outline that matches the usual chapter scheme, a costing sheet and 40 viva questions. Built for the February–April submission season.

The Build Note

One short email when something is worth your bench time.

A new build sheet, a part price that moved, or a mistake worth avoiding. No daily drip, no recycled news.

One short email when a build or a price is worth your time. Unsubscribe in one click.