"libdrone — PSB-1 Payload Shield Board: Perfboard Build Guide"
About¶
Step-by-step guide to building the PSB-1 Payload Shield Board on 2.54mm perfboard. No PCB design skills required. Estimated time: one evening. This is the prototype build — the circuit is proven, tested, and documented. A formal KiCad PCB comes later. Build this first.
What the PSB-1 does¶
Every libdrone payload currently hand-wires the same five components: MOSFET, two diodes, LDO regulator, and pull-up resistors. You make one mistake per build and spend an evening debugging. The PSB-1 builds these once, correctly.
After this build, a payload is:
1. Plug the two GX12 pigtails into the PSB-1 headers
2. Plug the ESP32-S3 dev board into the MCU headers
3. Connect your sensor to the I2C or UART header
4. Flash libdrone.py + your sensor code
5. Done
Tools required¶
- Soldering iron (fine tip, 350°C)
- Solder (0.6mm, leaded or lead-free)
- Side cutters
- Multimeter
- 2.54mm perfboard (at least 20×15 holes — a standard 7×5cm board is fine)
- Helping hands or small vice
Bill of materials¶
| Qty | Part | Value / Part number | Where to get | ~Cost |
|---|---|---|---|---|
| 2 | N-ch MOSFET | IRLML6344 SOT-23 | Mouser / LCSC | €0.30 ea |
| 2 | Signal diode | 1N4148 | Any electronics supplier | €0.05 ea |
| 1 | LDO regulator | MCP1700-3302E SOT-23 | Mouser / Farnell | €0.40 |
| 1 | Resistor | 10kΩ 1/4W through-hole | Any | €0.02 |
| 2 | Resistor | 10kΩ 1/4W through-hole | Any | €0.02 ea |
| 1 | Capacitor | 100nF ceramic | Any | €0.05 |
| 1 | Capacitor | 10µF electrolytic or ceramic | Any | €0.10 |
| 1 | LED | Any colour | Any | €0.05 |
| 1 | Resistor | 1kΩ (LED current limiter) | Any | €0.02 |
| 1 | Switch | Latching SPDT miniature | Any | €0.50 |
| 2 | Header | 2.54mm 6-pin female | Any | €0.20 ea |
| 1 | Header | 2.54mm dual-row 20-pin female | Any | €0.30 |
| 1 | Perfboard | 2.54mm, 7×5cm | Any | €0.50 |
| 2m | Wire | 28 AWG, several colours | Any | €1.00 |
| 2 | GX12-7 female | Cable mount | AliExpress | €1.50 ea |
Total component cost: approximately €8
Note on SOT-23 packages: these are small (3mm × 1.5mm) but hand-solderable with a fine tip. If uncomfortable with SMD, use through-hole equivalents: - MOSFET: 2N7000 (TO-92) instead of IRLML6344 - LDO: MCP1700-3302E is available in TO-92 package — specify when ordering
Circuit description (read before soldering)¶
The PSB-1 implements four things:
1. Master enable (MOSFET + diode-OR)
Conn A PIN 1 (5V) ──────────────────── MOSFET Drain
MOSFET Source ──► 5V_SW (payload rail)
Physical switch ──┐
├──► Diode ──► 10kΩ ──► MOSFET Gate
AUX GPIO1 ────────┘──► Diode ──┘
Pull-down 10kΩ from Gate to GND ensures MOSFET is OFF when both inputs are LOW.
Either the physical switch OR the radio GPIO can turn the payload on. Both OFF = MOSFET OFF = zero current draw from drone battery.
2. 3.3V regulation
5V_SW ──► 100nF ──► MCP1700 IN ──► MCP1700 OUT ──► 10µF ──► 3V3
↓
ESP32-S3, sensors
The LDO is downstream of the MOSFET — when master enable is OFF, the LDO has no input, the ESP32-S3 is unpowered. Zero standby current.
3. Status LED
5V_SW ──► 1kΩ ──► LED ──► GND
When master enable is active, the LED illuminates. Pre-flight visual check.
4. GPIO protection
AUX GPIO1 (Conn B PIN 5) ──► 10kΩ ──► GPIO1 header pin
AUX GPIO2 (Conn B PIN 6) ──► 10kΩ ──► GPIO2 header pin
Protects the FC's GPIO output from any wiring mistakes on the payload side.
Build sequence¶
Step 1 — Cut and prepare the perfboard¶
Cut a piece approximately 20×15 holes (50mm × 38mm). File the edges smooth. Mark the top surface with a permanent marker: "TOP — components this side."
Step 2 — Plan your layout¶
Before soldering anything, lay out all components dry on the board. Suggested layout zones (left to right):
[GX12-A header] [MOSFET circuit] [LDO + caps] [MCU headers] [GX12-B header]
6 pins IRLML6344 ×2 MCP1700 2×10 pins 6 pins
1N4148 ×2
10kΩ ×3
The GX12 pigtail wires will be soldered directly to the header pins — these are the first and last columns of the board.
Step 3 — Install GX12-A header (J1, left)¶
Solder a 6-pin female header at the left edge of the board. Label pins 1–6 top to bottom: 5V, GND, UART4TX, UART4RX, SCL, SDA.
Route wires from your two GX12-A female connector pigtails to these pins: - GX12-A PIN 1 (red, 22AWG) → header pin 1 (5V) - GX12-A PIN 2 (black, 22AWG) → header pin 2 (GND) - GX12-A PIN 3 (blue, 28AWG) → header pin 3 (UART4TX) - GX12-A PIN 4 (blue, 28AWG) → header pin 4 (UART4RX) - GX12-A PIN 5 (green, 28AWG) → header pin 5 (SCL) - GX12-A PIN 6 (green, 28AWG) → header pin 6 (SDA)
Strain relief: zip-tie the cable to the board edge before soldering.
Step 4 — Install GX12-B header (J2, right)¶
Solder a 6-pin female header at the right edge. Label: GND, GPS, UART5TX, UART5RX, GPIO1, GPIO2.
Route wires from GX12-B female connector pigtails: - GX12-B PIN 1 (black, 28AWG) → GND (joins main GND) - GX12-B PIN 2 (green, 28AWG) → header pin 2 (GPS) - GX12-B PIN 3 (blue, 28AWG) → header pin 3 (UART5TX) - GX12-B PIN 4 (blue, 28AWG) → header pin 4 (UART5RX) - GX12-B PIN 5 (blue, 28AWG) → 10kΩ → header pin 5 (GPIO1) - GX12-B PIN 6 (blue, 28AWG) → 10kΩ → header pin 6 (GPIO2)
Step 5 — MOSFET master enable circuit¶
If using IRLML6344 SOT-23: Solder the SOT-23 onto three perfboard pads using fine tip and thin solder. SOT-23 pinout: PIN 1 = Gate, PIN 2 = Source, PIN 3 = Drain. The tab/flat face of the package faces up.
Solder small pieces of wire to each pin immediately after soldering the package — SOT-23 pads are tiny, easier to work with connections made before routing.
MOSFET wiring: - Drain → 5V from GX12-A PIN 1 - Source → 5V_SW rail (internal power rail) - Gate → junction of two 1N4148 cathodes + 10kΩ pull-down to GND
Diode-OR: - 1N4148 diode 1: Anode to physical switch output, Cathode to Gate - 1N4148 diode 2: Anode to GPIO1 (after 10kΩ protection resistor), Cathode to Gate - 10kΩ pull-down: Gate to GND
Physical switch: - Wire from GND to switch common - Wire from switch NO to 1N4148 anode - Mount switch to mast body — not to the perfboard itself
Step 6 — LDO 3.3V regulator¶
MCP1700-3302E SOT-23 pinout: PIN 1 = GND, PIN 2 = OUT (3.3V), PIN 3 = IN.
- IN → 5V_SW rail
- GND → main GND plane
- OUT → 3V3 rail
- 100nF ceramic cap between IN and GND (as close to LDO as possible)
- 10µF cap between OUT and GND
Step 7 — Status LED¶
- 5V_SW → 1kΩ resistor → LED anode → LED cathode → GND
- Mount LED so it is visible on the mast exterior
Step 8 — MCU headers¶
Solder a 2×10 (20-pin) dual-row female header for the ESP32-S3 dev board. The ESP32-S3 mini dev board is approximately 25×20mm — verify your specific board's pin spacing before soldering.
Route traces from the header pins to the appropriate signal sources: - ESP32 GPIO17 → UART4TX header pin (Conn A PIN 3) - ESP32 GPIO18 → UART4RX header pin (Conn A PIN 4) - ESP32 GPIO16 → GPS header pin (Conn B PIN 2) - ESP32 GPIO4 → GPIO1 header pin (Conn B PIN 5, after 10kΩ) - ESP32 GPIO5 → GPIO2 header pin (Conn B PIN 6, after 10kΩ) - ESP32 GPIO9 → SCL header pin (Conn A PIN 5) - ESP32 GPIO8 → SDA header pin (Conn A PIN 6) - ESP32 3V3 in → 3V3 rail from LDO - ESP32 GND → main GND
Use the PSB1_PINS dict in libdrone.py — if you wire differently, update
those pin numbers. The library adapts to any mapping.
Test sequence (before connecting to drone)¶
Test 1 — No shorts With no battery and no components powered, measure resistance between 5V rail and GND rail. Must be > 10kΩ. Any lower = short circuit. Find and fix before proceeding.
Test 2 — MOSFET logic (bench power supply, 5V, 500mA max) Connect 5V bench supply to GX12-A PIN 1/2 (not the drone — bench supply). - Physical switch OFF, GPIO1 LOW (leave unconnected): LED must be OFF. Measure 5V_SW rail — must be 0V or near 0V (MOSFET off). - Physical switch ON: LED must illuminate. Measure 5V_SW = 5V. - Switch OFF, connect GPIO1 to 3.3V: LED must illuminate. 5V_SW = 5V. - Both OFF again: LED off.
Test 3 — LDO output With 5V_SW active (switch or GPIO): measure 3V3 rail = 3.3V ± 0.1V.
Test 4 — Install ESP32-S3, flash libdrone test
Flash the minimal test sketch below. Open serial monitor at 115200 baud.
Expected output every second: libdrone OK | GPS: waiting | GPIO1: 0 | GPIO2: 0
Test 5 — GPS test
Connect GX12-B to a live drone (powered, no arming required).
Serial monitor should show: GPS: 50.123456, 14.456789, 312m, 14 sats
Test 6 — OSD test
Connect GX12-A to a live drone. Verify text appears in HDZero goggles.
Expected OSD line 1: PSB-1 TEST OK
Minimal test sketch (flash before first drone connection)¶
# psb1_test.py — Flash this to verify PSB-1 hardware before payload code
from libdrone import OSD, GPS, AUX, Power, version
import time
version()
osd = OSD()
gps = GPS()
aux = AUX()
pwr = Power(aux=aux)
count = 0
while True:
fix = gps.read()
g1 = aux.switch1()
g2 = aux.switch2()
if fix.valid:
gps_str = f'GPS:{fix.lat:.4f},{fix.lon:.4f} {fix.sats}S'
else:
gps_str = 'GPS: waiting...'
status = f'PSB1 OK {count:04d}'
# Print to serial monitor
print(f'libdrone OK | {gps_str} | GPIO1:{int(g1)} | GPIO2:{int(g2)}')
# Send to OSD (only works when connected to drone)
osd.write(status, row=1)
osd.write(gps_str, row=2)
osd.write(f'G1:{int(g1)} G2:{int(g2)} EN:{int(pwr.is_enabled())}', row=3)
count += 1
time.sleep(1)
Minimal sensor payload template¶
Copy this and replace the read_sensor() function with your hardware.
# my_payload.py — Minimal compliant payload template
# Replace read_sensor() with your sensor code.
# Everything else — GPS, OSD, logging, command handling — is handled.
from libdrone import OSD, GPS, Command, AUX, Power, Logger
import time
# ── Hardware init ──────────────────────────
osd = OSD()
gps = GPS()
cmd = Command(osd=osd) # shares UART4 with OSD
aux = AUX()
pwr = Power(aux=aux)
log = Logger('/sd/flight.csv')
# ── Your sensor init goes here ─────────────
# Example: from machine import I2C
# i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=400000)
# sensor = MySensor(i2c)
def read_sensor():
"""Replace with your sensor reading code. Return a dict."""
return {
'value_1': 0.0, # e.g. 'PM25': 34.2
'value_2': 0.0, # e.g. 'CO2': 412
}
# ── Main loop ──────────────────────────────
logging_active = False
log_open = False
while True:
# 1. Read GPS (non-blocking)
fix = gps.read()
# 2. Handle commands from FC
action = cmd.poll()
if action == 'ENABLE':
cmd.respond('OK')
elif action == 'DISABLE':
cmd.respond('OK')
elif action == 'LOG_START':
if not log_open:
log.open()
log_open = True
logging_active = True
cmd.respond('LOG_OK')
elif action == 'LOG_STOP':
logging_active = False
cmd.respond('OK')
elif action == 'STATUS':
state = 'LOG' if logging_active else 'IDLE'
cmd.respond(f'STATUS:{state},{log.row_count}rows')
# 3. Check AUX GPIO (radio switches)
if aux.switch1() and not logging_active:
if not log_open:
log.open()
log_open = True
logging_active = True
# 4. Read sensor
if pwr.is_enabled():
readings = read_sensor()
# 5. Write to OSD
osd.write(f"V1: {readings['value_1']:.1f}", row=1)
osd.write(f"V2: {readings['value_2']:.1f}", row=2)
osd.write(f"LOG:{'REC' if logging_active else 'OFF'} {log.row_count}", row=3)
if fix.valid:
osd.write(f"GPS:{fix.sats}S {fix.alt:.0f}m", row=4)
# 6. Log to SD card
if logging_active and log_open:
log.write(fix, readings)
time.sleep(1)
What to build next¶
Once the PSB-1 perfboard is proven across 10+ flights:
- KiCad design brief — Document this exact circuit with component footprints, trace routing rules, and board dimensions. Brief is the input to fabrication.
- JLCPCB order — Upload Gerbers + BOM for PCBA (assembled) option. At qty 10 with PCBA: approximately €12/board delivered.
- PSB-1 v1.0 release — KiCad files in GitHub
/hardware/psb-1/. Any payload builder in the world orders boards, plugs in ESP32-S3, done.
Revision History¶
| Version | Date | Author | Summary |
|---|---|---|---|
| 1.0.0 | 2026-03-29 | JS | Initial release. Perfboard build guide, test sequence, minimal payload template. |