Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Documentation

on:
push:
branches: [main, master]
paths:
- "docs/**"
- "zensical.toml"
- ".github/workflows/docs.yml"
pull_request:
paths:
- "docs/**"
- "zensical.toml"
- ".github/workflows/docs.yml"

permissions:
contents: read

concurrency:
group: docs-${{ github.ref }}
cancel-in-progress: true

jobs:
# Runs on every PR touching docs: a broken internal link or a bad config
# fails review instead of shipping.
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Build the docs site
run: uv run --group docs zensical build --clean --strict

deploy:
# Only main pushes deploy; PRs stop after the strict build above.
if: github.event_name == 'push'
needs: build
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/configure-pages@v6
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Build the docs site
run: uv run --group docs zensical build --clean
- uses: actions/upload-pages-artifact@v5
with:
path: site
- uses: actions/deploy-pages@v5
id: deployment
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ __pycache__/
*$py.class
*.so
.Python
build/
# Anchored: an unanchored `build/` also swallows docs/build/, the enclosure
# section of the docs site.
/build/
develop-eggs/
dist/
downloads/
Expand Down Expand Up @@ -77,8 +79,12 @@ ui/test-results/

.superpowers/

# Zensical docs site build output
/site/
.cache/

#Markdown preview files
.crossnote/config.js
.crossnote/head.html
.crossnote/parser.js
.crossnote/style.less
.crossnote/style.less
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ SEN-14262 GND → Pi GND (shared with OPS243-A)

A through-hole resistor must be soldered into **R17** on the SEN-14262 to reduce preamp gain at 3.3V (47kΩ recommended, lower for noisy environments).

See [docs/sound-trigger-wiring.md](docs/sound-trigger-wiring.md) for full instructions.
See [docs/sound-trigger-wiring.md](docs/build/sound-trigger.md) for full instructions.

**Trigger Latency:**
| Trigger | Latency | Description |
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ SEN-14262 GND → Pi GND (shared with OPS243-A)

A through-hole resistor must be soldered into **R17** on the SEN-14262 to reduce preamp gain at 3.3V (47kΩ recommended, lower for noisy environments).

See [docs/sound-trigger-wiring.md](docs/sound-trigger-wiring.md) for full instructions.
See [docs/sound-trigger-wiring.md](docs/build/sound-trigger.md) for full instructions.

**Trigger Latency:**
| Trigger | Latency | Description |
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ make format

### TypeScript/React

Use the checked-in [UI color palette](docs/color_palette.html) when adding or
Use the checked-in [UI color palette](docs/development/color-palette.md) when adding or
changing visual states.

```bash
Expand Down
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: test lint format dev build-ui start
.PHONY: test lint format dev build-ui start docs docs-build

## Run Python tests
test:
Expand Down Expand Up @@ -35,3 +35,11 @@ install:
## Install pre-commit hooks
hooks:
uv run pre-commit install

## Serve the docs site with live reload at http://localhost:8000
docs:
uv run --group docs zensical serve

## Build the docs site; fails on broken internal links
docs-build:
uv run --group docs zensical build --clean --strict
73 changes: 38 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,27 @@ Without an angle radar you still get ball speed, club speed, smash factor,
experimental spin, and estimated carry. The angle radar adds measured launch
angle and experimental club path.

> **⚠️ The K-LD7 angle radars are deprecated.** The supported angle radar is now the **TI IWR6843**. Don't buy K-LD7s for a new build; their software support remains for existing builds only. See the [full parts list](docs/PARTS.md) for details and links.
> **⚠️ The K-LD7 angle radars are deprecated.** The supported angle radar is now the **TI IWR6843**. Don't buy K-LD7s for a new build; their software support remains for existing builds only. See the [full parts list](docs/get-started/parts.md) for details and links.

> **The IWR6843 needs custom firmware** — the stock TI demo doesn't expose the raw radar cube OpenFlight needs. A validated prebuilt image ships in `firmware/releases/`, so flashing it doesn't require the TI toolchain. See the [IWR6843 Operator Guide](docs/iwr6843/README.md).
> **The IWR6843 needs custom firmware** — the stock TI demo doesn't expose the raw radar cube OpenFlight needs. A validated prebuilt image ships in `firmware/releases/`, so flashing it doesn't require the TI toolchain. See the [IWR6843 Operator Guide](docs/iwr6843/index.md).

## Getting Started

### 1. Get the parts

See the **[Parts List](docs/PARTS.md)** for everything you need with purchase links.
See the **[Parts List](docs/get-started/parts.md)** for everything you need with purchase links.

### 2. Wire it up

Follow the **[Sound Trigger Wiring Guide](docs/sound-trigger-wiring.md)** to connect the SEN-14262 to the OPS243-A. The (deprecated) K-LD7 modules connect via USB — no wiring needed.
Follow the **[Sound Trigger Wiring Guide](docs/build/sound-trigger.md)** to connect the SEN-14262 to the OPS243-A. The (deprecated) K-LD7 modules connect via USB — no wiring needed.

**Adding the IWR6843 angle radar?** The Pi cannot power both radars over USB, so
the OPS243 moves to the Pi's GPIO UART header while the TI board takes the USB
port. Do it in this order, validating each step before the next — doing both at
once makes any failure ambiguous:

1. **[Move the OPS243 from USB to the Pi GPIO UART](docs/ops243-uart-migration.md)** — rewire and confirm the OPS still triggers on its own.
2. **[IWR6843 Operator Guide](docs/iwr6843/README.md)** — wire, flash the firmware, mount, aim, and measure geometry.
1. **[Move the OPS243 from USB to the Pi GPIO UART](docs/build/ops243-uart.md)** — rewire and confirm the OPS still triggers on its own.
2. **[IWR6843 Operator Guide](docs/iwr6843/index.md)** — wire, flash the firmware, mount, aim, and measure geometry.

If your OPS243-A has **WiFi**, you cannot use the GPIO UART — its WiFi module
already drives the radar's UART receive line. Use a separately powered USB hub
Expand All @@ -87,10 +87,7 @@ cd openflight
The script installs everything and walks you through the one-time hardware
configuration (radar flash setup, legacy K-LD7 device naming, auto-start, and
optional cloud sync) with prompts. It's safe to re-run any time.
See the **[Raspberry Pi Setup Guide](docs/raspberry-pi-setup.md)** for
details and troubleshooting. Touchscreen installations can use the
**[Startup Splash Screen](docs/splash-screen.md)** guide to install a
terminal-free desktop launcher with immediate startup progress.
See the **[Raspberry Pi Setup Guide](docs/setup/raspberry-pi.md)** for details and troubleshooting. Touchscreen installations can use the **[Startup Splash Screen](docs/setup/splash-screen.md)** guide to install a terminal-free desktop launcher with immediate startup progress.

### 4. Hit balls

Expand Down Expand Up @@ -120,7 +117,7 @@ scripts/start-kiosk.sh --battery geekworm
```

The IWR6843 example values are not universal. Measure the geometry from the
antenna center and follow the [operator guide](docs/iwr6843/README.md#measure-the-geometry);
antenna center and follow the [operator guide](docs/iwr6843/mounting.md#measure-the-geometry);
wrong values bias the result instead of producing an obvious startup error.

Then open http://localhost:8080 or use the touchscreen. Footer tabs switch
Expand All @@ -147,7 +144,7 @@ openflight-cloud status # linked? queued? parked?
```

Once linked, sessions sync automatically (on session end and via a ~10-minute
timer that heals wifi outages). See the **[Cloud Sync Guide](docs/cloud-sync.md)**
timer that heals wifi outages). See the **[Cloud Sync Guide](docs/using/cloud-sync.md)**
for details.

### TV Display Mode
Expand Down Expand Up @@ -175,7 +172,7 @@ For air swings and speed-stick training, OpenFlight can use the OPS243-A fast
speed stream directly instead of waiting for impact audio. Start it with
`scripts/start-kiosk.sh --swing-speed`; the server emits `swing_speed` events
with peak club speed, rep duration, reading count, and session stats. See the
**[Swing Speed Training Guide](docs/swing-speed-training.md)** for setup and
**[Swing Speed Training Guide](docs/using/swing-speed.md)** for setup and
tuning options.

## How It Works
Expand Down Expand Up @@ -212,7 +209,7 @@ Place the OPS243-A **3-5 feet behind the tee**, pointing down the target line:
```

The IWR6843 has stricter mounting and measurement requirements; use the
[operator guide](docs/iwr6843/README.md#mount-and-aim-the-radar) rather than assuming it
[operator guide](docs/iwr6843/mounting.md#mount-and-aim-the-radar) rather than assuming it
shares the OPS243 position.

## Configuration
Expand Down Expand Up @@ -253,7 +250,7 @@ monitor.disconnect()
## Limitations

- **Cosine error**: If ball doesn't travel directly toward/away from radar, measured speed will be slightly lower than actual
- **Spin detection**: The live multitaper value is experimental and is not used for carry by default. Short indoor flight windows and multipath make individual readings unreliable; see [Rolling Buffer and Spin Detection](docs/rolling_buffer_spin_detection.md).
- **Spin detection**: The live multitaper value is experimental and is not used for carry by default. Short indoor flight windows and multipath make individual readings unreliable; see [Rolling Buffer and Spin Detection](docs/how-it-works/rolling-buffer.md).
- **K-LD7 speed aliasing** (deprecated hardware): The K-LD7 max speed is 62 mph, so it's used only for angle/distance, not speed

## Hardware Diagnostic
Expand All @@ -266,7 +263,7 @@ uv run python scripts/hardware-test/diagnose.py

The diagnostic checks the OPS243 transport, rolling-buffer persistence,
software and hardware triggers, and any connected K-LD7 radars. IWR6843 builds
use the [operator guide's first-capture checks](docs/iwr6843/README.md#verify-the-first-capture).
use the [operator guide's first-capture checks](docs/iwr6843/verify.md#verify-the-first-capture).

Missing optional hardware (like the horizontal K-LD7) is reported as a skip rather than a failure. Pass `--require-all` to fail on skips, or `--no-interactive` to skip the sound-trigger prompt in unattended runs.

Expand Down Expand Up @@ -312,26 +309,32 @@ uv run pytest tests/ -v

## Documentation

- **[Parts List](docs/PARTS.md)** — What to buy
- **[Sound Trigger Wiring](docs/sound-trigger-wiring.md)** — How to wire the sound trigger
- **[Raspberry Pi Setup](docs/raspberry-pi-setup.md)** — Full setup guide
- **[Battery Monitoring](docs/battery/README.md)** — Provider architecture, UI states, and shared Pi support
- **[Geekworm X1202/X1206 Operator Guide](docs/battery/geekworm.md)** — Batteries, Pi setup, native telemetry, and warnings
- **[IWR6843 Operator Guide](docs/iwr6843/README.md)** — Wire, flash, mount, aim, and calibrate the angle radar
- **[LIS3DH Inclinometer Setup](docs/inclinometer/README.md)**: Add enclosure-level compensation to IWR6843 tilt
- **[OPS243 USB → GPIO UART Migration](docs/ops243-uart-migration.md)** — Required before adding the IWR6843
- **[IWR6843 Firmware Developer Guide](firmware/README.md)** — Build the firmware from source (not needed to flash the prebuilt image)
- **[Simulator Connectors](docs/simulator/README.md)** — Stream shots to GSPro, OpenGolfSim, and others
- **[Cloud Sync](docs/cloud-sync.md)** — Push filtered sessions to FlightWeb
- **[Rolling Buffer & Spin Detection](docs/rolling_buffer_spin_detection.md)** — Production capture and experimental spin details
- **[Dechirped-Sideband Spin Replay](docs/spin-dechirp-replay.md)** — Next-gen spin estimator test bench
- **[Camera and YOLO Experiments](docs/yolo-performance-tuning.md)** — Optional, non-production vision work
- **[Legacy K-LD7 Setup](docs/kld7.md)** — Existing K-LD7 builds only
- **[K-LD7 Ball Detection Theory](docs/kld7-ball-detection-theory.md)** — How angle detection works (deprecated hardware)
- **[K-LD7 Session Review](docs/kld7-session-review.md)** — Offline review workflow for session JSONL files (deprecated hardware)
- **[Observability & Log Shipping](docs/observability.md)** — Ship logs to Grafana Cloud
📖 **Full documentation site: <https://openflight.dev/docs/>**

Build it locally with `make docs` (serves at `localhost:8000`).

- **[Parts List](docs/get-started/parts.md)** — What to buy
- **[Sound Trigger Wiring](docs/build/sound-trigger.md)** — How to wire the sound trigger
- **[Raspberry Pi Setup](docs/setup/raspberry-pi.md)** — Full setup guide
- **[Battery Monitoring](docs/using/battery.md)** — Provider architecture, UI states, and shared Pi support
- **[Geekworm X1202/X1206 Operator Guide](docs/build/battery.md)** — Batteries, Pi setup, native telemetry, and warnings
- **[IWR6843 Operator Guide](docs/iwr6843/index.md)** — Wire, flash, mount, aim, and calibrate the angle radar
- **[LIS3DH Inclinometer Setup](docs/build/inclinometer.md)**: Add enclosure-level compensation to IWR6843 tilt
- **[OPS243 USB → GPIO UART Migration](docs/build/ops243-uart.md)** — Required before adding the IWR6843
- **[IWR6843 Firmware Developer Guide](docs/development/firmware.md)** — Build the firmware from source (not needed to flash the prebuilt image)
- **[Enclosure & Case](docs/build/enclosure.md)** — The printed IARC v3 case
- **[Hardware Diagnostic](docs/setup/raspberry-pi.md)** — Pi setup, auto-start, and troubleshooting
- **[Simulator Connectors](docs/using/simulator/index.md)** — Stream shots to GSPro, OpenGolfSim, and others
- **[Cloud Sync](docs/using/cloud-sync.md)** — Push filtered sessions to FlightWeb
- **[Rolling Buffer & Spin Detection](docs/how-it-works/rolling-buffer.md)** — Production capture and experimental spin details
- **[Dechirped-Sideband Spin Replay](docs/development/spin-replay.md)** — Next-gen spin estimator test bench
- **[Camera and YOLO Experiments](docs/development/camera-yolo.md)** — Optional, non-production vision work
- **[Legacy K-LD7 Setup](docs/legacy/index.md)** — Existing K-LD7 builds only
- **[K-LD7 Ball Detection Theory](docs/legacy/ball-detection-theory.md)** — How angle detection works (deprecated hardware)
- **[K-LD7 Session Review](docs/legacy/session-review.md)** — Offline review workflow for session JSONL files (deprecated hardware)
- **[Observability & Log Shipping](docs/using/observability.md)** — Ship logs to Grafana Cloud
- **[Contributing Guide](CONTRIBUTING.md)** — How to contribute
- **[Changelog](docs/CHANGELOG.md)** — Version history
- **[Changelog](docs/changelog.md)** — Version history

## License

Expand Down
44 changes: 12 additions & 32 deletions cad/IARC_case/README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,16 @@
![](images/IARC_case_v3.png)
# OpenFlight IARC v3 Case

> **⚠️ Note:** The KLD7 mounts in this case are for the deprecated K-LD7 angle radars — OpenFlight has moved to a more capable radar chip. Skip the KLD7 mount steps for a new build.
The assembly instructions and build photos now live in the documentation site:

- M5 Bolts needed: 10
- M2.5 Bolts needed: 12
**→ [docs/build/enclosure.md](../../docs/build/enclosure.md)**
(published at <https://openflight.dev/docs/build/enclosure/>)

Instructions for OpenFlight IARC v3 Case Build

1. Print out `sensor_housing.stl` ![](images/sensor_housing.png)
2. Print out (2x) `OPS_mount.stl` ![](images/ops_mount.png)
3. Secure the OPS sensor to each `OPS_mount.stl` part with screws (I don't know which ones)
4. Secure the `OPS_mount.stl` parts to the `sensor_housing.stl` part with (2x) M5 bolt ![](images/secure_ops_mount.png)
5. Fit the sound sensor into the little slot on the left side of the `sensor_housing.stl` part. ![](images/sound_placement.png)
6. Print out (1x) `KLD7_h_mount_L_v2.stl` and (1x) `KLD7_h_mount_R_v2.stl` ![](images/KLD7_mounts.png)
7. Slot a KLD7 sensor between the mount parts, and secure them to the `sensor_housing.stl` part with (2x) M5 bolt ![](images/bottom_KLD7_mount.png)
8. Print out (1x) `KLD7_v_mount_L_v2.stl` and (1x) `KLD7_v_mount_R_v2.stl` ![](images/KLD7_mounts.png)
6. Slot a KLD7 sensor between the mount parts, and secure them to the `sensor_housing.stl` part with (2x) M5 bolt ![](images/top_KLD7_mount.png)
7. Print out the `monitor_mount.stl` part. ![](images/monitor_mount_print.png)
8. Print out (4x) `monitor_standoffs.stl`'s. ![](images/monitor_standoffs_print.png)
9. Secure each `monitor_standoff.stl` part to the corners of the `monitor_mount.stl` part with (1x) M2.5 bolt. ![](images/monitor_mount_corners)
10. Secure the monitor to the `monitor_mount.stl` part. ![](images/monitor_secure.png)
11. Secure the raspberry Pi to the monitor. ![](images/rasp_secure.png)
12. Print out the `monitor_shell.stl` part. If you use the Raspberry Pi Touch Display 2 instead of the 7" HMTECH touchscreen, print `Touch_Display2_shell.stl` and `Touch_Display2_backplate.stl` instead. ![](images/monitor_shell_print.png)
13. Secure the monitor assembly inside the `monitor_shell.stl` part with (4x) M2.5 bolts at the corners. ![](images/monitor_shell_assembly.png)
14. Print out the `monitor_back.stl` part. ![](images/monitor_back.png)
15. Secure the `monitor_back.stl` part to the `monitor_standoffs.stl` parts with (4x) M2.5 bolts. ![](images/monitor_back_secure.png)
16. Slide the whole assembly into the sensor housing assembly, using the dovetails to align everything together. ![](images/whole_assembly.png)
17. Print out the `name_plate.stl` file. ![](images/name_plate_print.png)
18. Secure the `name_plate.stl` file to the front of the whole assembly with glue. ![](images/name_plate_glue.png)
19. Print out the `curvy_backplate.stl` file. ![](images/curvy_backplate_print.png)
20. Secure the `curvy_backplate.stl` file to the whole assembly with (4x) M2.5 bolts. ![](images/curvy_backplate_secure.png)
21. Print out (4x) `case_foot.stl` parts. ![](images/case_foot_print)
22. Secure each foot to the bottom of the whole assembly with (4x) M5 Bolts. ![](images/feet_attach.png)
## What's in this directory

And that’s how you put together the 3d printed parts!
| Path | Contents |
| --- | --- |
| `stl/` | Printable parts |
| `step/` | STEP files for CAD editing |
| `IARC_Case_v3.3mf` | Project file with print settings |

**Fasteners:** 10 × M5 bolts, 12 × M2.5 bolts.
Loading
Loading