Skip to content

lukaszkn/GateSpeed

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

GateSpeed

GateSpeed is an iOS app that measures how fast a rider travels through a five‑post slalom course using nothing but the iPhone's rear camera — no beams, sensors, or wearables. Prop the phone up facing the course and it detects the rider crossing each post, times the run, computes the average speed, calls the result out loud, and saves an annotated video of the ride.

How it works

Set the phone down in landscape with the whole course in frame. GateSpeed draws five vertical posts at fixed positions across the view (at 10%, 30%, 50%, 70%, and 90% of the width).

  1. Calibrate — On launch (and whenever you tap Recalibrate), the app waits until no rider is in view. Keep the course clear until the status changes from Calibrating… to Ready.
  2. Start — A run begins when the rider enters an outer post (post 1 or post 5), which also sets the direction (left‑to‑right or right‑to‑left).
  3. Measure — The rider must cross the posts in order. The status pill shows the next expected post and the elapsed time.
  4. Result — When the rider clears the final post, GateSpeed computes the speed over the 28 m course and shows it in km/h with a PASS/FAIL verdict (pass ≥ 30 km/h), then announces it aloud (e.g. "31 kilometres per hour. Pass.").
  5. Re‑arm — Once the result has been announced and the course is clear again, the app automatically re‑arms for the next run.

A run is flagged Invalid (and discarded) if it starts at an inner post, starts ambiguously (two outer posts at once), skips a post or goes out of order, or takes longer than 10 seconds.

Detection

Detection uses the Vision framework's on‑device human‑rectangle detector (VNDetectHumanRectanglesRequest) — no network, no custom model. Each camera frame is scanned for people; the rider's bounding box is mapped into the visible (preview‑cropped) region and its horizontal centre is tracked frame to frame. A post counts as "crossed" the moment the tracked centre passes its position, and the crossing time is interpolated between detection samples, so timing stays accurate even when frames are dropped. Tiny detections (bystanders far away) are ignored, brief detection gaps are bridged, and implausible jumps restart tracking so a second person can't hijack a run. When several people are visible, the one closest to the tracked rider wins (before tracking starts, the most prominent one).

Session scoreboard

The bottom‑left corner keeps a running tally for the session:

  • Runs — number of valid (completed) runs
  • Pass — how many of those met the passing speed
  • Avg — average speed across all valid runs

Tap Reset to clear the tally. The same scoreboard is burned into every exported video.

Ride videos

Every valid run is saved to your Photos library as a clip with the gate posts, the speed/verdict panel, and the session scoreboard burned into the footage — the posts light up in turn as the rider passes them, and the result appears as they cross the line. Recording keeps rolling for a few seconds past the finish so the result plays over real footage instead of a frozen frame. Invalid runs are recorded but discarded.

Requirements

  • iPhone running iOS 26.2 or later
  • Rear camera (ultra‑wide is preferred; the wide camera is used as a fallback)
  • Landscape orientation
  • Camera permission (required) and Photos "Add" permission (to save ride videos)

Build & run

Open the project in Xcode and run the GateSpeed scheme on a physical device (the camera is required):

GateSpeed/GateSpeed.xcodeproj

Or from the command line:

xcodebuild build \
  -project GateSpeed/GateSpeed.xcodeproj \
  -scheme GateSpeed \
  -destination 'generic/platform=iOS'

Tests

xcodebuild test \
  -project GateSpeed/GateSpeed.xcodeproj \
  -scheme GateSpeed \
  -destination 'platform=iOS Simulator,name=iPhone 17 Pro'

The unit tests cover the timing state machine, speed math, rider tracking and crossing interpolation, Vision coordinate mapping, and session statistics. One test — the burned‑in video overlay (RideVideoOverlayComposerTests) — is device‑only: the Core Animation video compositor crashes in the iOS Simulator, so it is skipped there and must be run on a real device.

Project structure

File Responsibility
GateSpeedApp.swift App entry point
ContentView.swift SwiftUI UI — camera preview, gate overlay, status/result panels, session scoreboard
CameraCaptureService.swift Capture‑session setup; wires detection → state machine → recording
CameraPreview.swift AVCaptureVideoPreviewLayer bridge; reports rotation and viewport geometry
RiderDetector.swift Vision human detection, rider tracking, post‑crossing timing
GateModels.swift Course layout, run state machine, results, session statistics
RideVideoRecorder.swift Records the run and saves it to Photos
RideVideoOverlayComposer.swift Burns the posts / result / scoreboard into the exported clip
SpeechAnnouncer.swift Spoken result announcements (British English)

Course parameters (post spacing, the 28 m distance, the 30 km/h pass threshold, and the 10 s timeout) live in GateLayout and GateRunStateMachine in GateModels.swift.

License

MIT © 2026 Lukasz

About

GateSpeed is an iOS app that measures how fast a rider travels through a five‑post slalom course using nothing but the iPhone's rear camera

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages