Skip to the content
4 layers180 × 100 mmClass board V0.2, the printed circuit board in 3D

TIGP class instrument 2026: one board, five blocks - KiCad hardware, ESP32-S3 firmware, phone PWA, Python API, workbook

Size
180 × 100 mm
Copper layers
4
Thickness
1.61 mm
Parts
342
Nets
260
Pads
1,115
Tracks, vias
2,823, 423
Pours
14
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
5 Sep 2026
Updated
3 Nov 2026

Overview

Class board V0.2 is an open-source printed circuit board by TIGP-Experimental-Methods, from the TIGP-Experimental-Methods/class-board-2026 repository on GitHub. It is a 4-layer board of 180 × 100 mm with 342 parts on 260 nets, routed with 2,823 tracks and 423 vias.

It is built around the 74HCT125PW,118-JSM, B0512S-2WR3 and OPA1612AIDRGR, with the ADS8688IDBTR, TS5A23157DGSR and 74HC74D,653-JSM among its other parts. Its parts include 126 resistors, 105 capacitors, 27 diodes, 13 ICs and 12 connectors.

Main components

12

README

README.md

class-board-2026

The teaching instrument for Basic Skills for Experimentalists (TIGP, 2026): one ESP32-S3 board (the ESP32-S3 is the microcontroller we use — a small computer on a chip, with WiFi) with three student-designed sections, a phone web app, and a Python client. The board is a small NMR console: a 2 mT field, a bottle of water, a pulse at 89 kHz, and the free induction decay that comes back turned into a spectrum on your phone.

FolderWhatWho edits it
hardware/KiCad project and library (KiCad is the free program we draw the schematic and lay out the printed circuit board in; the library is the set of symbols and footprints for our parts)students in their zone (the region of the board that is theirs), instructor merges (brings their changes into the main line)
firmware/PlatformIO project (Arduino, ESP32-S3) — the firmware is the program that runs on the microcontroller; PlatformIO is the tool that builds it and writes it onto the boardstudents, in the driver folders their instrument needs, under src/blocks/
host/pwa/the phone app (plain HTML/JS, no build step)students, in the panel files of those drivers, under panels/
host/instrument.pyPython command-line client (CLI) speaking the same protocol as the phoneinstructor

The three sections of the board (one design, made together in Workshop 2; each student added one section): A — inputs and the NMR receiver (the 8-channel 16-bit converter; the tuned coil, low-noise amplifier, blanking switch, I/Q mixer, IF filters and clock generator) · B — signal generation, timing and the NMR transmitter (±10 V outputs; the DDS synthesizer, reconstruction filter and power stage; TTL buffers, TRIG, the I²C expander) · C — the front panel board (the whole second board: the SMA field, the OLED, the LEDs, the TTL strip, the TX coil terminal and the Qwiic; the two isolated inputs; the module header with its 5 V buffer — seven outputs, MODULE OUT 1–7 plus a reserved spare pin, for driving opto-isolated modules outside the box). The instructor owns the base: the dev-board socket and the buses, the power entry and the rails, the external power input, the H-bridge and the polarizer switch.

Firmware drivers (the firmware calls each driver a block): base (dev board itself) · b1_inputs (ADS8688 8-ch ADC, analog-to-digital converter) · b2_power (rails) · b3_outputs (DAC8563 digital-to-analog converter + ±10 V) · b4_switching (7 module outputs, 2 isolated inputs) · b5_dio_trig (8 TTL out, 2 fast out, TRIG) · nmr (the console: pulse → free induction decay → spectrum). The drivers follow the sections: Section A b1_inputs and the receiver capture; Section B b3_outputs and b5_dio_trig; Section C b4_switching; b2_power is the instructor's. Protocol: firmware/PROTOCOL.md.

Until the class board arrives everything runs in SIM mode on a bare Jinhua ESP32-S3 N16R8 dev board (the development board: the microcontroller on a small board with a USB connector and pins): each driver fakes its hardware, so the app, the chart and the alarms all work from Workshop 1.

How this repository fits the course. Workshop 1: AI for experimentalists is Project 1 (a web app of your choice — a simulator or a game, built with the AI method) and Project 2 (your own phone app that controls the ESP32 over WiFi). The firmware and app in this repository are Step 1 of Project 2: every student flashes them onto their own board first — a known working hardware baseline, which separates hardware problems from software problems — then builds their own app in its own repository, reading this code for the access point, the WebSocket and the LED. They stay the fallback: flash them again if your own build stalls and you have a working app on the phone today. In Workshop 2: Designing printed circuit boards we design the class board together in KiCad — one board for everyone. They are also the base for Project 3 (from Workshop 3: Firmware and basic mechanical design (PCB housing)): your instrument — the firmware and the app that use the class board's capabilities, in a housing you design, presented on a great project website. You choose what instrument it is. The course ends with a project presentation and demonstration, 26–30 Oct.

The student package (everything you need is in this repository — the project folder whose complete history git keeps, stored online on GitHub)

WhatWhere
Setup (before Workshop 1)SETUP.md — paste the prompt from workbook ch. 0 into Claude Code and it installs the toolchain (the compiler and helper programs that turn source code into firmware)
Workbook — one chapter per workshop, each with a between workshops part ("Before the next workshop: complete the preparation, improve your apps, build and have fun."), the same text the tutor runsworkbook/: ch. 0 · ch. 1 · ch. 2 · ch. 3 · ch. 4 · A · B · C cheat-sheets
The section pages (documentation of the class board's hardware)workbook/blocks/: A — inputs and the NMR receiver · B — signal generation, timing and the NMR transmitter · C — the front panel board
The tutor (self-updating: fetches the latest guide and workbook from GitHub at the start of every session)/tutor L1 (etc.) in Claude Code — .claude/skills/tutor/, rules in tutor/COURSE-GUIDE.md
SlidesWorkshop 1 as a PDF on the course site: https://tigp-experimental-methods.github.io/slides/W1-AI-for-experimentalists.pdf (Workshop 2 and 3 slides follow the same way; see slides/README.md)
Firmware + app (Step 1 of Project 2 — the hardware baseline — and its fallback; the base of your Project 3 instrument)firmware/, host/ — flash it (write it onto the board over USB) in 5 commands below
The class project wall — one card per project (picture, title, student, two sentences, buttons Open the app · Project site · Video · Code), refreshed every minute, on the projector in class; every student pushes their own entries (workbook ch. 1, Put it on the class project wall). Project 3 — your instrument: its firmware, its app and the housing — is one repository, one project website and one cardhttps://tigp-experimental-methods.github.io/showcase-2026/ — repository https://github.com/TIGP-Experimental-Methods/showcase-2026 (its README documents the entry format)
KiCad library packagehardware/lib/ — project-local, nothing to unzip
Reference repositories for Project 1https://github.com/TIGP-Experimental-Methods/pendulum-example (cart-pole) · https://github.com/TIGP-Experimental-Methods/csv-scope-example (CSV → scope lab tool) — options, or a fork (your own copy of one of them on GitHub) if your session stalls
Course sitehttps://tigp-experimental-methods.github.io/

Flash in 5 commands (VS Code + PlatformIO)

Prerequisites: VS Code with the PlatformIO IDE extension (installs its own Python and pio), git, the dev board on a USB-C data cable plugged into the port marked USB (native USB, not UART).

sh
git clone https://github.com/TIGP-Experimental-Methods/class-board-2026.git
cd class-board-2026/firmware
pio run -e esp32s3-sim -t upload        # 1st time: downloads the toolchain
pio run -e esp32s3-sim -t uploadfs      # copies host/pwa/ to the board's LittleFS (its file store)
pio device monitor                      # watch it boot; note the AP name

(In VS Code: PlatformIO sidebar → esp32s3-sim → Upload, then Upload Filesystem Image, then Monitor.) If the upload cannot find a port: hold BOOT, tap RST, release BOOT, retry. Windows needs no driver for native USB. If the upload says "No serial data received" (a factory-fresh board, USB ID 303A:4001): hold BOOT, tap RST, release BOOT — the board comes back as 303A:1001 on a new COM port; pio device list again and flash to that port. Once only; the port also disappears and reappears at every reset, which is normal. All flashing and serial symptoms, and the secrets rule, are on one page: workbook ch. C, §C.2.

Open the app on your phone

  1. The board's RGB LED turns blue = it is an access point (its own WiFi network, which your phone joins). Serial monitor prints AP "instrument-XXXX" password "instrument".
  2. On the phone join WiFi instrument-XXXX, password instrument.
  3. Open http://192.168.4.1 in the browser (type the http://; stay connected when the phone warns about no internet, mobile data off on Android). Tap Red on the Base tab: the LED changes. The chart plots base.counter; pick another key from the dropdown.
  4. Add to Home screen gives an app icon. (Full "install" prompts need HTTPS, which the board does not have; the shortcut is enough.)

To use the lab WiFi instead: copy firmware/include/secrets.h.example to secrets.h, fill in SSID/password, and, if you want OTA (the update over WiFi), remove the // before OTA_PASSWORD and type a password of your own (left commented out, OTA stays off) — type the passwords into that file yourself, never into a Claude chat; the file is git-ignored (git check-ignore -v firmware/include/secrets.h prints a line) — and re-flash. For uploads over WiFi, copy firmware/secrets.ini.example to firmware/secrets.ini (git-ignored too), type the board's name and the same OTA password there, and run pio run -d firmware -e esp32s3-ota -t upload. The LED turns green and the board is at http://instrument-XXXX.local (mDNS: the board announces its own name on the local network, so no IP address is needed; XXXX is the same suffix as its access-point name, so several boards can share one network). If joining fails within 10 s it falls back to the AP.

Python client

sh
pip install -e host/            # or: uv pip install -e host/
instrument status
instrument send base led --args '{"r":0,"g":255,"b":0}'
instrument stream base.counter --seconds 5 --csv out.csv
instrument alarms list

It talks to 192.168.4.1 (the board's own access point); on a lab network give --host instrument-XXXX.local (XXXX = the last four hex digits of the MAC, printed in the boot log) or the IP address.

Add a driver (Workshop 3, exercise E11)

  1. Copy firmware/src/blocks/template/ → the driver folder of the block your instrument needs, e.g. firmware/src/blocks/b3_outputs/. Rename the class and name() → "b3".
  2. Write the SIM branch first: status() returns plausible fake values; handle() accepts your commands. Flash; your tab appears with a generic key/value view.
  3. Copy host/pwa/panels/template.js → panels/b3.js, set id: 'b3', replace the example control. Add it to PANELS in app.js. pio run -t uploadfs; reload the phone.
  4. Register the driver in firmware/src/main.cpp (one registry.add(&b3) line — the stub drivers are already registered, so you only replace the stub of the driver you are writing).
  5. Fill the #ifndef SIM branches with the real driver using the pin constants in firmware/include/pins.h; the chip's protocol, the signal path and the limits are in docs/class-board-reference.md (one subsection per capability, with a minimal snippet).
  6. Open a pull request (PR — a request to merge your changes into the shared project; someone reviews it first); CI (continuous integration — the automatic build GitHub runs on every pull request) builds both envs.

The rules: a driver talks only to its own hardware; all driver code runs from loop() (no tasks, no locks); every status key you show in the panel is one your status() emits.

The housing (Workshop 3, Project 3)

hardware/release/ holds the two board models (class-board.stl, front-panel.stl meshes and the STEP files, exported from the final KiCad boards with kicad-cli, keeping the connectors, LEDs and modules) and nothing else: the housing is yours to design, from the housing brief with Claude Code, in docs/students/<name>/housing/, starting by opening each board on its own in OpenSCAD; chapter 3 §A.6 has the steps, and SETUP.md Step 11 installs OpenSCAD and Bambu Studio.

Add an alarm rule

Rules are data: {block, key, op, threshold, action}, evaluated 20× per second on the same status the app sees; they fire once when the condition becomes true.

  • On the phone: Alarms tab → pick b1.ai1, gt, 9, action module 1 off → Add rule.
  • From a panel: api.addAlarm({ block: 'b2', key: 'v5_raw', op: 'lt', threshold: 4.9, action: 'notify' }) (see panels/template.js).
  • From Python: instrument alarms add --block b1 --key ai1 --op gt --threshold 9 --action module:1:off.

action is notify (toast on every phone, browser notification if allowed) or module:<n>:on|off (a module output on the front panel, Section C). Rules persist on the board in /alarms.json.

Layout

text
firmware/
  platformio.ini            envs esp32s3 (real), esp32s3-sim (-DSIM=1), esp32s3-ota (esp32s3 over WiFi)
  secrets.ini.example       OTA upload template (board name, OTA password)
  include/pins.h            GPIO map of the boards as ordered (docs/class-board-reference.md §3)
  include/secrets.h.example WiFi and OTA password template
  scripts/copy_pwa.py       pre-build: host/pwa -> firmware/data
  src/main.cpp              WiFi, mDNS, OTA, HTTP + WebSocket, 20 Hz broadcast
  src/blocks/Block.h        the 5-method driver interface
  src/blocks/Registry.*     list of drivers
  src/blocks/base/          LED, counter, temperature
  src/blocks/template/      copy-me block
  src/blocks/b1_inputs/ … b5_dio_trig/
  src/alarm/AlarmEngine.*   rules, block "alarms"
  PROTOCOL.md
host/
  pwa/                      index.html app.js style.css sw.js manifest, panels/*.js
  instrument.py, pyproject.toml
hardware/sections/                the main board split four ways BY AREA for routing (A rear right, B front right, C front left, D rear left); README.md there
hardware/scripts/main_sections.py  areas / split / check / merge / report for the main-board areas
hardware/front-panel/sections/    the front panel split four ways for routing (A analog, B digital, C modules, D isolated + power); README.md there
hardware/scripts/panel_sections.py  split / check / merge the four sections back into one board
docs/
  references.md             papers (NMR at low field), datasheets of every part, tools and suppliers
  class-board-reference.md  THE BOARD, PIN BY PIN: connectors, links, every chip's protocol, levels, limits, firmware state, known defects (netlist-derived, 2026-10-08)
  references/               the two Creative-Commons papers as PDF
.github/workflows/build.yml  both envs + ruff on every push/PR

Parts

342
QtyValueFootprintReferences
4010kResistor_SMD:R_0603_1608MetricR5, R6, R7, R8, R10, R102, R301, R303, R305, R307, R311, R706, R721, R724, R804, R805 +24
39100nFCapacitor_SMD:C_0603_1608MetricC108, C202, C208, C209, C212, C215, C302, C304, C305, C308, C501, C502, C503, C504, C507, C703 +23
1710uFCapacitor_SMD:C_0805_2012MetricC102, C106, C107, C203, C204, C211, C213, C216, C217, C303, C306, C307, C726, C727, C806, C811 +1
15BAV99class_board:SOT-23-3_L2.9-W1.6-P1.90-LS2.8-BRD111, D112, D113, D114, D115, D116, D117, D118, D301, D302, D501, D905, D906, D907, D908
1210nFCapacitor_SMD:C_0603_1608MetricC720, C804, C805, C817, C901, C902, C903, C904, C910, C911, C912, C913
101.00kResistor_SMD:R_0603_1608MetricR714, R723, R910, R911, R912, R913, R914, R916, R918, R923
81kResistor_SMD:R_0805_2012MetricR111, R112, R113, R114, R115, R116, R117, R118
81nFCapacitor_SMD:C_0603_1608MetricC111, C112, C113, C114, C115, C116, C117, C118
81uFCapacitor_SMD:C_0603_1608MetricC101, C103, C104, C210, C301, C704, C810, C930
840.2kResistor_SMD:R_0603_1608MetricR302, R304, R306, R308, R915, R917, R919, R924
7100Resistor_SMD:R_0603_1608MetricR704, R707, R710, R713, R816, R905, R931
7C2937625_-_Conn_01x03DDS_Library:C2937625-HDR-TH_3P-P2.54-V-MJ3, J9, J10, J11, J12, J14, J15
62.2kResistor_SMD:R_0603_1608MetricR203, R204, R205, R206, R207, R208
633Resistor_SMD:R_0603_1608MetricR1, R2, R101, R511, R703, R705
6600R@100MHzclass_board:L0603FB201, FB202, FB203, FB204, FB801, FB901
522uFCapacitor_SMD:C_1206_3216MetricC105, C201, C206, C207, C214
54.7kResistor_SMD:R_0603_1608MetricR3, R4, R211, R212, R941
5GREENclass_board:LED0805-R-RDD203, D204, D205, D206, D933
410.0kResistor_SMD:R_0603_1608MetricR712, R722, R901, R902
41kResistor_SMD:R_0603_1608MetricR209, R210, R821, R822
449.9Resistor_SMD:R_0603_1608MetricR309, R310, R509, R510
4M3class_board:MountingHole_3.2mm_M3H1, H2, H3, H4
3100kResistor_SMD:R_0603_1608MetricR811, R812, R942
3Fiducialclass_board:Fiducial_1mm_Mask2mmFID1, FID2, FID3
3Panel link 2x20 femaleConnector_PinSocket_2.54mm:PinSocket_2x20_P2.54mm_VerticalJ6, J7, J8
3SS54class_board:SMA_L4.4-W2.8-LS5.4-R-RDD801, D802, D930
2+3V3class_board:TestPoint_Pad_D1.5mmTP3, TP202
21.5A polyfuseclass_board:F1812F201, F202
2100pFCapacitor_SMD:C_0603_1608MetricC711, C721
2100uF 35Vclass_board:CAP-SMD_BD8.0-L8.3-W8.3-LS9.3-FDC921, C940
21N4148Wclass_board:SOD-123F_L2.7-W1.6-LS3.8-RDD703, D704
21kResistor_SMD:R_Array_Convex_4x0603RN501, RN502
2200Resistor_SMD:R_0603_1608MetricR802, R803
2270pFCapacitor_SMD:C_0603_1608MetricC914, C915
23.9pFCapacitor_SMD:C_0603_1608MetricC701, C702
247kResistor_SMD:R_0603_1608MetricR820, R940
25.1kResistor_SMD:R_0603_1608MetricR201, R202
274HCT125PWclass_board:TSSOP-14_L5.0-W4.4-P0.65-LS6.4-BLU302, U502
2B0512S-2WR3class_board:PWRM-TH_IBXX05S-2WR3PS201, PS202
2DNP-0RResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR715, R716
2KF301-5.0-2Pclass_board:CONN-TH_P5.00_KF301-5.0-2PJ901, J903
2LM66100DCKRclass_board:SC-70-6_L2.0-W1.3-P0.65-LS2.1-BLU201, U202
2OPA1612AIDRclass_board:SOIC-8_L5.0-W4.0-P1.27-LS6.0-BLU705, U706
2SMF5.0Aclass_board:SOD-123FL_L2.7-W1.8-LS3.8-RDD201, D202
2TS5A23157DGSRclass_board:MSOP-10_L3.0-W3.0-P0.50-LS5.0-BLU901, U902
1+12Vclass_board:TestPoint_Pad_D1.5mmTP203
1+5Vclass_board:TestPoint_Pad_D1.5mmTP4
1+5VAclass_board:TestPoint_Pad_D1.5mmTP205
1-12Vclass_board:TestPoint_Pad_D1.5mmTP204
10Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR717
11.2nFCapacitor_SMD:C_0603_1608MetricC710
110Resistor_SMD:R_0805_2012MetricR814
110Resistor_SMD:R_0603_1608MetricR932
110mRResistor_SMD:R_2512_6332MetricR933
110uFCapacitor_SMD:C_1206_3216MetricC818
111kResistor_SMD:R_0603_1608MetricR809
1120R@100MHz 3Aclass_board:L0603FB802
1130pFCapacitor_SMD:C_0603_1608MetricC809
115uHclass_board:IND-SMD_L3.2-W2.5-LQH32CN1R0M53LL801
11MResistor_SMD:R_0603_1608MetricR711
11kResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR718
120pFCapacitor_SMD:C_0603_1608MetricC807
122pFCapacitor_SMD:C_0603_1608MetricC712
125 MHzclass_board:CRYSTAL-SMD_4P-L3.2-W2.5-BLY701
1270Resistor_SMD:R_0603_1608MetricR808
132kResistor_SMD:R_0603_1608MetricR920
1390pFCapacitor_SMD:C_0603_1608MetricC808
14.7 1WResistor_SMD:R_2512_6332MetricR813
147pFCapacitor_SMD:C_0603_1608MetricC706
147uF 35Vclass_board:CAP-SMD_BD6.3-L6.6-W6.6-FDC815
15A fastclass_board:F1206F901
15V_RAWclass_board:TestPoint_Pad_D1.5mmTP201
16.49kResistor_SMD:R_0603_1608MetricR807
16.8kResistor_SMD:R_0603_1608MetricR801
174HC74D,653class_board:SOIC-14_L8.7-W3.9-P1.27-LS6.0-BLU702
178L05G-AB3-Rclass_board:SOT-89-3_L4.5-W2.5-P1.50-LS4.2-BRU203
1910Resistor_SMD:R_0603_1608MetricR815
1AD9834BRUZclass_board:TSSOP-20_L6.5-W4.4-P0.65-LS6.4-BLU801
1ADS8688IDBTRclass_board:TSSOP-38_L9.7-W4.4-P0.50-LS6.4-BLU101
1AMS1117-3.3class_board:SOT-223-3_L6.5-W3.4-P2.30-LS7.0-BRU204

The 313 most common of 342 parts.

More from TIGP-Experimental-Methods/class-board-2026

1
  • 4 layers180 × 100 mmFront panel, the printed circuit board in 3D

    Front panel

    TIGP-Experimental-Methods/class-board-2026

    TIGP class instrument 2026: one board, five blocks - KiCad hardware, ESP32-S3 firmware, phone PWA, Python API, workbook

    76 parts

Similar boards

  • 4 layers123.6 × 90.8 mmPlayduino sheep tester, the printed circuit board in 3D

    Playduino sheep tester

    playduino/sheep-tester

    Raspberry Pi 4B HAT for Playduino Sheep EOL factory test

    201 parts1MIT
  • 4 layers127.8 × 56.1 mmController, the printed circuit board in 3D

    Controller

    sudo-junkie/Controller

    ESP32-based replacement PCB for UCOM USB game controller, with LCD, IMU, IR TX/RX and more...

    105 parts1
  • 4 layers100 × 100 mmTtf ng a v1, the printed circuit board in 3D

    Ttf ng a v1

    gingerologist/ttf-ng-a-v1

    kicad 10 project for board A for ttf project, release.

    209 parts
  • 2 layers75.3 × 51.7 mmBoost Converter, the printed circuit board in 3D

    Boost Converter

    shahariyar-maraz/Gizantechbd

    32 parts
  • 4 layers170 × 170 mmDutlink, the printed circuit board in 3D

    Dutlink

    the78mole/jumpstarter-mono

    This is a monorepo containing all jumpstarter tools and (hopefully) adds a standalone server soon.

    144 partsApache-2.0
  • 6 layers53.9 × 35.5 mmPDNode PDCard-5031, the printed circuit board in 3D

    PDNode PDCard-5031

    DvidMakesThings/HW_PDNode-600-Pro

    The PDNode-600 is a professional-grade, 600W USB Power Delivery Unit designed specifically for compact 10-inch rack systems, targeting embedded developers, homelab enthusiasts, test benches, and smart infrastructure.

    125 parts86AGPL-3.0
  • 4 layers115 × 55 mmRoamr motors, the printed circuit board in 3D

    Roamr motors

    uw-roamr/roamr

    turn your phone into a robot running SLAM with two motors, two control boards, and a bluetooth chip

    110 parts6

Questions

How big is the Class board V0.2 PCB?

It measures 180 × 100 mm and has 4 copper layers, 1.61 mm thick.

What parts does the Class board V0.2 use?

342 parts, built around the 74HCT125PW,118-JSM, B0512S-2WR3, OPA1612AIDRGR and ADS8688IDBTR. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Class board V0.2 KiCad files?

From the TIGP-Experimental-Methods/class-board-2026 repository on GitHub, at the commit this page was made from: the board is hardware/V0.2/class-board_V0.2.kicad_pcb. PCBKit opens the board in the browser, with nothing to install.

Can I use the Class board V0.2 design in my own project?

Its repository states no licence, so its author keeps all rights: ask TIGP-Experimental-Methods before reusing the design.