ESP32-C3 SuperMini breadboard build with an SG90 micro servo pointing to a printed scale, controlled by a 10K potentiometer

Beginner

Build a Servo Position Controller

ActuatorsInputsMotion

Turn a knob, watch a servo move to match it in real time -- the fundamentals behind pointing, aiming, and steering anything with code.

6 real parts included

Total for this kit: 1,583.00 ฿

Doesn't include any order discount you may get at checkout.

What you'll need

Project Goal

This beginner project pairs a single knob with a single servo motor so that turning the knob moves the servo to match, in real time. It's a compact introduction to two fundamentals that show up in almost every more advanced motion project: reading an analog input, and generating a pulse-width signal to control position.

What the Controller Does

The ESP32-C3 continuously reads the potentiometer's analog voltage, maps that reading onto the servo's usable angle range, and outputs a corresponding PWM signal to the servo. This is a tight, simple loop: read, map, write, repeat -- with no timing complexity beyond what the servo itself expects.

What the Potentiometer Does

The 10K potentiometer is a simple voltage divider: as you turn its knob, the voltage at its middle (wiper) pin changes smoothly between the two ends of its supply range. The controller reads that changing voltage as an analog value and maps it directly onto the servo's pulse-width range, so the knob's physical position and the servo's angle track each other continuously as you turn it.

What the Servo Does

The SG90 micro servo is controlled by pulse-width modulation -- the width of a repeating electrical pulse, roughly between 1 and 2 milliseconds, tells the servo exactly what angle to hold. Unlike a simple DC motor, a servo actively maintains its commanded angle against resistance rather than just spinning freely; internally it constantly compares its actual position to the commanded pulse width and corrects itself.

Power Considerations

A single SG90 typically runs fine directly off the controller's own USB-supplied power for this project. Be aware this doesn't scale automatically, though: moving to a larger servo, or driving multiple servos at once, means moving to a separate, dedicated power supply for the servos. Servo current draw -- especially at startup or while working against resistance -- can be more than a controller's onboard regulator is meant to handle, and underpowering a servo is a common source of erratic behavior.

Software and Library Concepts

Use a standard servo control library rather than generating the PWM pulses by hand -- it handles the precise pulse timing for you and exposes a simple "set angle" function. Read the potentiometer's raw analog range first with a simple print-out before wiring in the servo, so you know the actual minimum and maximum voltage your specific potentiometer produces, then map that measured range onto the servo library's angle range in code.

Testing and Troubleshooting

  • Servo doesn't move at all -- check the signal wire connection first, then confirm the PWM library and pin setup in your code match the pin you actually wired.
  • Servo jitters or twitches instead of holding still -- this is very often a power supply issue (noisy or insufficient current), not a code problem; try powering the servo from a separate supply before changing any code.
  • Servo position doesn't track the knob correctly -- check the analog-to-servo-angle mapping range in your code against the potentiometer's actual measured voltage range, rather than assuming a textbook 0-100% range.
  • Servo moves in the wrong direction relative to the knob -- this is a mapping order issue, not a wiring fault; simply reverse the mapped range in code rather than rewiring anything.

Optional Future Upgrade: Two-Axis Pan/Tilt

Once a single knob-to-servo pairing is working reliably, a natural next step is adding a second potentiometer and a second servo to build a simple two-axis pan/tilt mount -- the same read-map-write logic, just duplicated and run independently for each axis.

Wiring

  • 10K potentiometer outer leg 1 → ESP32-C3 SuperMini 3.3V
  • 10K potentiometer outer leg 2 → ESP32-C3 SuperMini GND
  • 10K potentiometer wiper (middle leg) → ESP32-C3 SuperMini GPIO1 (`POT_PIN`) — must be an ADC1-capable pin (GPIO0–4 on ESP32-C3)
  • SG90 signal (orange/yellow) → ESP32-C3 SuperMini GPIO2 (`SERVO_PIN`), via the ESP32Servo library
  • SG90 power (red) → 5V — use your board's 5V/VBUS pin if it breaks one out, or a separate 5V source; do not run the servo from 3.3V, it won't have enough torque
  • SG90 ground (brown/black) → GND, common with the ESP32-C3's GND

A single SG90 drawing off USB 5V is normally fine, but its startup/stall current can spike to 250mA+ — if you add more servos later, move to a dedicated 5V supply rather than the SuperMini's onboard regulator. The ESP32-C3's ADC is known to be non-linear near the very top and bottom of its range, so if the servo doesn't quite reach 0° or 180° at the pot's extremes, tune the `map()` bounds in code rather than assuming a hardware fault.

Wiring Diagram

leg 1 → 3.3V leg 2 → GND wiper → GPIO1 signal → GPIO2 power ground ESP32-C3 SuperMini 10K potentiometer SG90 5V GND

Starter Code

#include <ESP32Servo.h>

#define POT_PIN 1     // ADC1-capable pin
#define SERVO_PIN 2

Servo myServo;

void setup() {
  Serial.begin(115200);

  // Allocate a PWM timer/channel for the servo (ESP32Servo handles this internally)
  myServo.setPeriodHertz(50);       // standard 50Hz servo signal
  myServo.attach(SERVO_PIN, 500, 2400); // typical SG90 pulse width range in microseconds

  analogReadResolution(12); // ESP32 ADC default is 12-bit (0-4095)
}

void loop() {
  int rawValue = analogRead(POT_PIN);         // 0-4095
  int angle = map(rawValue, 0, 4095, 0, 180);  // adjust bounds if servo doesn't reach full travel

  myServo.write(angle);

  Serial.print("Pot raw: ");
  Serial.print(rawValue);
  Serial.print("  Angle: ");
  Serial.println(angle);

  delay(20); // smooth, responsive without flooding the servo with commands
}

Not sure about a step? Ask us