ESP32 Wi-Fi pan-tilt mount with web sliders: design worksheet and code

A ₹1,390 design worksheet for a two-servo pan-tilt mount steered from a phone web page served by an ESP32, with a separate servo supply, a single-file sketch and a test plan.

About the author · Sources, testing and AI policy

  • Parts₹1,390
  • Bench time3–4 h
  • LevelIntermediate
  • ReviewedNov 2026

A ₹1,390 pan-tilt mount you steer from a web page on your phone. Two SG90-class servos in a pan-tilt bracket are driven by an ESP32 that serves a small web page with two sliders. Move a slider and the servo follows. The page includes the wiring, a separate servo supply, a complete sketch with the page built in, and a test plan for the brown-outs and Wi-Fi drops that make hobby servo projects flaky.

Scope: intermediate. This is a design worksheet with illustrative costs. It has not been bench-tested by this site. The sketch uses the ESP32 Arduino core’s built-in WebServer and Wi-Fi, plus the ESP32Servo library installed from the Library Manager; check both against their current examples, because names and defaults change between versions. The mount can later carry a camera, a sensor or a laser pointer; this build is only the mount and its controls.

How it works

The ESP32 joins your home Wi-Fi and starts a web server. Opening its address in a phone browser loads a page with two range sliders. Each slider sends a small request such as /set?pan=90 to the board, and the sketch moves the matching servo to that angle. There is no cloud service and no account: the phone and the board only need to share a network. The page is stored in the sketch as a text string, so the project is a single file.

Bill of materials

PartQtyUnitTotal
ESP32 dev board1₹450₹450
SG90-class servo2₹130₹260
Pan-tilt bracket1₹120₹120
5 V 2 A buck converter1₹220₹220
2×18650 holder with cells1₹200₹200
Switch1₹30₹30
Jumper wire set1₹50₹50
Small breadboard1₹60₹60
Parts total₹1,390

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 buck converter gives the servos their own 5 V rail; do not run both from the ESP32 board.

Power and wiring

PartESP32 dev boardNote
Pan servo signalGPIO 18A normal output pin; check your board’s pinout
Tilt servo signalGPIO 19A normal output pin; check your board’s pinout
Servo VCCBuck converter 5 V outputNot the board’s 3V3 or 5V pin
Servo GNDCommon GNDJoin the buck, ESP32 and servo grounds
Board powerUSB, or the buck 5 V into the 5V/VIN pinUse one source at a time
Set the buck converter to 5.0 V with a multimeter before connecting the servos. Servo signal lines accept the ESP32’s 3.3 V logic on most SG90-class servos, but test yours.

Two servos moving at once can pull more current than a USB port or the board’s regulator should provide. A weak supply shows up as the board rebooting when the servos move; see ESP32 brownout detector was triggered. A separate servo rail and a common ground is the fix.

The sketch

// ESP32 Wi-Fi pan-tilt mount: ESP32 + 2 servos, controlled from a web page
// Libraries: ESP32Servo (Library Manager). WiFi and WebServer come with the ESP32 core.
// Design worksheet: check names against the current library examples.

#include <WiFi.h>
#include <WebServer.h>
#include <ESP32Servo.h>

const char* WIFI_SSID = "your-network-name";
const char* WIFI_PASSWORD = "your-network-password";

const int PAN_PIN = 18;
const int TILT_PIN = 19;

const int PAN_MIN = 20;     // keep inside the range the bracket allows
const int PAN_MAX = 160;
const int TILT_MIN = 40;
const int TILT_MAX = 140;

Servo panServo;
Servo tiltServo;
WebServer server(80);

const char PAGE[] PROGMEM = R"HTML(
<!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Pan-tilt</title></head><body style="font-family:sans-serif;padding:16px">
<h2>Pan-tilt mount</h2>
<p>Pan <input id="pan" type="range" min="20" max="160" value="90" style="width:100%"></p>
<p>Tilt <input id="tilt" type="range" min="40" max="140" value="90" style="width:100%"></p>
<script>
function send(){
  fetch('/set?pan='+document.getElementById('pan').value+'&tilt='+document.getElementById('tilt').value);
}
document.getElementById('pan').oninput=send;
document.getElementById('tilt').oninput=send;
</script></body></html>
)HTML";

void handleRoot() {
  server.send(200, "text/html", PAGE);
}

void handleSet() {
  if (server.hasArg("pan")) {
    int pan = constrain(server.arg("pan").toInt(), PAN_MIN, PAN_MAX);
    panServo.write(pan);
  }
  if (server.hasArg("tilt")) {
    int tilt = constrain(server.arg("tilt").toInt(), TILT_MIN, TILT_MAX);
    tiltServo.write(tilt);
  }
  server.send(200, "text/plain", "ok");
}

void setup() {
  Serial.begin(115200);
  panServo.setPeriodHertz(50);
  tiltServo.setPeriodHertz(50);
  panServo.attach(PAN_PIN);
  tiltServo.attach(TILT_PIN);
  panServo.write(90);
  tiltServo.write(90);

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Open http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/set", handleSet);
  server.begin();
}

void loop() {
  server.handleClient();
}

The sketch clamps every request to the angle limits, so a bad request cannot drive a servo into its stop. Put your own network name and password into the two placeholders, and do not publish a sketch that contains them. The page has no password of its own, so anyone on the same network can move the mount; keep it on a home network you trust and do not expose the board to the internet.

Test plan

  1. Connection: confirm the Serial Monitor prints an address and that the page loads on a phone on the same network. If the board never connects, see ESP32 Wi-Fi won’t connect; the ESP32 uses a 2.4 GHz network.
  2. Servo centre: before fitting the horns, power the servos at 90 degrees and fit the mount level.
  3. Limits: slide to each end and listen for humming. Narrow the limits until it stops.
  4. Supply: move both sliders quickly together. A board reboot means the servo rail is too weak or the grounds are not joined.
  5. Latency: drag a slider fast and judge the lag. If requests pile up, send them less often from the page.
  6. Drop-out: move the phone away until Wi-Fi weakens, and confirm the mount stays where it was and the board recovers.
  7. Load: add the camera or sensor you plan to carry and check that the servos hold it without buzzing.

What usually goes wrong

SymptomLikely causeFix
Board reboots when servos moveServos drawing from a weak supplySeparate 5 V rail and a common ground
Never connects to Wi-FiWrong password or a 5 GHz-only networkCheck the credentials and use a 2.4 GHz network
Page loads, servos ignore itWrong GPIO or the library not attachedCheck the pin numbers and the attach calls
Servos twitchNoisy supply or long signal wiresShorten the wires, add a capacitor across the servo rail
Mount hums at the endsAngle limits too wideNarrow the limits
Address changes each dayThe router hands out a new addressReserve an address in the router settings

Upgrades

  • Camera: mount an ESP32-CAM and stream video, as in the ESP32-CAM robot car.
  • Smooth motion: move toward the target in small steps instead of jumping.
  • Presets: add buttons for home, left and right positions.
  • Access control: add a simple passcode check before any move is accepted.

Cost and parts notes

The ₹1,390 total is an illustration for the parts above and does not include shipping. Pan-tilt brackets vary in fit for SG90-class servos, so check the servo size before you buy. Use the cost calculator to compare sellers.

Common questions

Can I use an Arduino Uno instead?

Not for this version, because the Uno has no Wi-Fi. You could add a Wi-Fi module, but the ESP32 is simpler and cheaper for the job.

Is it safe to leave on my network?

The page has no password, so anyone on the same network can move the mount. Keep it on a trusted home network and do not forward a port to it.

Why is the servo supply separate?

Servos draw bursts of current that a USB port or the board regulator can not always supply. A separate rail avoids resets.

Can I drive more than two servos?

Yes, the library supports several, but watch the total current and keep the supply sized for the worst case.

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 the current ESP32 core and your board, 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.