Open source drag racing timing system — staging beams, Christmas tree, ET / 60ft / trap speed measurement, and race control software. Built from industrial off-the-shelf components so that any club, anywhere, can run a real drag event without a five-figure imported black box.
Status: prototype, week 1. Nothing works yet. Architecture is designed, components are on order, bench validation is next. Follow the commits.
Break the beam.
This project started the day a national drag event was cancelled mid-finals: the country's only timing system failed, and there was no second one. The timing rig turned out to be a single point of failure for an entire racing scene. Commercial systems exist — and cost like an engine build, ship for months, and are serviced an ocean away.
Beam402 is the answer: an open, reproducible, field-repairable timing system for grassroots drag racing — training days, junior events, alternative leagues, and everything the big rigs never reach.
- Timing nodes — identical boxes along the track (start, 60ft, 1/8, finish) that timestamp beam breaks with ≤1 ms resolution
- Industrial through-beam photoelectric sensors — 1 ms rated, IP67, with the range margin to survive burnout smoke; not hobby IR modules
- A wired RS-485 trunk with a broadcast start pulse — no clock sync, no radio jitter, verifiable with an oscilloscope
- Christmas tree module — full staging / AutoStart / pro & standard tree logic
- Race control software — classes, qualifying, ladders, time slips, and a local web scoreboard for spectators
- Per-node battery power — a cut cable loses data, never nodes
Design priorities, in order: trustworthy timing, field repairability by non-specialists, low cost, incremental deployment (start + finish + tree is already a complete working system).
| Doc | What's inside |
|---|---|
docs/architecture.md |
Full system design: sensors, timing model, bus, power, nodes, tree — including the honest list of unverified assumptions that gate the project |
docs/decisions.md |
Decision log (ADR): why wired and not wireless, why through-beam, why DIP addressing, why no photo finish, and what evidence would change each call |
docs/bench-validation.md |
The current stage. How to build the rig and run the measurements that gate everything — procedures, expected values, pass/fail criteria, and what each failure would mean |
docs/software.md |
Software architecture: what the node firmware, the race control software and the bench tooling each own — and what each is forbidden to do |
docs/protocol.md |
The wire contract: Modbus register map, poll strategy, and the mapping file that gives the numbers their meaning |
hardware/BOM.md |
Prototype bill of materials with sourcing guidance |
software/crates/protocol |
The register map itself, as code — registers.toml and the tables in protocol.md §3 are generated from it and checked against it (D27) |
- Bench validation — sensor jitter rig (differenced against a reference detector), make/break edge asymmetry, thermal drift, hardware capture jitter, start-pulse noise immunity over full-length cable (gates everything)
- Software design — architecture, bus register map, mapping file format
- Wire contract as code — register map crate, documents generated and checked against it
- Bench data-reduction script —
bench/, VCD in, distribution out - Mapping file: load-time validation
- Node and tree simulator, bus poller, race logic replayed against it — ET, splits, trap speed, reaction time, handicap starts and breakout
- Time slips:
beam402 sim scenarios/bracket.toml --format bracket --dial 12.34,7.50prints a full round against the simulator - Session recording and replay —
--recordwrites every bus transaction,beam402 replayre-runs it through the same code and prints the same slip -
beam402 scope— one self-contained page showing the strip, the tree, the beams, the bus and the events on a scrubbable timeline - Spectator scoreboard as a pixel frame at a declared resolution (D29), so the page previews a board instead of becoming a second design
- Two perfboard nodes (start + finish) + tree prototype
- Parking-lot demo: staging → tree → start pulse → ET on a laptop
- Carrier PCB (KiCad) + fab-assembled batch
- Field enclosures (IP67 assemblies), full two-lane configuration
- Event layer: classes as data, qualifying, pro and sportsman ladders, byes
- The qualifying cut as a class setting, not our arithmetic —
field = [8, 16]is "top 8 from four entries, top 16 from sixteen",[16]is a fixed field, unset is everybody; plus a minimum to run a class and a limit on how many passes score. Whoever missed the cut is named, because "seeded last" and "did not qualify" are different sentences. A class can be a time window —13.000–14.000— and whoever qualified outside theirs is reported for an official to move, never moved by us - HTTP server, written not depended on (D32) —
beam402 serveputs the round, the board and the scope on the LAN with zero dependencies - Live race control (D30): the bus on its own thread, an operator page
under a control token, and a scoreboard — all from
beam402 serve - Entry sheets and a meeting derived from an append-only result log —
beam402 event events/club-day.toml - Eliminations run off the ladder —
beam402 serve --event <sheet> --log <file>pairs the cars, the operator records, the ladder advances. A car that cannot make the call leaves its opponent a single: one car down the track, a timed pass still required, and a win rather than a bye recorded - The registration desk —
beam402 sheet entries.csv --event season.tomlturns the spreadsheet a club already has into an entry sheet (D34) - Carrying a day to a server —
beam402 pushandbeam402 host, live or in bulk that evening, resumable and idempotent (D33) - Write authority on the receiver — the first writer claims an event, and
deploy/is the reference way to put one on the internet - A read contract a league can build its own front end on — CORS on reads, an events index, and a pass-through key for their own ids (D35)
- Qualifying and practice over the bus: a queue of cars rather than a smaller eliminator — the operator calls a car into a lane, one or two go, each pass is recorded on its own, and closing qualifying draws the ladder. A practice day is an entry sheet nobody ever draws. A run now states which lanes have a car in it, which is also what a bye needed
- TLS on the push client — rustls behind a cargo feature, so a build that never leaves the track still has no dependencies (D36)
- Reasons in the log (D37): the master writes down the foul it measured beside the result, so a rulebook counting a driver's false starts across a competition has something to count and a mirror can say why somebody lost. An official calls the fouls the beams cannot see, voids a pass and takes a car out of a class from the panel, in their own rulebook's words
- A day in qualifying has a board, derived by the draw's own arithmetic so it cannot disagree with the ladder people end up in: where each car stands, its passes, where the cut falls, and no provisional place for one that has not run. A practice day used to produce no output at all
- A finished class publishes every round it ran, not the last one, so a results page can show how somebody reached a final — plus who missed the cut and who withdrew, which a facade with a field and a count cannot work out for itself
- A meeting over several days off one rulebook —
beam402 sheet … --date 2026-08-07 --id practice-day, because hand-edited copies of a class list drift and then the class runs two ways in one weekend - The record button waits for the numbers, not the finish beam: a car is over the line about a second before its ET is off the node (D25), and a press inside that beat wrote the pass down with no time in it
- What was run, not only who won (D38). An elimination pass was
measured, shown on the panel, shown on the board — and dropped: a finished
class said who beat whom and nothing about how, so nobody could say what
the winner ran in the final. One
Rline per car per pass records it now, the day's history derives from those, and opening a pass shows the run. Splits stay out of the log, because which beams a venue has belongs to its mapping — the detailed answer is the bus session, whichserve --recordfinally writes for a race and not only a rehearsal - Per-pass bus sessions:
serve --recordwrites one file for the day, soreplayreads the first round out of it. Scoring a particular pass needs the pair it belonged to, which the sheet and the log already say - Tree-hosted deployment (D31): a tree, two nodes and a phone — arm and read every run with no computer at the track
- A reference receiver actually deployed, so the chain runs end to end — a day pushed over TLS from a laptop, mirrored, and read cross-origin by a league's own front end
- First real event
The project is young and the best time to influence it is now. Especially welcome: eyes on the architecture and decision log (tell us where we're wrong — with evidence), experience with photoelectric sensors and RS-485 in the field, and later — firmware and race-control software contributions. Open an issue; English or Russian both fine. Ground rules and how to challenge a decision: CONTRIBUTING.md.
Community chat on Telegram: t.me/beam402 — mostly Russian, English welcome. Conclusions that affect the design come back to issues; the project's record lives on GitHub.
Related projects worth knowing: MajicDesigns/DragLights (tree lamp logic this project builds on) and RotorHazard (the FPV drone timing project whose open-community architecture is a reference for ours).
Code: MIT. Hardware design files: CERN-OHL (added with the first PCB commit).
The Beam402 name and logo identify builds verified by the project — the design is free to use, the name is not a free-for-all. A self-built system is the builder's responsibility; a verification checklist will ship with v1.
Документация проекта ведётся на английском. Краткий обзор на русском: README.ru.md. Полевые регламенты и правила серии — на русском отдельно.
