Openflight
No description available
Install / Use
/learn @jewbetcha/OpenflightREADME
[!WARNING] This project is in active development. Features may be incomplete, unstable, or change without notice. Expect bugs and breaking changes. Contributions and bug reports are welcome!
Overview
OpenFlight is an open-source golf launch monitor that measures ball speed using a commercial Doppler radar sensor. The OPS243-A from OmniPreSense provides professional-grade speed measurement (±0.5% accuracy) in a simple USB-connected package.
What It Measures
- Ball Speed: 30-220 mph range with ±0.5% accuracy
- Club Speed: Detected from pre-impact readings
- Smash Factor: Ball speed / club speed ratio
- Estimated Carry Distance: Based on ball speed (simplified model)
- Launch Angle (optional): With Raspberry Pi camera module
- Horizontal Angle (experimental): With K-LD7 angle radar module
- Spin Rate (experimental): Via rolling buffer I/Q analysis (~50-60% detection rate)
Hardware
| Component | Description | Cost | | -------------- | -------------------------- | --------- | | OPS243-A | OmniPreSense Doppler Radar | ~$225 | | Raspberry Pi 5 | (or any computer with USB) | ~$80 | | USB Cable | Micro USB to connect radar | ~$5 | | Total | | ~$310 |
Optional: | Component | Description | Cost | | -------------- | -------------------------- | --------- | | SparkFun SEN-14262 | Sound detector for rolling buffer trigger (spin detection) | ~$12 | | RFbeam K-LD7 + EVAL Board | 24 GHz angle/distance radar (experimental) | ~$200 |
See docs/PARTS.md for the full parts list including camera module, sound trigger wiring, and angle radar setup.
Quick Start
Installation
# Clone the repository
git clone https://github.com/jewbetcha/openflight.git
cd openflight
# Run the setup script (installs Python + Node dependencies, builds UI)
./scripts/setup.sh
Basic Usage (CLI)
# Run the launch monitor
openflight
# Specify serial port manually
openflight --port /dev/ttyACM0
# Show live readings
openflight --live
# Show radar info
openflight --info
Web UI
# Run the UI server with radar
openflight-server
# Run in mock mode (no radar needed, for development)
openflight-server --mock
# Disable camera (auto-enabled if available)
openflight-server --no-camera
# Use rolling buffer mode for spin detection
openflight-server --mode rolling-buffer
# Rolling buffer with sound trigger (requires SparkFun SEN-14262)
openflight-server --mode rolling-buffer --trigger sound
Then open http://localhost:8080 in a browser.
For kiosk mode on Raspberry Pi (fullscreen):
./scripts/start-kiosk.sh
See docs/raspberry-pi-setup.md for complete Raspberry Pi setup instructions including auto-start and camera configuration.
Python API
from openflight import LaunchMonitor
# Simple usage
with LaunchMonitor() as monitor:
print("Swing when ready...")
shot = monitor.wait_for_shot(timeout=60)
if shot:
print(f"Ball Speed: {shot.ball_speed_mph:.1f} mph")
print(f"Est. Carry: {shot.estimated_carry_yards:.0f} yards")
# Continuous monitoring with callbacks
from openflight import LaunchMonitor
def on_shot(shot):
print(f"Shot detected: {shot.ball_speed_mph:.1f} mph")
monitor = LaunchMonitor()
monitor.connect()
monitor.start(shot_callback=on_shot)
# ... do other things ...
stats = monitor.get_session_stats()
print(f"Average ball speed: {stats['avg_ball_speed']:.1f} mph")
Low-Level Radar Access
from openflight import OPS243Radar
# Direct radar control
with OPS243Radar() as radar:
# Get radar info
info = radar.get_info()
print(f"Firmware: {info.get('Version')}")
# Configure for golf
radar.configure_for_golf()
# Read speeds
while True:
reading = radar.read_speed()
if reading:
print(f"{reading.speed:.1f} {reading.unit}")
Setup Guide
1. Connect the Radar
Connect the OPS243-A to your computer via USB. The radar will appear as a serial device:
- Linux/Raspberry Pi:
/dev/ttyACM0or/dev/ttyUSB0 - macOS:
/dev/tty.usbmodem* - Windows:
COM3(or similar)
2. Position the Radar
For best results, position the radar 3-5 feet behind the tee, pointing at the hitting area. The radar has a 23° beam width.
Ball Flight Direction
======================>
[Tee] ←--- 3-5 ft ---→ [OPS243-A Radar]
↓
Points at ball
Important: The radar measures radial velocity (speed toward/away from sensor). For accurate readings, the ball should travel roughly along the radar's line of sight.
3. Run the Monitor
openflight
The system will automatically detect the radar, configure it for golf ball detection, and start monitoring.
How It Works
Doppler Radar Basics
The OPS243-A transmits a 24 GHz signal. When this signal bounces off a moving object (the golf ball), the frequency shifts proportionally to the object's speed - this is the Doppler effect.
The relationship is:
Speed = (Doppler_Frequency × c) / (2 × Transmit_Frequency)
At 24.125 GHz, each 1 mph of speed creates a ~71.7 Hz Doppler shift.
Golf Ball Detection
Golf balls are challenging targets for radar due to:
- Small size: ~1.68" diameter
- Low RCS: Radar cross-section of ~0.001 m²
- High speed: 100-180+ mph for well-struck shots
- Brief detection window: Ball is in range for < 100ms
The OPS243-A handles this with:
- High transmit power (11 dBm typical)
- 15 dBi antenna gain
- 24 GHz frequency (short wavelength suits small objects)
- Fast sampling (up to 100k samples/sec)
Based on link budget analysis, the OPS243-A should reliably detect golf balls at 4-5 meters (13-16 feet), making the 3-5 foot positioning ideal.
System Architecture
The data flows from radar to UI like this:
┌─────────────┐ USB/Serial ┌─────────────┐ Callback ┌─────────────┐ WebSocket ┌─────────────┐
│ OPS243-A │ ───────────▶ │ Launch │ ──────────▶ │ Flask │ ──────────▶ │ React │
│ Radar │ Speed data │ Monitor │ on_shot() │ Server │ "shot" │ UI │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
-
Radar streams data - The OPS243-A continuously sends speed readings over USB serial whenever it detects motion
-
LaunchMonitor processes readings - A background thread reads serial data, accumulates readings, and when there's a gap (no readings for 0.5s), analyzes the data to create a
Shotobject with ball speed, club speed, and smash factor -
Callback fires - When a shot is detected, the callback function registered via
monitor.start(shot_callback=...)is called with theShotobject -
Server broadcasts to clients - The Flask server's callback converts the shot to JSON and emits it to all connected browsers via WebSocket
-
React updates UI - The
useSockethook receives the event and updates state, triggering a re-render with the new shot data
This callback pattern keeps the components decoupled - LaunchMonitor doesn't know about Flask or WebSockets, it just calls whatever function you give it.
Configuration
The radar can be configured via API commands:
from openflight import OPS243Radar, SpeedUnit, Direction
radar = OPS243Radar()
radar.connect()
# Set units to MPH
radar.set_units(SpeedUnit.MPH)
# Increase sample rate for faster balls (up to 139 mph at 20kHz)
radar.set_sample_rate(20000)
# Filter out slow movements
radar.set_min_speed_filter(20) # Ignore < 20 mph
# Only detect outbound (ball going away)
radar.set_direction_filter(Direction.OUTBOUND)
# Save to persistent memory
radar.save_config()
Key Settings for Golf
| Setting | Value | Why | | ----------- | -------- | --------------------------- | | Sample Rate | 20 kHz | Supports up to ~139 mph | | Buffer Size | 512 | Faster updates (~10-15 Hz) | | Min Speed | 10 mph | Filter slow movements | | Direction | Outbound | Ball moving away from radar | | Power | Max (0) | Best detection range |
Limitations
What OpenFlight Does NOT Measure (Yet)
- Side Spin / Curve: Requires multiple sensors or camera
Note: Launch Angle is available with the optional camera module. See Camera Setup. Spin Rate is available experimentally via rolling buffer mode (see docs/rolling_buffer_spin_detection.md).
Accuracy Considerations
- Distance estimates are rough: Without launch angle and spin, carry distance is estimated using a simplified model (~2.5 yards per mph of ball speed)
- Cosine error: If ball doesn't travel directly toward/away from radar, measured speed will be slightly lower than actual
- Detection is probabilistic: Very fast shots with weak returns may be missed
Troubleshooting
"No OPS243 radar found"
- Check USB connection
- Try a different USB cable
- Check if device appears:
ls /dev/tty*(Linux/Mac) - Try specifying port manually:
openflight --port /dev/ttyACM0
Weak or No Detection
- Move radar closer to hitting area (try 3 feet)
- Ensure radar is pointing at ball flight path
- Check for obstructions
- Try increasing transmit power: `ra
