PhotoCar — Assembly & Wiring Guide

Current build, June 25, 2026. Control-side facts are read directly from the running firmware (motor-control/); part specs are the modeled PhotoCar parts.

ComputePi Zero 2 W
Motor driverCytron MD25HV
Control pins32 / 34 / 36
Power2× 12 V LiFePO4
Interface7" touch + BLE/WiFi
PWM = GPIO12 (PWM0), pin 32 DIR = GPIO16, pin 36 GND = pin 34 20 kHz hardware PWM Chain drive, single center wheel Never wire motor power to GPIO

1. Bill of Materials & Specs

PartQtySpecificationTerminals / role
Raspberry Pi Zero 2 W (or 2 WH)165 × 30 mm; 4× M2.5 on 58 × 23 mm; BCM43430 BLE 4.2 + WiFi; 40-pin J8 headerRuns the photocar-ble service; PWM/DIR out on GPIO12/16
Cytron MD25HV motor driver1Single channel, 7–58 V, 25 A, PWM/DIR mode (not I²C); PCB 111.76 × 60.96 × 1.6 mm; 4× Ø3 on 106.68 × 55.88 mmPower VB+/VB−, motor MA/MB; control GND/5VO/PWM/DIR
12 V wiper-style gear motor1~100 RPM; ~2.4 Ω → ~5.3 A / ~68 W running at 12.8 V; ~179 mm overall, Ø9.5 D-shaftTwo armature leads → MA/MB; park-switch taps unused
12 V 10 Ah LiFePO4 battery (A & B)212.8 V nominal, 20 A limit; 151 × 65 × 94 mm; F2 spade terminalsPOS/NEG → A/B/OFF selector
A/B/OFF battery selector1Rotary selector, red ringChooses pack A, pack B, or OFF
Emergency stop + master On/Off (DPST)1 eaE-stop cutoff; DPST master switchIn series between Main(+) bus and Switched(+) bus
Bus bars4Main(+), Main(−), Switched(+), Switched(−)Distribution to MD25HV + buck
5 V DC-DC buck converter167 × 38 × 14 mm; holes 61.05 × 31.45 mm; set output 5.1 V, ≥ 3 AINP/INN in, OUTP/OUTN out → Pi 5 V
Onboard LiFePO4 charger + inlet114.6 V 10 A LiFePO4 charger; 120 V AC charge inletCharges the pack(s) in place
Electronics mounting plate1180 × 180 × 2 mm PLA, 22 holes (Pi M2.5 Ø3.4, MD25/buck M3 Ø3.8, grid/corner M4 Ø4.7)Bolts the board stack to the deck
3D-printed board enclosure1Bolt-down case, side port cutout (board_case_*)Houses MD25HV / Pi / buck
7" touchscreen1HDMI + USB touchRuns the PhotoCar kiosk UI
1×3 connector housing + signal wire12.54 mm, 22–26 AWGPi-side control plug on pins 32/34/36
Single center knobby wheel, chain, sprocketssetOne-stage chain reductionMotor → chain → center drive wheel

2. System Architecture

High-current drive power and low-current control signals stay on separate paths. The selected battery feeds a main bus, through the E-stop and master switch to a switched bus, which feeds both the MD25HV power input and the buck converter. The buck powers the Pi at 5 V. The Pi commands the MD25HV with three signal wires: PWM, DIR, and a shared GND.

Power current and control signals stay on separate paths Battery A / B 12.8 V LiFePO4 A/B/OFF selector E-stop + On/Off (DPST) via main bus Switched bus + / − MD25HV VB± in, MA/MB out Wiper Motor 12 V gear motor → chain → wheel 5 V Buck 5.1 V, ≥ 3 A MA/MB Pi Zero 2 W control firmware BLE + WiFi (7777) GPIO12 / GPIO16 7" Touchscreen kiosk UI 5 V PWM / DIR / GND HDMI+USB
Hard safety rule: never connect motor power, battery, or charger output to a Raspberry Pi GPIO pin. GPIO is a 3.3 V signal interface. Motor current lives only on the MD25HV power/motor screw terminals. The Pi sends only PWM and DIR plus a shared ground.

3. Control Wiring — Pi to MD25HV

The MD25HV runs in PWM/DIR mode. Three wires connect it to the Pi. Physical pins 32, 34, 36 are three adjacent pins on the outer (even-numbered) row of the header, so a single 1×3 housing covers all three with no gap.

Pi Zero header → MD25HV

Pi physical pinPi signalMD25HV terminalWire
Pin 32GPIO12 (PWM0)PWMBlue — motor speed
Pin 34GNDGNDBlack — common reference
Pin 36GPIO16DIRPurple — direction
no connection5VOLeave empty / unwired

Verified in provision-photocar.sh (PWM_GPIO=12, DIR_GPIO=16) and MotorController.ts.

Connector plan

  • Pi side: one 1×3 housing over physical pins 32 / 34 / 36, wire order GPIO12 / GND / GPIO16.
  • MD25HV side: land on the green control screw terminal at the PWM, GND, and DIR positions; use ferrules.
  • The 5VO terminal stays empty. Do not use it to power the Pi.
  • Do not use three loose single-pin jumpers — they shake loose in a moving car.
  • Pi GPIO is 3.3 V and the MD25HV accepts it directly. No level shifter needed.
Pi Zero 40-pin header — control plug on pins 32 / 34 / 36 (outer row) View with the header along the top edge; odd pins inner row, even pins outer row. Pin 1 is at the left end. 12 odd pins (1..39) 30 32 34 36 38 1×3 control housing Pin 32 = GPIO12 / PWM0 → MD25HV PWM Pin 34 = GND → MD25HV GND Pin 36 = GPIO16 → MD25HV DIR
Cytron MD25HV board close-up with labeled terminals
The installed MD25HV. The green 4-pin control terminal (left) is silk-screened GND / 5VO / PWM / DIR. Land the Pi wires on PWM, GND, DIR by label. High-current MOTOR terminals are on the right.
12V wiper gear motor with multi-pin harness
The 12 V wiper gear motor. Its connector carries the two armature (drive) leads plus park-switch taps. Only the two armature leads go to the MD25HV MA/MB terminals; swap them if forward/reverse comes out inverted.
Direction sense and PWM mode: firmware default is DIR_FORWARD_LEVEL=1 (forward = DIR high). PWM is hardware-timed at 20 kHz on PWM channel 0 via dtoverlay=pwm,pin=12,func=4; on boot the firmware sets GPIO12 to its ALT0 PWM function with pinctrl. If the motor spins the wrong way, swap the two motor leads or flip DIR_FORWARD_LEVEL.

4. Power Wiring

The car's power path is: selected battery → main bus → E-stop → master On/Off (DPST) → switched bus → MD25HV power input and buck converter. Negatives return through the Main(−) and Switched(−) bus bars. The buck output powers the Pi at 5 V, which also establishes the Pi–MD25HV common ground through the control cable.

FromToMethodNotes
Battery A/B POS / NEGA/B/OFF selectorF2 spadeSelector picks pack A, B, or OFF.
Selector out (+)Main(+) busBus barSingle main positive distribution.
Main(+) busE-stop → On/Off (DPST)InlineE-stop then master switch in series.
On/Off outSwitched(+) busBus barEverything downstream is switch-controlled.
Switched(+) busMD25HV VB+Screw / ferruleHeavy wire (motor current).
Switched(+) busBuck INPScrew / solderBattery voltage in — not from MD25HV 5VO.
Battery NEGMain(−) / Switched(−) busBus barCommon ground.
Switched(−) busMD25HV VB− + Buck INNScrew / ferruleMotor + buck return.
Buck OUTP/OUTNPi 5 V inputExisting Pi power methodVerify 5.1 V with a meter before plugging the Pi.
MD25HV MA/MBWiper motor armature leadsScrew terminalSwap leads to invert direction.
Charge inlet (120 V AC)Onboard 14.6 V LiFePO4 charger → packInlet + leadsCharges in place; do not drive while charging.
3D-printed electronics enclosure render
The 3D-printed electronics enclosure (render). Six top mounting holes bolt the board stack down; the side cutout passes the wiring. The MD25HV photo above shows this case in white.
Raspberry Pi OS desktop with START PHOTOCAR launcher
Pi OS desktop with the START PHOTOCAR launcher. Provisioning enables desktop autologin + X11 and a no-blank entry so the kiosk comes up on boot and the screen never sleeps.
Before first power-up: measure the pack at full charge, verify MD25HV power polarity and buck input polarity, set the buck to 5.1 V and confirm it at the Pi end, and confirm MD25HV 5VO is not wired to the Pi. Lift the wheel off the ground for the first motor test.

5. Software & Control

The Pi runs motor-control (TypeScript/Node) as the systemd service photocar-ble.service, installed by scripts/provision-photocar.sh. It accepts drive commands over Bluetooth LE, a WiFi TCP control port, and the on-car touchscreen kiosk.

Provisioning a fresh Pi

Service environment (the source of truth for pins)

VariableValueMeaning
PWM_GPIO12Throttle PWM on GPIO12 / PWM0 (physical pin 32).
DIR_GPIO16Direction on GPIO16 (physical pin 36).
PWM_FREQUENCY_HZ2000020 kHz hardware PWM (period 50 µs).
MAX_THROTTLE100Throttle is clamped 0–100%.
WATCHDOG_TIMEOUT_MS1200Motor stops if no command arrives within 1.2 s.
DIRECTION_CHANGE_PAUSE_MS20Ramps to 0 then pauses before reversing.
WIFI_CONTROL_PORT / HOST7777 / 0.0.0.0WiFi TCP control listener.
BLUETOOTH_ENABLED1BLE GATT control enabled (BCM43430, HCI 4.2).
PHOTOCAR_REAL_MOTOR11 = drive real GPIO/PWM; 0 = dry run.

Boot config line written by the provisioner: dtoverlay=pwm,pin=12,func=4 (GPIO12 reaches the PWM block via ALT0). Reboot once after first adding it.

PhotoCar touchscreen control UI
The on-car 7" kiosk UI. Top status bar shows state, direction, and throttle. Throttle presets 25/50/75/100% + HOLD, then FORWARD / BACK / STOP / POWER DOWN, plus WiFi and EXIT.
Driving commands: over BLE or the WiFi port the car accepts JSON like {"cmd":"drive","dir":"forward","throttle":50,"seq":1}, plus stop, ping, and (when ALLOW_SHUTDOWN=1) power-off. The 1.2 s watchdog stops the motor if commands stop arriving, so a dropped link fails safe. Pack-voltage telemetry on the UI requires an ADC/voltage divider wired to the Pi (BATTERY_VOLTAGE_FILE); until then the UI marks battery as not configured.

6. Bring-Up Checklist

Source Notes

Control-side facts (pins, PWM mode, frequency, service env, provisioning, kiosk UI) are read from the live firmware in motor-control/ — primarily scripts/provision-photocar.sh and src/MotorController.ts. Part specifications (MD25HV, Pi Zero 2 W, buck, battery, motor, mounting plate, bus/selector/E-stop power chain) are the modeled PhotoCar parts.