PhotoCar — Complete Build & Wiring Guide
GPIO12 is dead/shorted-to-ground on this board, so PWM stays on GPIO18; DIR moved from the older GPIO23 to GPIO16. PWM and DIR are at opposite ends of the header, so this is not a single 1×3 plug. Source: motor-control/scripts/provision-photocar.sh.1. Bill of Materials & Specs
| Part | Qty | Specification | Terminals / role |
|---|---|---|---|
| Raspberry Pi Zero 2 W (or 2 WH) | 1 | 65 × 30 mm; 4× M2.5 on 58 × 23 mm; BCM43430 BLE 4.2 + WiFi; 40-pin J8 header | Runs the photocar-ble service; PWM/DIR out on GPIO18/16 |
| Cytron MD25HV motor driver | 1 | Single 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 mm | Power VB+/VB−, motor MA/MB; control GND/5VO/PWM/DIR |
| 12 V wiper-style gear motor | 1 | ~100 RPM; ~2.4 Ω → ~5.3 A / ~68 W running at 12.8 V; ~179 mm overall, Ø9.5 D-shaft | Two armature leads → MA/MB; park-switch taps unused |
| 12 V 10 Ah LiFePO4 battery (A & B) | 2 | 12.8 V nominal, 20 A limit; 151 × 65 × 94 mm; F2 spade terminals | POS/NEG → A/B/OFF selector |
| A/B/OFF battery selector | 1 | Rotary selector, red ring | Chooses pack A, pack B, or OFF |
| Emergency stop + master On/Off (DPST) | 1 ea | E-stop cutoff; DPST master switch | In series between Main(+) bus and Switched(+) bus |
| Bus bars | 4 | Main(+), Main(−), Switched(+), Switched(−) | Distribution to MD25HV + buck |
| 5 V DC-DC buck converter | 1 | 67 × 38 × 14 mm; holes 61.05 × 31.45 mm; set output 5.1 V, ≥ 3 A | INP/INN in, OUTP/OUTN out → Pi 5 V |
| Onboard LiFePO4 charger + inlet | 1 | 14.6 V 10 A LiFePO4 charger; 120 V AC charge inlet | Charges the pack(s) in place |
| Electronics mounting plate | 1 | 180 × 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 enclosure | 1 | Bolt-down case, side port cutout (board_case_*) | Houses MD25HV / Pi / buck |
| 7" touchscreen | 1 | HDMI + USB touch | Runs the PhotoCar kiosk UI |
| 2.54 mm connector housings + signal wire | 1 | 22–26 AWG; 1×2 for PWM+GND, plus a DIR lead | Pi control: PWM pin 12, GND pin 14, DIR pin 36 |
| Single center knobby wheel, chain, sprockets | set | One-stage chain reduction | Motor → chain → center drive wheel |
2. Parts — Reuse, Buy & Budget
Conservative list including the small wiring and mounting parts that usually get missed. Buy the genuine Raspberry Pi from a trustworthy listing; save money on generic wiring, housings, heat-shrink, standoffs, fuse holders, and buck converters — never by removing the Pi fuse, undersizing the 5 V regulator, or powering the Pi from the MD25HV 5VO.
Reuse from the existing car
| Part | Use | Notes |
|---|---|---|
| Cytron MD25HV motor driver | Motor power stage | Keep existing motor + battery screw-terminal wiring if it already runs the motor. |
| Charger, XT60 leads, power distribution | Charging / wiring | A LiFe-capable charger handles the 4S LiFePO4 pack; reuse XT60s and distribution. |
| 12 VDC gear motor + connector | Drive motor | Leave motor wiring as heavy-current wiring — never route motor current into GPIO harnesses. |
| Enclosure, glands, lever connectors, loom | Mounting / service | Reuse where practical; add strain relief where wires leave the box. |
Buy / add
| Part | Qty | Minimum spec | Why |
|---|---|---|---|
| 4S LiFePO4 battery pack | 1–2 | 12.8 V nominal (14.6 V full), 10 Ah, balance lead; BMS ≥ 20 A continuous | Main power. 12.8 V matches the 12 V motor. Two packs + A/B/OFF selector for runtime. |
| Raspberry Pi Zero 2 WH (or 2 W + soldered header) | 1 | Onboard BLE, 40-pin header | WH saves soldering. Runs the photocar-ble service. |
| microSD card | 1 | 16–32 GB, reputable brand | Raspberry Pi OS + control program. |
| 5 V DC-DC buck converter | 1 | Input 8–30 V; output 5.1 V; ≥ 3 A (LM2596/MP1584) | Powers the Pi from the 12.8 V bus. Set to 5.1 V before connecting the Pi. |
| Inline fuse holder + fuses | 1 | Mini blade, 2 A to start | Protects the buck/Pi branch. |
| Pre-crimped 1-pin Dupont leads | 20–40 | 22–26 AWG, 2.54 mm | Each conductor starts as a 1-pin lead, then loads into housings. |
| 2.54 mm connector housings | assort. | 1×3, 1×4, plus 1×2 / 2×n | Build keyed groups: the Pi control plug and power plugs. |
| 18 AWG red/black wire | 6–10 ft | Stranded copper | Battery branch to fuse, switch, buck input. |
| 22–26 AWG signal wire | 3–6 ft | Blue / black / purple | PWM, GND, DIR control leads. |
| Ferrules / heat-shrink / zip ties / M2.5 nylon standoffs | sets | Match gauges | Clean terminations, strain relief, and a non-conductive Pi mount. |
| Multimeter | 1 | DC volts + continuity | Required to verify buck output before plugging the Pi. |
Optional add-ons
| Part | Include when |
|---|---|
| Pi Camera Module + Zero CSI ribbon | The car should capture photos/video (narrow Pi-Zero ribbon). |
| Micro-USB OTG adapter | Setup / rescue access before BLE is stable. |
| Low-current status LED/buzzer (via resistor/driver) | Boot/control status feedback — never drive high current from GPIO. |
3. 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.
4. Control Wiring — Pi to MD25HV
The MD25HV runs in PWM/DIR mode. Three wires connect it to the Pi: PWM = GPIO18 (physical pin 12), DIR = GPIO16 (physical pin 36), and a shared GND. GPIO18 is used because GPIO12 is dead/shorted-to-ground on this board. PWM (pin 12) and DIR (pin 36) sit at opposite ends of the header, so they are not one 1×3 plug — pair PWM with the adjacent ground on pin 14, and run DIR as its own keyed lead.
Pi Zero header → MD25HV
| Pi physical pin | Pi signal | MD25HV terminal | Wire |
|---|---|---|---|
| Pin 12 | GPIO18 (PWM0) | PWM | Blue — motor speed |
| Pin 14 | GND | GND | Black — common reference (next to PWM) |
| Pin 36 | GPIO16 | DIR | Purple — direction |
| — | no connection | 5VO | Leave empty / unwired |
Connector plan
- Pi side: a 1×2 housing on pins
12 / 14(PWM = GPIO18, GND), and a separate keyed lead forDIRon pin36(GPIO16). PWM and DIR are at opposite ends of the header. - MD25HV side: land on the green control screw terminal at the
PWM,GND, andDIRpositions; use ferrules. - The
5VOterminal stays empty. Do not use it to power the Pi. - Do not use loose single-pin jumpers for the PWM/GND pair — they shake loose in a moving car. Secure the DIR lead with a tie.
- Pi GPIO is 3.3 V and the MD25HV accepts it directly. No level shifter needed.
MD25HV board — connect here, not there
The MD25HV has more than one control area. Ignore the small manual potentiometer/rocker headers (those were for standalone manual control). For Pi/software control, land on the green control screw terminal silk-screened GND / 5VO / PWM / DIR. Battery power goes to the high-current terminals on the opposite edge: VB+, VB−, and the motor on MA / MB. Match the printed labels on your physical board before powering anything.
MA / MB. The 5VO terminal stays empty — never use it to power the Pi.DIR_FORWARD_LEVEL=1 (forward = DIR high). PWM is hardware-timed at 1 kHz on PWM channel 0 via dtoverlay=pwm,pin=18,func=2; on boot the firmware sets GPIO18 to its ALT5 PWM function with pinctrl. If the motor spins the wrong way, swap the two motor leads or flip DIR_FORWARD_LEVEL.
5. 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.
| From | To | Method | Notes |
|---|---|---|---|
Battery A/B POS / NEG | A/B/OFF selector | F2 spade | Selector picks pack A, B, or OFF. |
| Selector out (+) | Main(+) bus | Bus bar | Single main positive distribution. |
| Main(+) bus | E-stop → On/Off (DPST) | Inline | E-stop then master switch in series. |
| On/Off out | Switched(+) bus | Bus bar | Everything downstream is switch-controlled. |
| Switched(+) bus | MD25HV VB+ | Screw / ferrule | Heavy wire (motor current). |
| Switched(+) bus | Buck INP | Screw / solder | Battery voltage in — not from MD25HV 5VO. |
Battery NEG | Main(−) / Switched(−) bus | Bus bar | Common ground. |
| Switched(−) bus | MD25HV VB− + Buck INN | Screw / ferrule | Motor + buck return. |
Buck OUTP/OUTN | Pi 5 V input | Existing Pi power method | Verify 5.1 V with a meter before plugging the Pi. |
MD25HV MA/MB | Wiper motor armature leads | Screw terminal | Swap leads to invert direction. |
| Charge inlet (120 V AC) | Onboard 14.6 V LiFePO4 charger → pack | Inlet + leads | Charges in place; do not drive while charging. |
Soldered Y-split harness (positive & negative distribution)
Where the switched bus feeds both the MD25HV and the buck, a clean removable harness is a soldered Y-split rather than soldering directly to fixed components:
- Cut one trunk wire (from the switched bus / switch output) and two branch wires (MD25HV + buck).
- Slide adhesive-lined heat-shrink onto the trunk before soldering.
- Strip enough insulation that the three copper ends overlap mechanically; twist the two branches together, then wrap with the trunk.
- Solder so it flows through the joint, not just on the outside; let it cool without movement.
- Cover with the adhesive heat-shrink; add an outer sleeve or cable wrap if the harness will vibrate.
- Repeat for the negative side. Use heavier wire on the MD25HV branch (motor current) than on the buck branch.
5VO is not wired to the Pi. Lift the wheel off the ground for the first motor test.
6. 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
- Run on the Pi from the repo:
bash scripts/provision-photocar.sh(idempotent; reboots if the boot config changed). - Installs
bluetooth bluez nodejs npm, adds the kiosk user togpio, writes the PWM overlay, builds the app, enables the service. - Verify the PWM hardware actually drives:
bash scripts/provision-photocar.sh selftest(looks for the channel reportingenabled).
Service environment (the source of truth for pins)
| Variable | Value | Meaning |
|---|---|---|
PWM_GPIO | 18 | Throttle PWM on GPIO18 / PWM0 (physical pin 12). GPIO12 is dead on this board. |
DIR_GPIO | 16 | Direction on GPIO16 (physical pin 36). |
PWM_FREQUENCY_HZ | 1000 | 1 kHz hardware PWM (period 1 ms). Keep ≤~1 kHz — the MD25HV only responds at 100% duty near 20 kHz. |
MAX_THROTTLE | 100 | Throttle is clamped 0–100%. |
WATCHDOG_TIMEOUT_MS | 1200 | Motor stops if no command arrives within 1.2 s. |
DIRECTION_CHANGE_PAUSE_MS | 20 | Ramps to 0 then pauses before reversing. |
WIFI_CONTROL_PORT / HOST | 7777 / 0.0.0.0 | WiFi TCP control listener. |
BLUETOOTH_ENABLED | 1 | BLE GATT control enabled (BCM43430, HCI 4.2). |
PHOTOCAR_REAL_MOTOR | 1 | 1 = drive real GPIO/PWM; 0 = dry run. |
{"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.
7. Assembly Steps
1. Bench-test the Pi before installing it
Image Raspberry Pi OS and enable Bluetooth; on the Pi run bash scripts/provision-photocar.sh.
Pair the tablet/controller while on USB bench power.
Confirm PWM hardware drives: bash scripts/provision-photocar.sh selftest before touching car wiring.
2. Mount the Pi and buck converter
Vacuum debris from the enclosure; mount the Pi on non-conductive standoffs on the electronics plate.
Place the buck close enough to keep the 5 V leads short; keep the Pi antenna area clear of metal and large bundles.
Keep low-current electronics away from the battery terminals and motor leads.
3. Add the fused, switched buck branch
Install the fuse close to the bus tap, not next to the Pi; verify buck input polarity before connecting power.
Set buck output to 5.1 V with a meter before plugging into the Pi.
4. Build the control harness from 1-pin pre-crimp leads
Build a 1×2 housing for PWM + GND (GPIO18 pin 12 / GND pin 14) and a separate keyed lead for DIR (GPIO16 pin 36), in the same order as the wiring table.
Tug-test each lead after insertion; if a crimp backs out, replace that lead. Label the harness before plugging it in.
Do not solder loose wires directly to the Pi header — serviceable connectors survive a moving car.
5. Connect to the MD25HV control terminal only
Land on the MD25HV green control screw terminal (GND / 5VO / PWM / DIR), not the heavy motor terminals; leave 5VO empty.
Keep existing motor screw-terminal wiring intact. After plugging in, check continuity from Pi GND to MD25HV GND.
First motor test at low throttle with the wheel lifted off the ground.
8. Bring-Up Checklist
- Selector set, E-stop released, master switch off until checks pass.
- MD25HV power polarity and buck input polarity verified with a meter.
- Buck output set and verified at 5.1 V before plugging the Pi.
- MD25HV
5VOis not connected to the Pi. - Control wiring: PWM on pin 12 (GPIO18), GND on pin 14, DIR on pin 36 (GPIO16), landing on MD25HV
PWM / GND / DIRby label. - Boot config has
dtoverlay=pwm,pin=18,func=2and the Pi has been rebooted since. provision-photocar.sh selftestpasses (PWM channel reports enabled).- Wheel lifted off the ground for the first
forward/backtest; confirm direction, then test STOP and the 1.2 s watchdog. - If direction is reversed: swap the two motor leads or flip
DIR_FORWARD_LEVEL.
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.