Week 8: On Painting with Input Devices

The brief this week was to measure something—add an input to a microcontroller board I designed and read it. I turned my custom XIAO ESP32-S3 board into a tactile instrument by using two copper pads as capacitive touch sensors. The goal was an input that feels delightful and works reliably as a button for the earphone product we are continuously working towards.

Hand holding the week 8 capacitive touch pads
Week 8 device in context: off-board copper touch pads you can actually wear / play with.

Starting Point: Week 6 Board

I reused my Week 6 board (XIAO ESP32-S3 core, broken-out headers, clean ground reference). Two nets are reserved for touch sensing: TOUCH_PLAY and TOUCH_VOL.

Photo of the assembled main board
The assembled Week 6 style main board that I extended for capacitive input.

Plan & Design Choices

Play/pause SVG icon
Base SVG artwork for the PLAY/PAUSE pad.
PCB renders of play and volume pads
Renders of the two separate pad PCBs: PLAY/PAUSE and VOLUME.
Green render of play and volume icons
Icon design for PLAY and VOLUME, sized for the copper pads.

Toolchain Setup

Last week I switched from a windows PC to a macbook so there was a bit of a learning curve in gettin gup and running again. I cleaned and reinstalled the Arduino IDE, installed the official Espressif ESP32 core, and enabled USB-CDC so Serial works immediately on boot.

Pro tip: picking a generic “ESP32 Family Device” hid CDC options and broke Serial. Installing the Espressif core fixed it.

First Contact (Serial)

Sanity check: a tiny heartbeat to confirm the board and IDE are speaking the same language.


void setup() {
  Serial.begin(115200);
  delay(1000);
  while (!Serial) { delay(10); }
  Serial.println("Hello ✨ ESP32S3 is alive!");
}
void loop() {
  Serial.println("Still alive...");
  delay(1000);
}
  

Capacitive Sensing

I started on the wrong pins (GPIO 4/5) and got the ESP32 sentinel 4194303 (= 2²²−1), which means “not a touch pin.” Remapping to GPIO 8 (TOUCH8) and GPIO 9 (TOUCH9) fixed it instantly.


// XIAO ESP32S3 touch pads
const int touchPlayPin = 8;   // D9  → TOUCH8
const int touchVolPin  = 9;   // D10 → TOUCH9

void setup() {
  Serial.begin(115200);
  delay(1000);
  while (!Serial) { delay(10); }
  Serial.println("Capacitive sensing 🎨");
}

void loop() {
  int vPlay = touchRead(touchPlayPin);
  int vVol  = touchRead(touchVolPin);

  Serial.print("Play: "); Serial.print(vPlay);
  Serial.print("\tVol: "); Serial.println(vVol);
  delay(200);
}
  

Typical readings on my setup: idle ~70–90, touched ~30–40 (exact values vary with copper area, wiring, humidity, and grounding).

Off-Board Touch Pads (PCB Design)

I designed the pads as tiny PCBs so they can live where the human is, not where the MCU is. Each pad is:

  1. A large filled copper shape on F.Cu (the sensor).
  2. An optional matching opening on F.Mask to expose copper for touch.
  3. One THT/SMD pad (1×01) for a single signal wire back to the main board.
  4. Optional NPTH mounting/string hole.

Icons (“▶︎∥” and “VOL”) were imported as SVG via File → Import → Graphics; vector art keeps edges crisp.

Circular pad PCB test in KiCad
Early circular pad test board.
Funky shaped PCB test
Exploring funkier pad outlines before settling on circles.
Top layer outline export
Exported outline / top layer used for milling toolpaths.
Mods or KiCad window displaying and tracing outlines
Checking that the traces match the intended icon geometry.
Mods settings for play/pause pad
Mods toolchain configured for the PLAY/PAUSE pad.
Mods settings for edge cuts
Separate job for the edge cuts of the circular pads.
Preview of edge cuts toolpaths
Edge-cut preview before committing to the mill.
Preview of holes in Mods
Previewing the small mounting/string holes on the pad PCBs.
Edge cuts PNG used for Mods
Edge-cuts PNG that drove the circular pad outlines.
Filled copper region on pad design
Filling in the copper region for stronger, more responsive pads.
Moving button footprints around the board
Iteration where I shuffled the pads and buttons to better fit the board.
Traces without board outline
Traces-only view used to sanity-check connectivity before milling.
Board with messed up traces
A “learning experience” board where the traces and edge cuts didn’t quite line up.
Swept/milled board after cleaning
Cleaned-up board after sweeping away copper dust.

Milling & Assembly

Once the designs looked good, I went to the mill, set up the jobs, and then soldered and reworked the boards as needed.

Machine screen while setting the origin
Setting the XY origin on the milling machine.
Sticking board down on the mill bed
Sticking the copper board down securely before milling.
Milling traces on the PCB
Trace pass in progress.
Board covered in white powder while milling
Using powder to make the milled traces easier to inspect.
Live shot of the milling head cutting copper
Action shot of the mill carving out the circular pads.
Milling the edge cuts around the circular board
Second job: cutting the circular outline and holes.
Standing by the machine watching the milling job
Babysitting the mill to make sure the pads survived the cutout.
Recycling / reusing a XIAO board
Recycling a XIAO and making sure the headers & pads still worked.
Soldering the XIAO onto the main board
Soldering the XIAO and cleaning up joints.
Reworking XIAO headers and pins
Rework: replacing the XIAO with headers/pins that made more sense mechanically.
Board taped down again
Re-sticking the board for a later clean-up pass.

What I Measured

Most of the interesting behavior showed up directly in the Serial Monitor, so this section is more text and numbers than pretty plots.

Debugging Notes

Error dialog while struggling with through-hole settings
KiCad / Mods moment: struggling with through-hole settings and drill files.
Board with messed up traces and edge cuts
One of the early “messed up traces” boards that informed the final design.

Files

Update or remove links based on what you actually used this week.

What I Learned

Final glam shot of input device setup
Final setup: main board + detachable touch pads = very tappable interface.