SkillAgentSearch skills...

Openflight

No description available

Install / Use

/learn @jewbetcha/Openflight
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<p align="center"> <img src="./ui/public/openflightlogo.svg"> DIY Golf Launch Monitor using the OPS243-A Doppler Radar. </p> <p align="center"> <a href="https://buymeacoffee.com/colemangolfs"> <img src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-support-yellow?style=for-the-badge&logo=buy-me-a-coffee&logoColor=white" alt="Buy Me a Coffee" /> </a> </p>

[!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/ttyACM0 or /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      │
└─────────────┘              └─────────────┘             └─────────────┘             └─────────────┘
  1. Radar streams data - The OPS243-A continuously sends speed readings over USB serial whenever it detects motion

  2. 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 Shot object with ball speed, club speed, and smash factor

  3. Callback fires - When a shot is detected, the callback function registered via monitor.start(shot_callback=...) is called with the Shot object

  4. Server broadcasts to clients - The Flask server's callback converts the shot to JSON and emits it to all connected browsers via WebSocket

  5. React updates UI - The useSocket hook 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"

  1. Check USB connection
  2. Try a different USB cable
  3. Check if device appears: ls /dev/tty* (Linux/Mac)
  4. Try specifying port manually: openflight --port /dev/ttyACM0

Weak or No Detection

  1. Move radar closer to hitting area (try 3 feet)
  2. Ensure radar is pointing at ball flight path
  3. Check for obstructions
  4. Try increasing transmit power: `ra
View on GitHub
GitHub Stars269
CategoryDevelopment
Updated1h ago
Forks24

Languages

Python

Security Score

90/100

Audited on Apr 1, 2026

No findings