Complete guide for setting up OpenFlight on a Raspberry Pi 5 with the 7" touchscreen display.
Make sure you have all the hardware. See the Parts List for what to buy.
Required:
- Raspberry Pi 5 (4GB+ recommended)
- 7" Touchscreen Display
- MicroSD Card (32GB+)
- 27W USB-C Power Supply (official Pi 5 PSU recommended)
- OPS243-A Doppler Radar + USB cable
- SparkFun SEN-14262 sound detector (wired per the Sound Trigger Wiring Guide)
Optional:
- K-LD7 + FTDI adapter (×2) — for launch angle and club path (see Parts List)
Use Raspberry Pi Imager to flash Raspberry Pi OS (64-bit) to your SD card.
Plug in the OPS243-A (and the K-LD7 adapters if you have them), then:
cd ~
git clone https://github.com/jewbetcha/openflight.git
cd openflight
./scripts/setup/setup.shThe script installs everything, then walks you through the one-time hardware configuration with prompts:
- Dependencies — Python venv, packages, UI build, test run
- OPS243-A radar — saves rolling buffer mode to the radar's flash (you'll be asked to unplug/replug the radar once)
- K-LD7 radars (if you have them) — identifies each radar by plugging them in one at a time, so OpenFlight always knows which is which
- Auto-start on boot — optional systemd service
- Desktop shortcut — optional
Every step can be skipped and the script is safe to re-run any time — it picks up where you left off.
./scripts/start-kiosk.sh # Default: rolling buffer + sound trigger
./scripts/start-kiosk.sh --kld7 # With K-LD7 angle radars
./scripts/start-kiosk.sh --mock # Mock mode (no hardware)Then open http://localhost:8080 or use the touchscreen.
To send shots to GSPro, OpenGolfSim, or another supported sim, copy the example config and enable your simulator:
cp config/sim.example.json config/sim.json # then edit host/port + "enabled": trueSee Simulator Connectors for the full guide.
You don't need this section unless something went wrong or you prefer to do things by hand.
The OPS243-A needs a one-time configuration to enable rolling buffer mode with hardware sound triggering, saved to flash so it boots correctly every time.
Why? The OPS243-A has a firmware bug where the HOST_INT pin mode switches unexpectedly when entering rolling buffer mode at runtime. Saving to flash and power cycling bypasses this. Confirmed by OmniPreSense engineering.
Manual steps
# 1. Configure and save to flash
uv run python scripts/hardware-test/test_rolling_buffer_persist.py --setup
# 2. Power cycle: unplug the radar's USB cable, wait 3 seconds, plug back in
# 3. Verify — make a sound near the SEN-14262, you should see I/Q trigger data
uv run python scripts/hardware-test/test_rolling_buffer_persist.py --testUSB serial adapters can swap between /dev/ttyUSB0 and /dev/ttyUSB1 after a
reboot, so OpenFlight needs fixed names (/dev/kld7_vertical and
/dev/kld7_horizontal) to tell the two radars apart. The wizard handles this —
you just plug each radar in when asked:
./scripts/setup/setup_kld7_devices.sh # run / redo the mapping
./scripts/setup/setup_kld7_devices.sh --show # check the current mappingIt also installs the FTDI low-latency rule (the K-LD7 RADC stream runs at
3 Mbaud and needs latency_timer=1ms instead of the Linux default 16ms).
On startup, the server logs should show both radars at 1ms:
[KLD7:vertical] USB serial latency_timer=1ms ...
[KLD7:horizontal] USB serial latency_timer=1ms ...
Manual steps (what the wizard does)
Find each adapter's serial number:
udevadm info -a /dev/ttyUSB0 | grep '{serial}' | head -1
udevadm info -a /dev/ttyUSB1 | grep '{serial}' | head -1Create a udev rule with the serial numbers (replace FTXXXXXX/FTYYYYYY):
sudo tee /etc/udev/rules.d/99-kld7.rules << 'EOF'
SUBSYSTEM=="tty", ATTRS{serial}=="FTXXXXXX", SYMLINK+="kld7_vertical"
SUBSYSTEM=="tty", ATTRS{serial}=="FTYYYYYY", SYMLINK+="kld7_horizontal"
EOF
sudo udevadm control --reload-rules && sudo udevadm triggerThen install the latency rule:
sudo scripts/setup/setup_kld7_latency.shUse --dry-run to preview the rule, or --all-ftdi if the /dev/kld7_*
names aren't set up yet.
The setup script installs and enables a systemd service configured for your username and install path.
Manual steps and service management
# Install (adjust User= and paths in the file if your username isn't the default)
sudo cp ~/openflight/scripts/setup/openflight.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable openflight
sudo systemctl start openflightManagement:
sudo systemctl status openflight --no-pager # Check status
journalctl -u openflight -f # View logs
sudo systemctl stop openflight # Stop
sudo systemctl restart openflight # Restart
sudo systemctl disable openflight # Disable auto-startTo modify the service:
sudo nano /etc/systemd/system/openflight.service
sudo systemctl daemon-reload
sudo systemctl restart openflight- Vertical unit — measures launch angle. Mount with the antenna plane vertical, aimed at the hitting area.
- Horizontal unit — measures club path / aim direction. Mount with the antenna plane horizontal.
Both should be positioned near the OPS243-A, 3-5 feet behind the tee.
The vertical K-LD7 geometry estimator needs the physical mount tilt, ball-to-radar distance, and boresight offset to match real launch angles.
- Start a session with
--kld7-geometry - Hit 5-10 shots with a known club (7-iron recommended)
- Compare reported launch angles to expected values:
- Wedge: 24-30°, 7-iron: 16-18°, 5-iron: 12-14°, Driver: 10-14°
- Keep
--kld7-mount-tiltand--kld7-ball-distancematched to the physical setup; adjust--kld7-angle-offsetfor a stable boresight bias.
The current field preset is mount tilt 10°, ball distance 5ft, and angle
offset +2.5°. The exact values depend on your mounting position.
See K-LD7 Troubleshooting for more details.
./scripts/start-kiosk.sh # Default: rolling buffer + sound trigger
./scripts/start-kiosk.sh --kld7-geometry # With K-LD7 launch-angle geometry defaults
./scripts/start-kiosk.sh --mock # Mock mode (no hardware needed)openflight-server # With radar
openflight-server --mock # No hardwareThen open http://localhost:8080.
DISPLAY=:0 ./scripts/start-kiosk.shOpenFlight can ship session logs to Grafana Cloud for long-term analysis.
sudo ./scripts/setup/setup_alloy.sh
sudo vim /etc/alloy/credentials.envSee observability.md for full setup and LogQL queries.
ls /dev/ttyACM* /dev/ttyUSB*
openflight --port /dev/ttyACM0 --infoSee the Sound Trigger Wiring Guide — Troubleshooting.
# Check the device mapping
./scripts/setup/setup_kld7_devices.sh --show
# Test standalone
uv run python scripts/hardware-test/test_kld7.pyIf the mapping is missing or points at the wrong radar, re-run the wizard:
./scripts/setup/setup_kld7_devices.sh. Look for [KLD7] Connected on /dev/ttyUSB... in the server logs. See K-LD7 Troubleshooting
for "Wrong length reply" and other connection issues.
journalctl -u openflight --no-pager -n 50
# If service is masked
sudo systemctl unmask openflight
sudo cp ~/openflight/scripts/setup/openflight.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable openflightCheck for WebSocket instability:
journalctl -u openflight -fLook for "Client disconnected/connected" messages.
Use DISPLAY=:0 prefix for commands that need the Pi's display.
./scripts/start-kiosk.sh # Default
./scripts/start-kiosk.sh --mock # No hardware
./scripts/start-kiosk.sh --kld7-geometry # With angle radar
./scripts/start-kiosk.sh --port 3000 # Custom portopenflight-server # Start with radar
openflight-server --mock # Mock mode
openflight-server --web-port 3000 # Custom port./scripts/setup/setup.sh # Full interactive setup (re-run safe)
./scripts/setup/setup.sh --deps-only # Dependencies only
./scripts/setup/setup_kld7_devices.sh # K-LD7 device naming wizard
./scripts/setup/setup_kld7_devices.sh --show # Show current K-LD7 mappinguv run python scripts/hardware-test/test_rolling_buffer_persist.py --test # Sound trigger
uv run python scripts/hardware-test/test_sound_trigger_hardware.py # Direct trigger test
uv run python scripts/hardware-test/test_kld7.py # K-LD7 standalone
uv run pytest tests/ -v # Full test suite