
Data port x4
kartben/hw-testing-rack
3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer

3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer
Bay node is an open-source printed circuit board by kartben, from the kartben/hw-testing-rack repository on GitHub. It is a 4-layer board of 74 × 90 mm with 135 parts on 93 nets, routed with 1,082 tracks and 446 vias.
It is built around the ESP32-S3-WROOM-1-N8R8, TJA1462AT/0Z and INA226AIDGSR, with the USBLC6-2SC6, AP2114H-3.3TRG1 and FSUSB42MUX among its other parts. Its parts include 37 resistors, 27 capacitors, 13 ICs, 7 diodes and 6 connectors. It belongs with the ESP32 boards of this library.
An all-printed, tilted test rack for development boards (12 in its default 4 × 3 layout) — every board in its own sliding drawer, power-switched, current-metered and exposed over the network with USB/IP by a Zephyr-powered ESP32-S3 in each bay.

▶ Interactive 3D model · Logic analyzer · BOM · Architecture · Mechanics · Cabling · Power · Electronics · Assembly · Firmware · Standalone bays · CI
config/rack.yaml:
OpenSCAD parts, KiCad schematics and PCBs (schematic-as-code, Freerouting),
the BOM with LCSC part numbers, and the interactive viewer.![]() | ![]() |
| Bay B3 pulled out, still connected: a DATA ×4 at the back serves two XIAOs and two Pico 2s | The DATA ×4 up close: a USB-C lead per board, Dupont jumpers wiring a UART between two of them (real models) |
![]() | ![]() |
| Row B: the GIGA's LVGL screen in B2, between two DATA ×4 bays | Bay node — ESP32-S3 (8 MB PSRAM), 2 USB muxes, TPS26600 eFuse, INA226, CAN, 60 V buck |
Neutral technical renders: the rack, one bay exploded, side view.
config/rack.yaml single source of truth (rows, bays, tilt, dimensions, population)
mechanical/ OpenSCAD: lib/, parts/, boards/boards.yaml, generated/ (from the config)
electronics/
tools/ schematic-as-code (eda.py), PCB builder (pcbgen.py), catalogue, LCSC resolver
bay-node/ design.py + generated KiCad project, fab/, docs/
power-hub/ design.py + generated KiCad project, fab/, docs/
data-port-x6/ the drawer's DATA ×6, six USB-C, power only (the default): design.py + KiCad, fab/, docs/
data-port-x4/ the DATA ×4 v2, four USB-C and the logic, for bays with wires: design.py + KiCad, fab/, docs/
data-port/ the single-port board, retired from the rack, kept for the standalone Solo box
camera-pod/ the camera pod's board (lead, camera header, 3.3 V, LEDs): design.py + KiCad, fab/, docs/
lib/ custom symbol(s), cached JLC basic passives
site/ GitHub Pages: three.js viewer + BOM page (assets generated)
bom/ full rack BOM (CSV + summary)
render/ Blender scene + photoreal renders
tools/ build.py (config/STL/web), kicad.sh, bom.py, jlc_mcp.py, notice/ (FreeCAD line art)
docs/ design documentationPrerequisites: Python ≥ 3.10 with pyyaml numpy trimesh (pip install -r tools/requirements.txt),
Docker (for KiCad 10, Freerouting and — if not installed locally — OpenSCAD).
python tools/build.py all # config → STLs → web viewer assets
tools/kicad.sh bay-node --route --fab # schematic, PCB, autoroute, Gerbers/BOM/CPL, renders
tools/kicad.sh power-hub --route --fab
tools/kicad.sh data-port-x6 --fab # fab outputs of the routed board, no re-route
tools/kicad.sh data-port-x4 --fab
tools/kicad.sh camera-pod --route --fab
python tools/bom.py # full rack BOM
python -m http.server -d site 8000 # open http://localhost:8000Generated outputs (STLs, Gerbers, renders, PDFs, GLBs, the BOM) are committed with the change that alters
them, never for a date: python tools/keep_unchanged.py puts back every regenerated file whose content didn't
change (tools/kicad.sh … --fab runs it on its board).
For screenshots the viewer takes URL parameters: ?bay=B4&openbay=1&view=dut&hideui
pulls bay B4's drawer out and frames its DUT cable (DATA port to board), with no UI.
?bay=B2&view=camera&camlight=1&preview=B2 looks into a camera bay with its LEDs on and opens what
its camera sees (an Arducam Mega with a ~120° lens: fisheye, noise, auto-exposure and JPEG, at 5 fps).
The viewer lights the rack like the photos: a real room (Poly Haven's "Small Empty Room 1", CC0, cut to
512 × 256 in site/assets/env/), AgX with Blender's "Medium High Contrast" look, PETG with its layer lines.
Its High quality box (on by default on a desktop GPU, off on phones and small GPUs, and dropped by itself
under 25 fps) adds ambient occlusion (GTAO), a glow on the status LEDs and the camera lights, 4× MSAA through
the post-processing and 4096² sun shadows; ?quality=high or ?quality=low forces one for screenshots.
Photoreal renders (Blender + Cycles) start from render/assembly.glb, baked
from the same scene as the viewer by python tools/assembly_glb.py --hq (--hq:
full-resolution part meshes instead of the viewer's lighter ones). Either
render headless in Docker (tools/render.sh hero) or drive a Blender you
already have open — GPU and all — through the Blender MCP add-on's socket:
python tools/blender_live.py exec render/live_scene.py # (re)build the scene
python tools/blender_live.py exec render/live_render.py hero # → docs/img/hero.jpg
python tools/blender_live.py exec render/live_render.py drawer:B3 docs/img/drawer.jpg
python tools/assembly_glb.py --hq --explode-bay B2 --out render/bay-exploded.glb # one bay, layers apart
python tools/blender_live.py exec render/live_scene.py render/bay-exploded.glb
python tools/blender_live.py exec render/live_render.py explodedThe photo shots (docs/img/photo-*.jpg) use their own scene: a small office
lit through a window, PETG with 0.2 mm layer lines and
rounded edges, scanned oak and plaster (CC0 textures from Poly Haven), a laptop
showing a Zephyr shell, wired to bay B4 by a USB-C cable that hangs as a real
one would (a catenary), depth of field, bloom and a vignette, rendered at 2× and averaged down:
python tools/fetch_render_assets.py # CC0 textures + vendor board models → render/assets/
python tools/board_models.py # normalise the board models (docs/boards-3d.md)
python render/screen_terminal.py # the laptop's screen → render/assets/
node tools/lvgl_frame.mjs music 480 800 # B2's GIGA display: one frame of the viewer's LVGL demo
# (the drawer fronts' status screens: assembly_glb.py draws them)
python tools/assembly_glb.py --hq --with-pc-cable --open-bays B3 --out render/assembly-photo.glb
python tools/blender_live.py exec render/live_photo.py build
python tools/blender_live.py exec render/live_photo.py shot desk # desk, drawer, detail → docs/img/photo-*.jpgChange the rack in config/rack.yaml (tilt, rows, columns, panel thickness,
which bays get cameras, which board sits where) and rebuild.
v0.2 — the printed panel frame replaces the aluminium frame, not yet
built. Mechanics are printable and parametric, the power box included;
still to design: double-width bays (see mechanical.md).
Each drawer front carries the node's 1.9" touch display, waiting on the
module to check its fit before a test print. Five PCBs (bay node, power hub,
DATA port, DATA ×4 v2, camera pod) pass ERC and DRC, are routed and smoothed,
and went through a schematic review
(schematic-review-2026-10-25.md) and a
datasheet audit; none is fabricated yet (see
electronics.md). The node firmware:
firmware.md.
Board outlines marked verified: false in boards.yaml are approximate.
Hardware (mechanical and electronics design files): CERN-OHL-P-2.0. Software (tools, viewer, firmware): Apache-2.0. See LICENSE.
| Qty | Value | Footprint | References |
|---|---|---|---|
| 14 | 100n | Capacitor_SMD:C_0603_1608Metric | C4, C5, C14, C16, C17, C18, C19, C22, C23, C24, C25, C26, C27, C28 |
| 10 | 10k | Resistor_SMD:R_0603_1608Metric | R3, R6, R7, R11, R17, R18, R20, R28, R30, R37 |
| 8 | 100k | Resistor_SMD:R_0603_1608Metric | R1, R2, R4, R13, R26, R27, R36, R39 |
| 6 | GND | TestPoint:TestPoint_Pad_D1.5mm | TP3, TP5, TP17, TP22, TP26, TP32 |
| 5 | 22u | Capacitor_SMD:C_1206_3216Metric | C7, C8, C9, C12, C13 |
| 5 | 33 | Resistor_SMD:R_0603_1608Metric | R8, R31, R32, R33, R34 |
| 4 | M3 | MountingHole:MountingHole_3.2mm_M3 | H1, H2, H3, H4 |
| 4 | USBLC6-2SC6 | Package_TO_SOT_SMD:SOT-23-6 | U4, U8, U12, U13 |
| 3 | 1k | Resistor_SMD:R_0603_1608Metric | R23, R24, R25 |
| 2 | +3V3 | TestPoint:TestPoint_Pad_D1.5mm | TP4, TP8 |
| 2 | 10u | Capacitor_SMD:C_1206_3216Metric | C2, C3 |
| 2 | 150k | Resistor_SMD:R_0603_1608Metric | R29, R42 |
| 2 | 18k | Resistor_SMD:R_0603_1608Metric | R5, R12 |
| 2 | 1u | Capacitor_SMD:C_0805_2012Metric | C20, C21 |
| 2 | 2.2k | Resistor_SMD:R_0603_1608Metric | R21, R22 |
| 2 | 2N7002 | Package_TO_SOT_SMD:SOT-23 | Q2, Q3 |
| 2 | 5.1k | Resistor_SMD:R_0603_1608Metric | R9, R10 |
| 2 | BAT54S | Package_TO_SOT_SMD:SOT-23 | D6, D7 |
| 1 | +5V | TestPoint:TestPoint_Pad_D1.5mm | TP7 |
| 1 | 0.75A | Fuse:Fuse_1206_3216Metric | F1 |
| 1 | 100u/50V | Capacitor_SMD:CP_Elec_8x10 | C1 |
| 1 | 10u | Capacitor_SMD:C_0805_2012Metric | C11 |
| 1 | 1u | Capacitor_SMD:C_0603_1608Metric | C15 |
| 1 | 22n | Capacitor_SMD:C_0603_1608Metric | C29 |
| 1 | 4.7u | Inductor_SMD:L_Changjiang_FXL0630 | L1 |
| 1 | 50m | bench:R_1206_3216Metric_Kelvin | R19 |
| 1 | 6.8k | Resistor_SMD:R_0603_1608Metric | R16 |
| 1 | 680 | Resistor_SMD:R_0603_1608Metric | R35 |
| 1 | AO3400A | Package_TO_SOT_SMD:SOT-23 | Q4 |
| 1 | AP2114H-3.3TRG1 | Package_TO_SOT_SMD:SOT-223-3_TabPin2 | U2 |
| 1 | AUX | Connector_JST:JST_PH_S6B-PH-SM4-TB_1x06-1MP_P2.00mm_Horizontal | J5 |
| 1 | AUX_BOOT_CTL | TestPoint:TestPoint_Pad_D1.0mm | TP30 |
| 1 | AUX_RST_CTL | TestPoint:TestPoint_Pad_D1.0mm | TP29 |
| 1 | AUX_RX | TestPoint:TestPoint_Pad_D1.0mm | TP28 |
| 1 | AUX_TX | TestPoint:TestPoint_Pad_D1.0mm | TP27 |
| 1 | BOOT | Button_Switch_SMD:SW_Push_1P1T_XKB_TS-1187A | SW2 |
| 1 | BOOT | TestPoint:TestPoint_Pad_D1.0mm | TP12 |
| 1 | BZT52C12 | Diode_SMD:D_SOD-123 | D1 |
| 1 | CAM | Connector_JST:JST_PH_B8B-PH-SM4-TB_1x08-1MP_P2.00mm_Vertical | J6 |
| 1 | CAM_5V | TestPoint:TestPoint_Pad_D1.5mm | TP10 |
| 1 | CAM_CS_P | TestPoint:TestPoint_Pad_D1.0mm | TP21 |
| 1 | CAM_MISO_P | TestPoint:TestPoint_Pad_D1.0mm | TP20 |
| 1 | CAM_MOSI_P | TestPoint:TestPoint_Pad_D1.0mm | TP19 |
| 1 | CAM_SCK_C | TestPoint:TestPoint_Pad_D1.0mm | TP18 |
| 1 | CAN_RXD | TestPoint:TestPoint_Pad_D1.0mm | TP24 |
| 1 | CAN_TXD | TestPoint:TestPoint_Pad_D1.0mm | TP23 |
| 1 | DATA | Connector_JST:JST_PH_S8B-PH-SM4-TB_1x08-1MP_P2.00mm_Horizontal | J7 |
| 1 | DATA_VIN | TestPoint:TestPoint_Pad_D1.5mm | TP9 |
| 1 | DFLS260-7 | Diode_SMD:D_PowerDI-123 | D8 |
| 1 | DUT_FLT_N | TestPoint:TestPoint_Pad_D1.0mm | TP13 |
| 1 | EN | TestPoint:TestPoint_Pad_D1.0mm | TP11 |
| 1 | ESP32-S3-WROOM-1-N8R8 | bench:ESP32-S3-WROOM-1_NoEPVias | U3 |
| 1 | I2C_SCL | TestPoint:TestPoint_Pad_D1.0mm | TP16 |
| 1 | I2C_SDA | TestPoint:TestPoint_Pad_D1.0mm | TP15 |
| 1 | INA226AIDGSR | Package_SO:TSSOP-10_3x3mm_P0.5mm | U10 |
| 1 | INA_ALERT_N | TestPoint:TestPoint_Pad_D1.0mm | TP14 |
| 1 | LMR51625YDDCR | Package_TO_SOT_SMD:TSOT-23-6 | U1 |
| 1 | MUX_DUT | Package_SO:MSOP-10_3x3mm_P0.5mm | U6 |
| 1 | MUX_PC | Package_SO:MSOP-10_3x3mm_P0.5mm | U5 |
| 1 | PC | Connector_USB:USB_C_Receptacle_GCT_USB4105-xx-A_16P_TopMnt_Horizontal | J3 |
| 1 | PESD2CAN | Package_TO_SOT_SMD:SOT-23 | D5 |
| 1 | POS_IN | TestPoint:TestPoint_Pad_D1.0mm | TP25 |
| 1 | POS_OUT | TestPoint:TestPoint_Pad_D1.0mm | TP31 |
| 1 | RESET | Button_Switch_SMD:SW_Push_1P1T_XKB_TS-1187A | SW1 |
| 1 | ROW IN | Connector_JST:JST_PH_S6B-PH-SM4-TB_1x06-1MP_P2.00mm_Horizontal | J1 |
| 1 | ROW OUT | Connector_JST:JST_PH_S6B-PH-SM4-TB_1x06-1MP_P2.00mm_Horizontal | J2 |
| 1 | SERVICE | Button_Switch_SMD:SW_SPDT_Shouhan_MSK12C02 | SW3 |
| 1 | SMBJ33A | Diode_SMD:D_SMB | D2 |
| 1 | SN74LVC1G32DBVR | Package_TO_SOT_SMD:SOT-23-5 | U7 |
| 1 | SUD50P06-15(UMW) | Package_TO_SOT_SMD:TO-252-2 | Q1 |
| 1 | TJA1462AT | Package_SO:SOIC-8_3.9x4.9mm_P1.27mm | U11 |
| 1 | TPS26600PWPR | Package_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask2.66x2.46mm | U9 |
| 1 | U0RX | TestPoint:TestPoint_Pad_D1.5mm | TP2 |
| 1 | U0TX | TestPoint:TestPoint_Pad_D1.5mm | TP1 |
| 1 | VIN | TestPoint:TestPoint_Pad_D1.5mm | TP6 |
| 1 | WS2812B-2020-V6 | LED_SMD:LED_WS2812B-2020_PLCC4_2.0x2.0mm | D4 |
It measures 74 × 90 mm and has 4 copper layers, 1.6 mm thick.
135 parts, built around the ESP32-S3-WROOM-1-N8R8, TJA1462AT/0Z, INA226AIDGSR and USBLC6-2SC6. 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.
From the kartben/hw-testing-rack repository on GitHub, at the commit this page was made from: the board is electronics/bay-node/bay-node.kicad_pcb and its schematic electronics/bay-node/bay-node.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Its repository states no licence, so its author keeps all rights: ask kartben before reusing the design.

kartben/hw-testing-rack
3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer

kartben/hw-testing-rack
3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer

kartben/hw-testing-rack
3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer

kartben/hw-testing-rack
3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer

kartben/hw-testing-rack
3D-printed, tilted test shelf for 16 dev boards: sliding drawers, per-bay ESP32-S3 running Zephyr (USB/IP, power switching, metering), KiCad PCBs, OpenSCAD parts, BOM and an interactive 3D viewer

Tinkerbug-Robotics/TinkerRocket
Model rocket flight computer, ground station, iOS app, and simulation

TomBonness/open-micro
Open-source USB/BLE desktop programming controller with RGB status integration

adamjvr/S1G-Mod
A Sub 1GHZ Wireless Module for various Sub 1GHZ projects and applications


open-pasture/opencollar
OpenCollar: a virtual-fence collar you can buy assembled or build from published parts.



JosueHerrera05/Josue_Herrera_Electiva_2026_C2
Repositorio Electíva Diseño Mecatrónico 2026-C2