# 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.

Canonical: https://roboticsengineering.in/projects/raspberry-pi-colour-tracking-pan-tilt-opencv/ | Published: 2026-11-04 | Updated: 2026-11-04

**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

| Part | Qty | Unit | Total |
| --- | --- | --- | --- |
| Raspberry Pi 4 Model B 2 GB | 1 | ₹4,500 | ₹4,500 |
| Pi camera module v2 or compatible with ribbon cable | 1 | ₹1,200 | ₹1,200 |
| Micro servo (SG90 or MG90S) | 2 | ₹120 | ₹240 |
| Pan-tilt bracket for two micro servos | 1 | ₹200 | ₹200 |
| 5 V 3 A USB-C power supply | 1 | ₹500 | ₹500 |
| Separate 5 V supply or battery pack for the servos | 1 | ₹250 | ₹250 |
| Jumper wires | 1 | ₹50 | ₹50 |
| Coloured ball or marker for the target | 1 | ₹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 centre | Angle off-axis | Move at 40 percent gain |
| --- | --- | --- |
| 20 px | 1.9° | 0.8° |
| 50 px | 4.9° | 1.9° |
| 100 px | 9.7° | 3.9° |
| 160 px | 15.6° | 6.2° |
| 320 px | 31.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

| Part | Connects to | Note |
| --- | --- | --- |
| Pan servo signal | GPIO 17 | Use pigpio for steadier pulses than software PWM |
| Tilt servo signal | GPIO 27 |  |
| Servo power | Separate 5 V supply | Do not power servos from the Pi 5 V pin |
| Grounds | Servo supply GND to Pi GND | Common ground |
| Camera | CSI ribbon connector | Contacts 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

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Locks onto the wrong object | HSV range too wide | Narrow the range and raise MIN_AREA |
| Mount oscillates | Gain too high | Lower GAIN |
| Servos jitter | Software PWM timing | Use pigpio and a separate supply |
| Runs away from the target | Wrong sign | Flip the sign of the correction |
| Pi reboots when servos move | Servos on the Pi supply | Power servos separately |
| Slow frame rate | Resolution too high or no threshold tuning | Lower 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](https://roboticsengineering.in/robotics-project-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.
