Joshua Kiff
All work
2023 – presentProduct design · Software

Impact Pro: Padel Ball Machine & Training System

Co-founder, sole engineer across mechanical, embedded, app, and cloud

  • BLDC
  • ESP32
  • BLE
  • Flutter
  • Rails
  • ML Kit
  • CI/CD
  • Motion Control
First principlesBLDC launch system, designed from scratch
~0k LOCFlutter app + Rails firmware control plane
Custom BLEbinary protocol, fully mockable without hardware
Impact Pro: Padel Ball Machine & Training System

TL;DR

Existing tennis ball machines are the size of a suitcase and priced like one full of cash. KH Tech's Impact Pro is an ultra-compact tennis/padel ball machine developed from first principles: a from-scratch BLDC launch system, ESP32 embedded electronics, and a software system that outgrew "companion app" some time ago. The Flutter app (~38,700 lines of Dart across ~530 files) controls the launcher over a custom BLE binary protocol, translates target shots into motor parameters through a physics calculator, layers on ML-based swing analysis and a rules-based tactics engine, and even carries the internal DevOps surface for triggering and promoting firmware builds. Behind it sits a Rails backend that acts as the cloud control plane for firmware releases. The engineering story is the compactness; the product story is the software.

The problem

A ball machine has one job (deliver repeatable, controllable balls) but the incumbent way of doing it (large flywheels, big hoppers, mains-class batteries) fixes the form factor at "wheeled luggage." That size is why most players don't own one. The design target for KH Tech was a machine compact enough to change who buys one, without giving up the launch performance that makes practice useful.

System architecture

The product spans four layers, all mine: the mechanical layer (launch mechanism, ball feed, and the packaging that gets it all into the envelope), the embedded layer (ESP32 running motor control for BLDC spin motors, a DC drive motor, and a stepper for aim and elevation), the app layer (Impact Pro, Flutter), and a cloud layer (Firebase for auth, session tracking and diagnostics, plus a Rails backend that orchestrates firmware builds and releases).

The app is built to a strict feature-first, domain-driven architecture, and the control path is a clean pipeline: UI to a Riverpod controller, to a use case, to the BallLauncherCalculator that translates a desired shot (target depth, direction, spin, speed) into motor parameters, to the repository, and out over BLE as compact binary packets. That calculator is the physics and maths core of the whole product.

The control app

Shots are designed visually in an interactive 3D court: drag the target to where the ball should land, rotate the view to check the trajectory, and set launch height on a slider. Each shot carries its full parameter set: shot type (volley, smash, drop, flat), side (forehand or backhand), pitch angle, and a continuous spin control from backspin through topspin. Padel-specific behaviour like wall play is a first-class toggle, not an afterthought. Shots compose into routines the machine fires autonomously, a calibration flow anchors the physical launcher to real court geometry in a 3D coordinate system, and a Wear OS companion puts control on the wrist mid-session.

Two engineering choices under this deserve the spotlight. The BLE layer is a hand-built binary protocol with its own encode/decode mappers, not JSON over the air. And the entire BLE stack has a full mock implementation, so the whole app can be developed and tested without the physical launcher: a deliberate testability investment that pays for itself every day the hardware is on a bench somewhere else.

Coaching intelligence

The app's ambition is to be a trainer, not a remote control, and three features carry that:

  • Tactical View. Given the shot the launcher is about to fire, a rules engine shows where a real opponent would stand on an isometric 3D court, lets you drag two virtual opponents around, recommends target zones with explanations, and predicts the likely return. The engine itself is pure Dart with a hard purity boundary (no Flutter imports, consumed through one interface), so the hand-written rules can later be swapped for an ML model with zero UI changes.
  • Rally Lab (in development). A rally is authored as a JSON script of semantic events, compiled into continuous ball and player motion using real flight and bounce physics, and played back through a pure sample(rally, t) function. Because sampling is a deterministic function of time, scrubbing, pausing, and variable-speed playback come for free. It is also deliberately built as a substrate for AI-generated rally scenarios later: an LLM emits the JSON, and the compiler's validation errors become its correction loop.
  • AI Trainer. A live camera feed runs through on-device ML Kit pose detection; a swing detector tracks wrist trajectory across frames to recognise a forward swing and capture the pose sequence for review.

Firmware, built and shipped like a product

The machine's firmware ships without an app-store release and without ever handing GitHub or AWS credentials to the app or to untrusted code. The app flashes firmware over BLE (streamed in 500-byte chunks, SHA-256 verified before flashing, status polled from the device), and the Rails backend is the single trusted intermediary for producing those binaries: an engineer triggers a cloud build from the phone, Rails pins the request to an immutable commit SHA and dispatches GitHub Actions always against the main workflow so a feature branch can never rewrite the CI's own permissions, the workflow splits into trusted and untrusted jobs so live credentials and branch code never share a process, and Rails independently re-verifies every artefact's size and SHA-256 against S3 before a build can be marked succeeded. A green CI run alone is structurally incapable of flipping a build to succeeded; that is an explicit regression test. Verified builds are then promoted by an admin through internal, beta, and production channels, with every state transition written to an append-only audit log and artefacts served only through short-lived presigned URLs.

The build surface lives inside the app itself: trigger builds, watch status through adaptive polling with backoff, browse artefacts, promote releases. An internal CI/CD console in a consumer mobile app is not a common thing to get to build.

Engineering practice

The largest features were built spec-first and executed largely by AI coding agents against those specs, and the discipline is the point: implementation specs and architecture decision records written before code, with every claim tagged as verified fact, binding decision, or open assumption, kept in lockstep between the app and backend repos, and revised in dated passes as the code landed underneath them. The flagship ADR runs to roughly 2,500 lines.

Testing follows the same instinct. The app has 66 test files, with timer-driven code (like the build-status polling state machine) tested deterministically via fake async. The backend's spec code outweighs its application code at roughly 1.4:1, and the interesting tests are behavioural: concurrent build requests racing one idempotency key resolve to a conflict rather than a duplicate, tampered and replayed webhook payloads each get their own test, and the CI dispatch is covered by explicit injection-attempt fixtures.

Results

  • Working launcher hardware controlled end-to-end from the app over a custom BLE binary protocol
  • ~38,700 lines of Dart across ~530 files in the app, plus a Rails control plane with a 1.4:1 spec-to-code ratio, all solo
  • Firmware pipeline live: cloud builds triggered, verified, and promoted through release channels from inside the app
  • Spec-first, AI-agent-executed development practised on a real production codebase, with the ADR paper trail to show for it

A separate piece of software completes the training loop: CourtVision Lab, a match-analysis tool that reconstructs real rallies in 3D from single-camera footage. CourtVision Lab captures what actually happens in match play, and Impact Pro turns shot patterns into repeatable practice.

Gallery