
ESP32-S3 board
The brain that runs your uploaded sketch.
TinySkiff ESP32-S3 Lab · Day 24 of 30
Today the board gets a helm. You wire the knob from Day 13 and the servo from Day 23 into one circuit, and a two-line conversion joins them — turn the knob and the horn swings with your hand, live. Serial Monitor prints the raw reading and the finished angle side by side so you can watch the mapping happen.
TSK-DAY24-SERVOKNOB
Hand this to an agent so it can pull the lesson packet and coach you step by step.
01 First, know the pieces
Six things, and you've met them all. Tap Define on any part you'd like a refresher on — the answer opens as a field note you can read and dismiss without losing your place.

The brain that runs your uploaded sketch.

Spreads the pins into rows you can reach and label.

The motor that holds whatever angle you command.

The knob — a resistor track with a sliding tap.

Temporary, solder-free connections.

Uploads the sketch and opens Serial Monitor.
02 Make the physical circuit
The official Freenove diagram is your chart — schematic on top, the same circuit built on a breadboard below. Click it to enlarge. Two familiar circuits share the board today: the knob on one side, the servo on the other, joined through the code.
Two power rails, each to its own device. The servo's motor drinks from the 5V pin; the potentiometer stays on 3.3V so GPIO 14 reads within its limit. Keep the two supplies straight, never twist the horn by hand while it's powered, and unplug USB before you move any wire.
03 One action at a time
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.
Seat the ESP32-S3 on the GPIO extension board and keep USB unplugged while you wire.
Push the potentiometer into the breadboard so each of its three pins has its own row.
Wire the pot's outer pins to 3.3V and GND, then run its middle pin to GPIO 14.
Connect the servo's lead — orange signal to GPIO 21, red to 5V, brown to GND.
Press a horn onto the servo's output shaft so the motion is easy to see.
Compare every wire to the chart before you plug in USB.
Open Sketch_17.2_Control_Servo_by_Potentiometer.ino in Arduino IDE and upload it.
Open Serial Monitor and set the baud rate to 115200.
Turn the knob slowly end to end and watch the horn follow your hand.
04 Read just enough code
The loop is five working lines — read the knob, print, map, steer, print again. Switch to MicroPython if you'd rather see the same idea in Python — the wiring never changes.
#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
#define ADC_PIN 14 //define the adc pin
void setup() {
servo_set_pin(SERVO_PIN);
Serial.begin(115200);
}
void loop() {
// read the value of the potentiometer (value between 0 and 4095)
int potVal = analogRead(ADC_PIN);
Serial.printf("potVal_1: %d\t",potVal);
// scale it to use it with the servo (value between 0 and 180)
potVal = map(potVal, 0, 4095, 0, 180);
// set the servo position according to the scaled value
servo_set_angle(potVal);
Serial.printf("potVal_2: %d\r\n",potVal);
delay(15);// wait for the servo to get there
}
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);
}
map(potVal, 0, 4095, 0, 180)Rescales the knob's raw reading onto the servo's range — 0 stays 0, 4095 becomes 180, and everything between lands in proportion. map(angle, 0, 180, 103, 512)The second map turns the angle into a duty value — the width of the pulse that tells the servo where to hold. ledcAttachChannel(pin, SERVO_FRQ, SERVO_BIT, SERVO_CHN)Sets GPIO 21 up as 50 Hz PWM with 12-bit precision — the timing a hobby servo expects. Serial.printf("potVal_1: %d\t",potVal)Prints the raw reading before the mapping, so each line pairs the input with its finished angle. Optional side path · same circuit
servo=myServo(21)
adc=ADC(Pin(14))
adc.atten(ADC.ATTN_11DB)
adc.width(ADC.WIDTH_12BIT)
adcValue=adc.read()
angle=(adcValue*180)/4096
servo.myServoWriteAngle(int(angle))
time.sleep_ms(50)
angle=(adcValue*180)/4096The same rescale as the Arduino map — one line of arithmetic from reading to angle.servo.myServoWriteAngle(int(angle))The helper in myservo.py builds the matching pulse and sends it to GPIO 21.Same pins, same behaviour. Copy myservo.py onto the board alongside the script — the import needs it there. Run it in Thonny if MicroPython is set up; otherwise skip it — it should never block the Arduino-first path.
05 Understand, don't memorise
Everything in today's loop is a rescale. The knob speaks in 0 to 4095, the servo listens in 0 to 180, and the PWM hardware wants a duty value — map() translates at each border.
The wiper hands GPIO 14 a voltage that tracks the knob's position.
analogRead turns that voltage into a number from 0 to 4095.
map() rescales 0-4095 onto 0-180 so every knob position names an angle.
A second map() converts the angle to a duty value from 103 to 512 and ledcWrite sends it.
angle = map(reading, 0, 4095, 0, 180) → pulse = map(angle, 0, 180, 103, 512)
Each call bridges one border — sensor range to human range, then human range to hardware range. Keeping the angle in the middle lets you think in degrees.
At 50 Hz with 12-bit precision, duty 103 is roughly a 0.5 ms pulse and 512 is roughly 2.5 ms — the width, repeated every 20 ms, is the position command the servo holds.
06 Know it worked
The horn tracking your hand is the payoff; the serial pairs are the proof. Success and recovery sit side by side, so you never have to go hunting when something looks off.
Each line pairs the raw reading with its mapped angle — one end of the knob prints near 0 and 0, the centre near 2048 and 90, the far end near 4095 and 180.
07 Make the idea yours
Same working circuit, three small rewrites of one line. Each teaches you something about owning the mapping. It fits inside today's 20 minutes.
Change the first map() so the angle runs 67 to 112 — a 45° window around centre, like the stops on a boat's tiller. The knob still sweeps end to end; the horn stays inside its lane.
Swap the output ends — map to 180 down to 0 — and the horn runs against the knob. One line reverses the helm.
With the original sketch restored, find the knob positions that print 0, 90, and 180, and mark each on the knob with a sliver of tape. You've calibrated a control.
Logbook
08 Learn it with a hand on the tiller
Every lesson ships with a code and a machine-readable packet, so an agent can guide you with full context.
TSK-DAY24-SERVOKNOB
How the agent should behave: guide one wire at a time, wait for you to confirm, explain terms on request, and always check wiring, board, port, and baud rate before changing code.