HockeyVision - AI Shot Analyzer
by Carl Jonsson in Design > Software
97 Views, 1 Favorites, 0 Comments
HockeyVision - AI Shot Analyzer
Have you ever spent hours practicing with no idea whether you're actually getting better? No coach watching, no feedback.
That's exactly the problem I wanted to solve.
My name is Carl Jonsson, a former ice hockey player from Sweden. This project started because I know what it feels like to practice alone with no way to measure progress.
HockeyVision is an AI-powered shot analysis system built for hockey players who want to increase their shooting accuracy, especially players who want to train independently and still receive feedback. Using two computer vision models running in real time, it detects where the puck hits the goal and gives you feedback through a display, an RGB indicator, and a live dashboard on your laptop.
The system consists of two parts, a laptop that runs the AI models, and a Raspberry Pi packed inside a custom-built housing shaped like a hockey puck. Together, they track every shot and store the data so players can follow their progress over time.
In this Instructable, I will walk you through how I built it, from training the AI models to building the end-to-end pipeline.
Link to Github.
Supplies
- Raspberry Pi 5
- Laptop
- LCD Display
- RGB LED indicator
- RFID reader
- Powerbank 10000mAh
- Sony a5100
- Velbon EX-230 II camera stand
Downloads
How It Works - System Overview
HockeyVision consists of two main parts that work together, a laptop and a Raspberry Pi.
The laptop is connected to a camera placed in front of the goal. It runs two AI models in real time, one that detects the puck, and one that maps the exact corners of the goal. Together, they calculate where the puck hit the goal.
The Raspberry Pi handles everything else. It runs the database that stores every shot, hosts the web dashboard where players can see their stats, and controls the physical hardware such as an LCD display, an RGB indicator, and an RFID reader for identifying players.
The two sides communicate over a local network. When a shot is detected on the laptop, the result is sent to the Raspberry Pi, stored in the database, and feedback is shown.
The system works in three stages: Ready, where it waits for the player. Capturing, where it records the shot as it happens. Analysing, where the AI processes the footage and delivers the result.
Dataset Collection and Labeling
Before training any AI model, you need data, probably more than you think.
I built two separate datasets for HockeyVision, one for each model. The first model is an object detection model, trained to detect three things: the puck, the goal, and the hockey stick. The second is a keypoint detection model, trained to detect the four corners of the goal. Knowing the exact corners is what allows the system to calculate where the puck hit inside the goal.
To collect the data, I recorded video footage of shots being taken at a goal. I then extracted individual frames from the footage with Roboflow's built-in tool. Roboflow is a tool that makes it easy to label images and export datasets for AI model training. Each frame was manually labeled, drawing bounding boxes around the puck, goal, and stick, and placing keypoints on each corner of the goal.
To make the models more robust, I recorded in different environments, indoors against multiple backgrounds, and outdoors against multiple backgrounds. I also varied the camera angle and lighting conditions. The more variety in the dataset, the better the model handles different situations.
One thing worth knowing if you try this yourself, the image resizing in Roboflow should match the way YOLO resizes images during training. I ran into an issue where the keypoints were slightly off because of a mismatch in resizing methods. The fix was to set Roboflow to "fit (black edges)" instead of stretching the images. A small setting, but it made a big difference in the performance of the model.
Training the AI Models
With the datasets ready, it was time to train the models.
Training was done using Google Colab, a free cloud platform that gives you access to a GPU. This matters more than you might think. When I tested training locally on my laptop CPU, it would have taken many hours per model. On Google Colab with a GPU, the same training completed in a fraction of the time. My laptop (Lenovo Yoga Slim ultra 7) does not have a dedicated GPU, which made the decision of training with Google Colab even more obvious.
Each model was trained separately. The object detection model was trained to recognize the puck, the goal, and the hockey stick. The keypoint detection model was trained to locate the four corners of the goal. Training each model separately kept things clean and made it easier to improve one without affecting the other.
Building the Housing
I wanted the housing to be built with a strong connection to hockey, so I built it in the shape of a hockey puck.
The housing is made from a repurposed plastic container, roughly 200mm in diameter and 60mm in height. Instead of buying something new or 3D printing the housing, I reused an existing container and modified it to fit the components. This kept the cost down for the housing and gave the build a more personal touch.
Inside the housing sits the Raspberry Pi 5, a powerbank that keeps everything running without power connections from the outside, the RGB indicator, the LCD display, and the RFID reader. The lid is removable which makes it easy to access the components if something needs to be adjusted.
All internal cables are kept inside the housing to keep things clean and protected. The goal was a build that looks intentional, not just a simple prototype without a thought behind it.
Wiring the Hardware Components
When the housing was built, it was time to connect everything together. The Raspberry Pi 5 communicates with three hardware components: an LCD display, an RFID reader, and an RGB indicator.
Each component connects to the Raspberry Pi differently. The LCD display uses I2C, the RFID reader uses SPI, and the RGB indicator uses standard GPIO pins.
Below is a wiring table showing which pin each component connects to. If you build this yourself, follow it carefully. Connecting to the wrong pin can cause components to not work, or in some cases conflict with each other.
LCD display:
- GND -> pin 6
- VDD -> pin 2
- SDA -> pin 3
- SCL -> pin 5
RFID reader:
- 3.3V -> pin 1
- RST -> pin 22 (GPIO 25)
- GND -> pin 39
- IRQ -> Empty
- MISO -> pin 21 (SPI, GPIO 9)
- MOSI -> pin 19 (SPI, GPIO 10)
- SCK -> pin 23 (SPI, GPIO 11)
- SDA -> pin 24 (SPI, GPIO 8)
RGB indicator:
- 5V -> pin 4
- R -> pin 29 (GPIO 5)
- G -> pin 31 (GPIO 6)
- B -> pin 33 (GPIO 13)
Always double check every pin assignment before powering everything on. Some pins on the Raspberry Pi have specific functions, and it is easy to accidentally assign two components to pins that conflict with each other. Also make sure that I2C is enabled via "sudo raspi-config".
Software Setup - Raspberry Pi Side
The Raspberry Pi is responsible for running three things: a FastAPI backend, a PostgreSQL database, and a Gradio web interface. The API and the database are deployed using Docker.
Make sure Docker and Docker Compose are installed on your Raspberry Pi. Clone the repository and navigate to the "RPi/api" folder. Before starting, make sure you have a ".env" file filled in with your database credentials. In the "RPi/api" folder, create a virtual environment by running "python -m venv .venv", and then run "pip install -r requirements.txt" to install all required packages. Once that is done, start the stack by using "docker compose up". The database and API will start automatically, you can verify this by running "docker compose ps" in the terminal.
Navigate to "RPi" and use "python app.py" to launch the Gradio interface, this can be found in your browser via "<pi-ip-address>:7860". A service is used to make the Gradio interface start by default when the Raspberry Pi is powered on.
The Gradio interface is built using six different tabs to keep the interface clean. The "About" tells the user about HockeyVision and how to use it. A data tab to display the stats, an operating tab used to control the shooting session, a debugging tab to test all the hardware, a rankings tab for player rankings, and a config tab to configure the IP address of the laptop being used.
The combination of deploying the API and backend with Docker, and using a service for the Gradio interface makes the Raspberry Pi side headless, meaning you just have to give the Raspberry Pi power and everything will start up automatically.
Software Setup - Laptop Side
The laptop side of HockeyVision is responsible for one thing, running the AI. It reads frames from the camera, analyses them in real time, and sends the results back to the Raspberry Pi.
The camera used is a Sony a5100 which sends frames to the laptop through an HDMI capture card. The system continuously reads frames while in the Capturing state and runs at 1080p and 60 frames per second. If you use a different camera or capture card, you may need to change the device index.
The laptop side is started by running "python Laptop/ws_server.py" from the root directory. This launches everything automatically. Before starting, make sure your ".env" file contains the IP address of your Raspberry Pi.
The inference engine is where the AI runs. Once a session starts, it processes the incoming frames using both YOLO models, detecting the puck, the goal, and the goal corners in real time. When a shot is detected, it calculates which zone the puck was in and passes the result forward.
The sender takes the shot result and posts it to the Raspberry Pi over HTTP. It runs in a background thread so it never interrupts the inference pipeline. If the connection fails, it automatically retries up to three times before giving up.
The WebSocket server is what ties everything together. It receives session commands from the Raspberry Pi, start and stop, and tells the inference engine what to do.
Running the System
With everything set up, here is a description of how a full session works from start to finish.
Start by giving the Raspberry Pi power. Since the Gradio interface runs as a service, it starts automatically. Open a browser on a device connected to the same network as the Raspberry Pi and navigate to "<pi-ip-address>:7860" to access the Gradio interface.
On the laptop, run "python Laptop/ws_server.py" to start the inference engine. Once running, the system is ready to receive commands from the Raspberry Pi (make sure that your laptop's IP address is filled in the config tab). To start a session, go to the Operating tab. Scan your RFID card against the reader to identify yourself as a player. The session will start automatically if you exist in the database, otherwise you have to sign up. The LCD display will confirm that the system is active, and the RGB indicator turns green.
Make sure that the camera is positioned in front of the goal and the entire goal is visible. Shots can be taken and the system detects the puck entering the goal, analyses the frame, and determines which zone was hit. The result appears on the LCD display and in the Gradio interface.
When you are done, press "STOP SESSION" in the Operating tab or scan your player card. The RGB indicator turns red and the session ends. All your shots are saved and visible in the Data tab, including the "Shot Position Map" showing where your shots have landed over time.
Results, Limitations, and Future Work
HockeyVision started as an idea to solve a real problem, players practicing alone with no feedback.
The system detects shots in real time, identifies which zone of the goal was hit, and gives feedback through hardware and a Gradio interface. All shot data is stored and visualized so players can track their progress over time.
The most significant limitation is the camera setup. The system requires a fixed camera angle with the entire goal visible at all times. Small adjustments in position or angle can affect detection accuracy negatively.
If I were to continue developing HockeyVision, the first priority would be expanding the dataset with more varied footage to improve robustness. Training on a real-sized hockey goal instead of a mini-goal would also be something to work on. A mobile app for viewing stats would also be nice to have.
This project taught me a lot, everything from training AI models, building hardware systems, and connecting everything together into something that actually works.