TinySkiff ESP32-S3 Lab · Day 23 of 30

Swing an arm
to any angle

Today the board gets an arm. You wire a small servo to one pin, upload a sketch that counts through the angles, and the horn sweeps from 0° to 180° and back — the same steady nudge an autopilot gives a tiller.

About 20 minutesArduino firstMicroPython optionalNo electronics assumed
Agent assist code TSK-DAY23-SERVOSWEEP

Hand this to an agent so it can pull the lesson packet and coach you step by step.

01 First, know the pieces

What you need

Five things, and one of them moves. Tap Define on any part you haven't met — the answer opens as a field note you can read and dismiss without losing your place.

Official manual photo of the ESP32-S3 development board.
Manual photo

ESP32-S3 board

The brain that runs your uploaded sketch.

Official manual image of the ESP32-S3 GPIO extension board.
Manual photo

GPIO extension board

Spreads the pins into rows you can reach and label.

Official manual illustration of a servo with its three wires labelled 1 signal, 2 power, and 3 ground.
Manual photo

Servo

A small geared motor that turns its horn to the angle you ask for and holds it.

Official manual image of a jumper wire.
Manual photo

3 jumper wires (M/M)

Temporary, solder-free connections.

Official manual screenshot of the Arduino IDE interface.
Manual screenshot

Arduino IDE

Uploads the sketch to the board.

02 Make the physical circuit

Chart the circuit

The official Freenove diagram is your chart — schematic on top, the same circuit built on a breadboard below. Click it to enlarge. The servo's three wires are colour-coded, so the colours are your map.

Official Freenove circuit — C Tutorial, Chapter 17 (Servo), page 154.
Servo signal (orange) GPIO 21 Carries the timed pulse that names the angle.
Servo power (red) 5V Feeds the servo's motor with enough current to move.
Servo ground (brown) GND Gives board and servo the same zero point.

5V for the servo. The manual's own caution: "Use caution when supplying power to the servo, it should be 5V." The red wire goes to the 5V pin with its own jumper — and unplug USB before you move any wire.

03 One action at a time

Build it

This is the main path — you can finish the day without opening a single field note. Tap each step as you go to keep your place.

0 / 8 done
  1. Seat the ESP32-S3 on the GPIO extension board and keep USB unplugged while you wire.

  2. Push a jumper into each of the servo's three sockets — orange, red, and brown.

  3. Run the orange signal wire to GPIO 21.

  4. Run the red wire to 5V and the brown wire to GND.

  5. Press a horn onto the servo's shaft so you can see it move.

  6. Compare every wire to the chart before you plug in USB.

  7. Open Sketch_17.1_Servo_Sweep.ino in Arduino IDE and upload it.

  8. Watch the horn sweep from one end of its travel to the other and back.

The arm answers.

The horn is swinging on your command. Head to Test & debug to confirm the pace and the full 180° reach.

04 Read just enough code

Read the code

The whole sketch is short, and it drives the servo with the same LEDC hardware that faded your LEDs — set to 50 Hz and 12 bits, the timing a servo listens for. The loop counts angles up and down; one map() line turns each angle into a pulse. Switch to MicroPython if you'd rather see the same idea in Python — the wiring never changes.

Sketch_17.1_Servo_Sweep.ino
#define SERVO_PIN 21  //define the pwm pin
#define SERVO_CHN 0   //define the pwm channel
#define SERVO_FRQ 50  //define the pwm frequency
#define SERVO_BIT 12  //define the pwm precision

void servo_set_pin(int pin);
void servo_set_angle(int angle);

void setup() {
  servo_set_pin(SERVO_PIN);
}

void loop() {
  for (int i = 0; i < 180; i++) {
    servo_set_angle(i);
    delay(10);
  }
  for (int i = 180; i > 0; i--) {
    servo_set_angle(i);
    delay(10);
  }
}

void servo_set_pin(int pin) {
  ledcAttachChannel(pin, SERVO_FRQ, SERVO_BIT, SERVO_CHN);
}

void servo_set_angle(int angle) {
  if (angle > 180 || angle < 0)
    return;
  long pwm_value = map(angle, 0, 180, 103, 512);
  ledcWrite(SERVO_PIN, pwm_value);
}
ledcAttachChannel(pin, SERVO_FRQ, SERVO_BIT, SERVO_CHN)Sets GPIO 21 switching at 50 Hz with 12-bit precision — the frame rate a servo expects.
map(angle, 0, 180, 103, 512)Translates degrees into pulse counts — 103 counts for 0° up to 512 counts for 180°.
ledcWrite(SERVO_PIN, pwm_value)Sends a pulse of that width every 20 ms; the servo turns until its shaft matches.

05 Understand, don't memorise

The pulse is the position

The clever part of today fits in one line — the map() call. Everything around it is a counter going up and coming back down.

Beat

50 frames a second

The pin starts a fresh pulse every 20 ms.

Width

The pulse is the order

A 0.5 ms pulse means 0° and a 2.5 ms pulse means 180°.

Convert

map() translates

Degrees become pulse counts — 103 at one end and 512 at the other.

Hold

The servo obeys

A circuit inside turns the shaft until it matches the width.

The model angle = pulse width — 0.5 ms is 0° · 1.5 ms is 90° · 2.5 ms is 180°

Where 103 and 512 come from

At 50 Hz and 12 bits, each 20 ms frame is 4096 counts — so 103 counts lasts about 0.5 ms and 512 counts about 2.5 ms, the two ends of the servo's travel.

A straight line of angles

The mapping is linear — 0.5 ms sits at 0°, 1.5 ms at 90°, 2.5 ms at 180°, and every angle between gets its own width.

06 Know it worked

Test & debug

Nothing prints to the screen today — the proof is the horn swinging in front of you.

What you should see
Servo horn
  • The horn glides smoothly from 0° all the way round to 180°.
  • It reverses and glides back, then repeats — about 1.8 seconds each way.
  • The pace is steady, like a metronome.

A soft hum while it moves is normal. Each sweep should be one continuous glide, never a twitchy stutter.

If it doesn't
  • Horn twitches or judders? Power the servo from the 5V pin with its own jumper — a GPIO can't feed a motor.
  • Sweeps once, then jams at an end? The horn is hitting something — pull it off the shaft and refit it clear.
  • No motion at all? Check the orange signal wire on GPIO 21, then the red and brown power pair.
  • Board resets mid-sweep? The USB supply is weak — unplug other loads from the board.

07 Make the idea yours

Try this: run a lighthouse

Same working circuit, three small experiments with the sweep. They fit inside today's 20 minutes.

Sweep a half-arc

Change both for loops so the sweep runs 0° to 90° and back. Predict where the horn will stop before you upload.

Rest like a lighthouse

Add delay(1000) after each for loop so the horn pauses a second at each end before turning back.

Find the smallest step

Make the loops step by 2, then 5, then 10. Watch for the smallest angle step your servo turns into a visible move.

Logbook

08 Learn it with a hand on the tiller

Coach me through it

Every lesson ships with a code and a machine-readable packet, so an agent can guide you with full context.

Lesson code

TSK-DAY23-SERVOSWEEP

How the agent should behave: guide one physical connection at a time, wait for you to confirm, explain terms on request, and always check wiring, board, port, and USB before changing code.

Field note

Shortcut

Prompt copied