Sports analytics has long promised a revolution, turning raw athleticism into data points that coaches and fans can scrutinize. When Hubert Hurkacz strikes a 140-mph serve, the television broadcast reduces it to a single speedometer number. But for engineers building real-time performance pipelines, that singular event is the tip of an iceberg. Beneath the court surface-and behind every sensor feed-lies a distributed architecture that must capture ballistic trajectories, skeletal kinematics, and environmental telemetry, all within sub-second latency. This article dissects how we assembled an open-source analytics stack for Hurkacz, transforming match play into a stream of actionable insights that would make any Site Reliability Engineer proud.
We built a full-stack system that ingests multi-modal tracking data, applies computer vision and pose estimation in real time and predicts match outcomes with LSTM networks-all while keeping the athlete's privacy ironclad. The pipeline, initially a weekend prototype, now processes over 60,000 data points per minute of match play, delivering dashboards that some ATP analysts use for pre-serve tactical breakdowns. Here's how we engineered it, the trade-offs we faced. And what every developer can learn from applying MLOps to elite sport.
Our work started not with a business requirement but with a question: could we reverse-engineer the physics of a Hurkacz kick serve using only consumer-grade cameras and open-source tooling? The answer required marrying edge computing - event streaming, and a bit of creative feature engineering-and it taught us more about data pipeline resilience than a typical e-commerce backend ever could.
Mapping the Data Landscape of a Professional Tennis Match
To frame the problem, we cataloged every possible signal surrounding a single Hurkacz point. At the ATP level, matches generate official Hawk-Eye tracking data (12 cameras at 250 fps), radar gun measurements, wearable IMU outputs (some players use Catapult vests). And even court-side audio. Our goal was to replicate a meaningful subset of that treasure trove using off-the-shelf gear: two GoPro Hero 11 cameras, a Raspberry Pi 4 for edge compute. And a Stalker radar unit. We settled on ingesting 1080p video streams at 60 fps from two 45-degree angles behind the court, coupled with raw radar speed data over a serial connection.
The funnel starts broad. Each camera produces roughly 15 MB per second of video; over a three-set match, that's over 300 GB of raw footage. Storing that in the cloud blindly would be a budget disaster. So we designed an edge filtering mechanism that extracts only relevant frames-when the ball is in play-using a combination of motion detection and audio spike analysis from court-side microphones. This reduced our storage footprint by 87% before a single byte touched the cloud.
Defining a universal schema for tennis points was the next challenge. We adopted a hierarchical JSON structure inspired by the Sportradar real-time tennis data format, extending it with fields for ball coordinates, player joint positions. And radar confidence scores. Each point becomes a self-contained event, timestamped with NTP-synced microsecond precision, so that video frames, sensor readings. And manual annotations align perfectly in downstream processing.
Real-Time Ingestion with Apache Kafka and Edge MQTT Brokers
Relaying data from a tennis court in Sopot to a centralized analytics engine required a resilient messaging backbone. We chose Apache Kafka for its ability to handle high-throughput streams with exactly-once semantics. On the edge, a lightweight MQTT broker (Mosquitto) served as the gateway: the Raspberry Pi published compressed frame chunks and radar readings to local topics, which an MQTT-Kafka bridging service forwarded to a three-node Kafka cluster running on AWS EC2 instances in eu-central-1.
We learned early that tennis data is incredibly bursty. Between points there's almost total silence. But during a 20-shot rally, the system must absorb a flood of events. Kafka's partitioning strategy, keyed by match ID, allowed us to parallelize consumption across consumer groups that handled different aspects: a raw video archiver, a real-time analytics processor. And a long-term ML training ingester. By setting retention to 24 hours for raw topics and 7 days for compressed analytics, we kept storage costs around $120 per month.
One critical detail: the radar gun emitted a 25-byte hex packet every 0. 1 seconds, but only when a serve exceeded 100 km/h. This meant we had to implement heartbeat-based dead-zone detection in our ksqlDB stream processing to mark periods of inactivity without false triggers. The resulting SERVE_START events are now the primary trigger for all downstream computer vision pipelines.
Ball Tracking with YOLOv8 and Homography-Corrected Coordinate Grids
Detecting a fast-moving tennis ball in variable lighting is notoriously difficult. After experimenting with frame differencing and traditional optical flow, we settled on fine-tuning YOLOv8-nano with a custom dataset of 15,000 labeled frames extracted from Hurkacz practice sessions. The model, converted to ONNX and deployed via ONNX Runtime on the edge device, achieves an inference time of 12 ms per frame on the Raspberry Pi's CPU-enough to process both camera feeds concurrently at 60 fps.
The output is a bounding box and a confidence score. But raw bounding boxes aren't enough for tactical analysis; we need court-space coordinates. We applied a homography transformation using four manually calibrated court corners. The 2D pixel positions are mapped to a standardized 23. 77m x 10. 97m coordinate system. This transformation runs as a post-processing step in OpenCV, with warp matrix inversion computed once at the start of each session. The result: we can pinpoint a ball's bounce location within 5 cm of the official Hawk-Eye data, verified during a controlled test at a Stuttgart indoor court.
Handling the ball's rapid acceleration and occlusions-like when Hurkacz's body masks the ball during a serve toss-required a Kalman filter. We implemented an extended Kalman filter (EKF) with a constant-acceleration motion model, using Python's filterpy library. The filter smoothly bridges gaps up to 4 frames and predicts the trajectory during occlusions. So that the bounce-detection algorithm. Which triggers on a sudden drop in Y velocity, remains reliable even when the ball momentarily disappears behind the net post.
Decoding Hurkacz's Biomechanics with MediaPipe Pose Landmarks
While ball tracking tells you where the shot went, understanding why a Hurkacz backhand down the line landed long requires examining his body mechanics. We integrated Google's MediaPipe Pose to extract 33 3D landmarks from the same video feeds. Because we already ran object detection, we cropped the player's bounding box and fed only that region to the pose model, reducing per-frame latency to 15 ms on the Raspberry Pi using the Lite model.
We tracked three key features during the serve: the angle between the shoulder and elbow during the trophy phase, the hip-shoulder separation angle at ball impact. And the wrist snap speed. In one Hurkacz match against Alexander Zverev, we noticed his trophy-phase elbow angle widened by 12 degrees when he aimed for the T-shot serve, a nuanced adjustment invisible to the naked eye. This biomechanical marker became a predictor in our ML model.
Pose data, however, introduces a privacy dimension that traditional ball tracking does not. We'll explore the compliance automation that keeps this biometric data secure later, but Fun fact: we deliberately smear the face landmarks in real time using a blurring filter before any frame leaves the edge device, satisfying GDPR's right-to-privacy mandates even for non-European jurisdictions out of caution.
Fusing Radar, Video. And IMU Data for Serve Velocity Truth
Radar guns have an inherent tendency to measure the maximum speed at the racket tip. While camera-based tracking estimates speed from frame-to-frame displacement. For Hurkacz, these two figures can disagree by up to 3 mph due to spin and measurement error. We built a sensor fusion module using a Kalman filter that combines radar velocity, visual ball-track speed, and-when available-data from a wrist-worn IMU that captures racket head acceleration.
The IMU, a Bosch BNO055 sensor attached to the racket throat, transmits 1000 Hz readings via BLE to the edge device. We time-align all three streams using the NTP-synced system clock and a rolling median filter to Remove jitter. The fused output consistently matched the ATP's official serve-speed reading within 0. 4 mph across 200 serves tracked during a Hurkacz training block. This reliability let us build historical serve-speed profiles that correlate with fatigue, detectable as a gradual 2% drop in velocity in later sets.
Interestingly, the fusion revealed that Hurkacz's flat serve loses less speed over distance than expected-a mere 8% reduction from racket to bounce point, compared to the tour average of 11%. This suggests a more efficient ballistic coefficient, likely due to a tighter ball fluff management and a serve trajectory closer to a line-drive. These nuances fed directly into our feature store.
Feature Engineering: Crafting Strategic Signatures from Raw Telemetry
Armed with ball trajectories, joint angles,? And fused speeds, we faced the classical ML challenge: what features actually predict the outcome of a point? We collaborated with a tennis strategy consultant to identify over 120 candidate features, ranging from the trivial (serve speed) to the exotic (torso twist momentum). Feature engineering took place in Apache Spark notebooks, using the Delta Lake format to version our feature sets.
One potent feature we engineered was the "angle-of-attack discrepancy"-the difference between the opponent's body lean direction and the eventual ball landing zone. Against Hurkacz, we observed that when he serves out wide on the deuce court
.Need a Custom App Built?
Let's discuss your project and bring your ideas to life.
Contact Me Today →