Learning Goals 5 min
Two servos + a tiny mount + a phone holder = a remote-controlled camera you can pan and tilt from across the room. Drive it from a physical joystick (potentiometer × 2) or from a phone webpage. Last of the three L3 builds. By the end of this lesson you will:
- Wire two SG90 servos in a pan-tilt configuration: one rotates the base (pan), one tilts the top platform (tilt).
- Control both with two pots (analog joystick) and apply slew-limiting + dead-zone (from L03-04) for smooth motion.
- Add a WiFi web UI with a touch-pad control so the phone can frame the shot remotely.
Warm-Up 10 min
Hardware:
- 2 × SG90 (or MG90S — better gears).
- Plastic pan-tilt bracket (sold cheaply as "FPV camera mount") or hand-build from cardboard / 3D-print.
- Phone or small camera as "payload" — anything under 100 g works with SG90.
- 2 × potentiometers for the analog joystick.
- ESP (for the WiFi version) or UNO (for pots-only).
- External 5 V supply for the servos (4 × AA pack) — UNO 5V can't supply two servos at once.
Plan the axes
Pan = horizontal rotation. The base servo turns left/right. Tilt = vertical rotation. The top servo tilts up/down. Mount the tilt servo on top of the pan servo so the tilt axis moves with the pan.
New Concept · Two-axis control with smoothing 20 min
Wire-up summary
| Wire | UNO / ESP pin |
|---|---|
| Pan servo signal | D9 |
| Tilt servo signal | D10 |
| Servo + 5 V | 4 × AA pack + |
| Servo GND + UNO GND + battery GND | common GND |
| Pan pot wiper | A0 |
| Tilt pot wiper | A1 |
The slew-limited mapping
Same pattern as L03-04 (indicator needle), now applied to two axes:
#include <Servo.h>
const int PAN_PIN = 9, TILT_PIN = 10;
const int PAN_MIN = 20, PAN_MAX = 160; // mechanical limits
const int TILT_MIN = 30, TILT_MAX = 150;
const int MAX_DEG_PER_SEC = 90; // slew limit
Servo pan, tilt;
int currentPan = 90, currentTilt = 90;
unsigned long lastSlewAt = 0;
int slewTowards(int current, int target, int dtMs) {
int maxStep = (long)MAX_DEG_PER_SEC * dtMs / 1000;
if (maxStep < 1) maxStep = 1;
int diff = target - current;
if (diff > maxStep) diff = maxStep;
if (diff < -maxStep) diff = -maxStep;
return current + diff;
}
void setup() {
pan.attach(PAN_PIN);
tilt.attach(TILT_PIN);
pan.write(90);
tilt.write(90);
lastSlewAt = millis();
}
void loop() {
unsigned long now = millis();
int dt = now - lastSlewAt;
lastSlewAt = now;
int rawPan = analogRead(A0);
int rawTilt = analogRead(A1);
int targetPan = constrain(map(rawPan, 0, 1023, PAN_MIN, PAN_MAX), PAN_MIN, PAN_MAX);
int targetTilt = constrain(map(rawTilt, 0, 1023, TILT_MIN, TILT_MAX), TILT_MIN, TILT_MAX);
currentPan = slewTowards(currentPan, targetPan, dt);
currentTilt = slewTowards(currentTilt, targetTilt, dt);
pan.write(currentPan);
tilt.write(currentTilt);
delay(20); // ~50 fps update
}Without slew limiting, fast pot moves cause the servos to snap, jarring the camera. With it, the camera glides smoothly even if the pots are flicked.
WiFi version — a touch-pad in the browser
Replace the pots with a small HTML touch pad that POSTs ?pan=N&tilt=M. The ESP receives, sets targetPan / targetTilt, and the slew limiter does the rest. The touch pad is just a square <div> on the page; JS reads touch X/Y and maps to angles.
Worked Example · Pots-driven version 25 min
Step 1 — assemble the mount
Mount pan servo to a heavy base (taped to a brick / wood block — anything that won't tip). Glue tilt servo on top of pan servo's horn, perpendicular axis. Tape the phone/camera to the tilt horn.
Step 2 — upload the §3 sketch
Step 3 — calibrate the mechanical limits
Manually pan to far left / far right while watching for the gears straining. Note the angles where the servo starts to bind; set PAN_MIN / PAN_MAX 5° inside those points. Same for tilt.
Step 4 — joystick test
Turn pot A — pan moves smoothly. Turn pot B — tilt moves smoothly. Flick both fast simultaneously — slew limiter keeps them gentle. The camera tracks like a real director-controlled rig.
Step 5 — add a return-to-centre button
Button on D2 with INPUT_PULLUP. When pressed, sets targets to 90, 90. Useful as a "home" pose after wild panning.
Step 6 — record a panning shot
Point camera at a scene. Slowly turn pan from one end to the other while filming. The slew limiter produces a smooth cinematic pan — much nicer than a hand-held attempt.
Try It Yourself 15 min
Goal: Add a centre dead-zone on the pots so the camera doesn't drift while you're "not touching" (raw 480..540 → centre, ignore).
Goal: Add a "sweep" mode — button press triggers an auto-pan from PAN_MIN to PAN_MAX over 10 seconds, then returns. Useful for unattended timelapse.
Goal: WiFi touch-pad version. ESP serves a webpage with a <div> that captures touch / mouse drag; JS POSTs the X/Y as pan/tilt percentages. Replace the pot inputs with the values from the most recent POST.
Mini-Challenge · Cinematic pan video 10 min
- Frame a scene. Position the rig.
- Slowly drive the pan from left to right while the phone records video.
- Slowly tilt up at the end.
- Watch the playback. Compare with a hand-held attempt.
- Share your favourite clip.
You've built the physical equivalent of a director's crane — for < £30 of parts. The pattern (smoothed two-axis servo control with limits) scales directly to robot arms, antenna trackers, satellite dishes, and 3D printer gantries.
Recap 5 min
Pan-tilt = two servos + slew-limited targets + dead-zones + mechanical limits in software. Pots for hand control; phone touch-pad for remote. The slew limiter (L03-04) is the difference between "jerky toy" and "cinematic shot". Three L3 builds done. Last few lessons: power budgeting, schematic reading III, recap.
- Pan / tilt
- Horizontal rotation (pan) + vertical rotation (tilt). The standard 2-DOF camera mount.
- Slew limit
- Maximum rate of change per second. Keeps motion smooth even when the input is jumpy.
- Mechanical end-stop
- The physical angle at which the servo can't turn further. Forcing past = stripped gears. Clamp in software with
constrain(). - Centre dead-zone
- Input range near the middle that's treated as "exactly centre". Stops jitter.
- External servo power
- A separate 4–6 V supply for the servos so the microcontroller doesn't brown out under peak load. Common ground to the controller.
- Cinematic pan
- A slow, steady camera rotation — the visual signature of professional video. Achieved here with the slew limiter.
Homework 5 min
- Finish the build + record a 30-second pan / tilt clip.
- Save sketch.
- Read ahead to ARD-L03-46 (Power Budgeting).
- Bring a multimeter tomorrow.