# IoT Golf Statistics Tracker
By Joel Toryd, jt223kg. This is an IoT golf shot tracker developed for the course *1DT305 - Tillämpad Internet of Things, Introduktion* at Linneuniversitetet. The developed IoT device of this project aims to make tracking and visualising golf shot statistics easier on and off the golf course. With an IMU and a GPS module, the device can capture accurate position and heading data for each golfshot. The main Raspberry Pi Pico WH microcontroller processes the data for visualisation both on an included 16x2 LCD display as well as an online dashboard provided by https://io.adafruit.com/. If you choose to follow this tutorial, you should have a working prototype within 2-3 hours (not including 3D printing)!
# Objective
Golf is a game of statistics and risk management. It is impossible to hit the golf ball perfectly every time. This means that there will be deviations in length and accuracy of each shot due to human error and the differing conditions of the environment. The size of this deviation is a measurement of how good a golf player is. If a player is aware of their most statistically probable shot length and dispersion the game becomes significantly easier (given that the player has adequate accuracy, dispersion and shot length). Tracking these statistics are therefore valuable, not only for a competitive edge, but also as a way of tracking improvement in a golfer over time.
The device developed here aims to make the process of collecting and analysing statistically valuable data easier. As a handheld device it should be easy to bring along and easy to use before and after each shot. The future aim for the device is to incorporate a laser range-finder, thus adding new functionality to a device most golfers already use during play. The device will give the user short and relevant data on course, but a more comprehensive overview on the online dashboard after the game to provide valuable insight. Such as average shot lengths and average dispersions and errors.
# Material
Listed below are the main components used in this project. The LCD-display, button and encoder were components that I had laying around since previous projects, so feel free to use any kind of display you like or have access to. The GPS and BNO055 chips were the cheapest I could find, but there are more quality versions available on Electorkit. Further materials required for this project is wire for connecting everything, an USB-A to USB-micro wire for programming and powering the Pico and a breadboard for connecting everything. If you choose the cheapest alternatives as I did, you perhaps need to purchase some headers for connecting to standard breadboards and wires, as well as a soldering iron and solder for soldering the headers.
The Raspberry Pico is the main brains of the operation. The LCD is used for giving the user in field information (debugging and analytics). The potentiometer is used for operating the LCD in 4-bit mode, so if you purchase an I2C LCD, you won't need this. The GPS-module is used for location tracking and the BNO055 chip is an IMU used for tracking headings and angles. Perhaps a simple gyro/acceleration sensor is all that this project requires, but I liked the added accuracy of the fused 9-axis sensor in the BNO055. The button is for user interaction with the device.
| Image | Description | Purchase link | Price |
| --------------------------------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|  | Raspberry Pi Pico WH | [Electrokit](https://www.electrokit.com/raspberry-pi-pico-wh) | 99 kr |
|  | 16x2 LCD | [Elektrokit](https://www.electrokit.com/lcd-2x16-tecken-jhd162a-stn-bla/vit-led) | 99 kr |
|  | 10k Potentiometer | [Elektrokit](https://www.electrokit.com/pot-10k-lin-pcb-rk09) | 25 kr |
|  | GPS module | [Amazon](https://www.amazon.se/ICQUANZX-GY-NEO6MV2-flygkontrollmodul-superstark-keramisk/dp/B088LR3488/ref=sr_1_1?crid=ANNS3JUGVYFT&dib=eyJ2IjoiMSJ9.Vw1y9Dz-Ksnv_Z6Bwp_nVSzv9HQVwj-cIuU024SpRLC3ktpdIZu-62Y0Lp1fIh5T9Gp1hATFWtVVWXAAWJVHqL7gUimktGe8gO3MnwqV13o4nkLZdy5WBI7Y3NFV7YM5Jz5VItIlgibhvid8HIO0eiVHZOsH04e5OMGhZQ5ibS5LDDZ6qy9gGIplihVclGIfkTaYoBEwQ6CVLB-Pt1wKO5fWbB2Q-4YTOyMqQI36Vy-Uz7xhqIfiaUClidDGFaQGhiWvuYPSfmFg-ZJ1rV6BvfudxMlvPMHQL4xaFGGQwxI.41n-yaloM0k4mB_fZ-aldYEvnKbPkYB2TgPHWX0S4_8&dib_tag=se&keywords=GY-NEO6MV2+NEO-6M&qid=1751381812&sprefix=gy-neo6mv2+neo-6m+%2Caps%2C85&sr=8-1) | 110kr |
|  | 9 Axis IMU, BNO055 | [Amazon](https://www.amazon.se/Gyroskopsensormodul-GY-axelmodul-Acceleration-Geomagnetismssensor/dp/B091CVMVPF/ref=sr_1_6?crid=19Y256FVPDYTT&dib=eyJ2IjoiMSJ9.LHQvftZ3UItoxAEUbcIM1MmHyIkN2-7sb7gL6GUJPryBl4jimDpzLUAm6cxjYB2TVizzPC28fw3mww7h9I023YuRZsIIHVWcr65Utt1kJ4E1pXupTuQtHtdz9lsThkeGjSX0qPUjnqhaN4rS2RAfwK5OdmgT0ZDXVAVeSuSOamB7AXdkX_YTiYTg8PccTQqVLDpBvhmzLyVAjuHDlAotqNzuAIutzafk2T6jbISpNvZGY95MsT019lLz_xwqseZsAeo_1J9l1yWG4fIPxgFoxCYZSKJ_-KVu6goiXnHYx0o.skt3KXM2pGbI408HrCVqyC1rXbhiUW5_ivRnPnI3zLM&dib_tag=se&keywords=BNO055&qid=1751382311&sprefix=bno055%2Caps%2C100&sr=8-6) | 269kr |
|  | Momentary button | [Elektrokit](https://www.electrokit.com/en/tryckknapp-momentan) | 19 kr |
# Computer setup
I'm programming from a windows 10 machine using VScode as an IDE with the [MicroPico addon](https://marketplace.visualstudio.com/items?itemName=paulober.pico-w-go), which eases the process of connecting and uploading files to the Pico. For a detailed tutorial on how to install and setup this software, check out these tutorials: [VScode Setup](https://hackmd.io/@lnu-iot/rkiTJj8O9) (ignore the part about Pymakr, it is not supported anymore, instead use microPico), [MicroPico setup](https://hackmd.io/@lnu-iot/H1MgIIaQex), [Firmware setup](https://hackmd.io/@lnu-iot/rkFw7gao_). Don't forget to install [Node.js](https://nodejs.org/en). I've had some issues with faulty terminal printouts and connectivity, so perhaps [Thonny Ide](https://hackmd.io/@lnu-iot/SyTPrHwh_) could be an alternative to VScode. However, if you make sure to run the programs directly from the virtual MicroPico workspace you should minimize the amount of trouble you will encounter.
# Putting everything together
The GPS, IMU and button are powered from the Picos supplied 3.3v, while the LCD is powered directly from the 5v USB supply via the VBUS pin. See below for a detailed circuit diagram.

The LCD I had on hand did not come with a shield or capability to communicate via I2C protocol, so it required a lot of wires and a library to work in 4-bit mode instead. But the library does not require any specific pins to be used, so I chose pin 4-7 on the Pico to correlate to DB4-DB7 for neatness sake. The GPS communicates via UART, so make sure that the pins you connect it to are UART enabled. The same goes for the BNO055, but it instead communicates using the I2C protocol, so make sure that the pins you connect it to are I2C enabled.
In its current form (see pictures under "Finalizing the design" further below), the project is not suitable for production. More than a housing would be required for it to go into production. But a further discussion regarding this is held later in the tutorial
# IoT Platform
I've chosen to use the free Adafruit IO platform for its simplicity and ease of setup. To setup an account and connection, follow [this tutorial](https://hackmd.io/@lnu-iot/r1yEtcs55), but ignore the Webhooks and Adafruit IO Actions as that won't be used in this project. The free plan has more than enough functionality, but only 30 days of storage. This is no problem, as I've implemented a local storage system on the Pico. The platform uses the MQTT protocol to communicate with IoT devices.
For future and further development, I would like to look into some sort of self-hosting IoT platform for better control of visualisation, storage and cloud computing. While the dashboard and blocks of Adafruit IO are serviceable, they leave a lot to be desired in terms of customizability. The map-block would especially need some customization to be the optimal visualisation tool for this project.
# The code
All code used is included in [this GitHub repo](https://github.com/Tvattis/IoT-Golf-Tracker). I have used several libraries for ease of implementation. Here all non standard libraries are listed.
| Library name | Description | Author | Link |
| --------------------------------------- | ----------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------ |
| bno055.py & bno055_base.py | For calibrating and interpreting IMU data | Radomir Dopieralski | [Link](https://github.com/micropython-IMU/micropython-bno055) |
| keys.py, mqtt.py and wifiConnection.py | For connection and IoT communication | LNU and various | [Link](https://hackmd.io/@lnu-iot/r1yEtcs55#Webhooks-in-Adafruit-and-sending-messages-to-the-Discord-server) |
| lcd_4bit_mode.py | For displaying text to the LCD | M. Pugazhendi | [Link](https://www.instructables.com/Raspberry-Pi-Pico-16x2-LCD-4Bit-Mode-Interface-BCD/) |
| micropyGPS.py | For communicating and parsing GPS data | Michael Calvin McCoy | [Link](https://github.com/inmcm/micropyGPS/) |
The .txt and .dat files are used for storing data locally on the Pico.
A quick walkthrough of the main loop is as follows. For every loop, the Pico reads the GPS data and displays it to the LCD with a refresh rate of 1 new update per second. If there is more important information that needs to be displayed it wont update the screen with this base GPS information. After updating the GPS data, the Pico checks if there is enough data to calculate statistics. If there is, it does some calculations and prepares data for upload to Adafruit IO. The upload function is called every 60 seconds and checks for connection to WiFi and if there is data to send. The program also features actions that will be performed when the button is pressed and released. This is handled via interrupts that set flags to handle the logic in the main loop. If the button is pressed, an initial heading is stored. Then when the button is released the angle between the first and second heading is recorded along with the GPS-location.
Most calculations assume a flat earth, as the distances are relatively small, and have been tested to be accurate to within 1 meter. However, the recording of data could use with some optimization for accuracy. Perhaps by taking an average of the GPS position updates between button press and release. Right now, the program just chooses the GPS-data fetched precisely after the button is released. Also the addition of some kind of aiming assist would be a relatively easy optimization for more accurate angles. Furthermore, reading and writing to file should be put in a separate library just to keep everything clean and working.
# Transmitting the data / connectivity
Data is only sent when there is available data and a stable WiFi connection. However, checks for these conditions occur every 60 seconds. WiFi as a wireless protocol was chosen since it is natively supported in the Raspberry Pi Pico WH, as well as there is no need for the detailed dashboard view while out on the golf course playing (and if you want that, you can connect to your phone via hotspot). The intended use case is to record data while out in the field, then let the device upload the data when you get home to your home WiFi.
The Transport protocol used is MQTT, as this is a simple and effective protocol for data publication of this type. The GPS-data is sent as JSON packages, and statistical data is sent as a raw string for compatibility with the feeds of Adafruit IO.
# Presenting the data
Simplified data is presented on the LCD display of the device. However, more detailed data and statistics are presented in an Adafruit IO Dashboard. See below figure for example of how it can look like:

The red letters are added to the screenshot after it was taken to better explain the dashboard here. The dashboard is built up from one block that displays a map with the recorded and calculated GPS positions and another block that presents data of the shots. Data considered is the shot length and the PEI (procent error index, error distance divided by shot length). In the example above, one shots is considered, A-C. In the GPS block 3 points are displayed for each shot taken. The first point (A), is where the shot is taken from. The second (B) is where the shot landed. The third (C ) is the calculated point of aim for the shot.
This data is saved on Adafruit IO storage for 30 days. However, it is also stored locally on the pico for further/manual analytics of the data. The size of the code in the project is 94 208 bytes. Data for one shot takes around 200 bytes. The raspberry pi has 2 000 000 bytes of available storage. Therefore it can store 9 528 shots or 101 rounds of 94 shot golf (average shots for an amateur playing 18 holes) or 4 years of 25 rounds/year before it needs to be flushed. Therefore this choice of data storage is justified for this device, at least in the development process.
For future development a more sophisticated data storage and backup system needs to be developed. Especially the ability to sort and label data in accordance to rounds played or practice done, which could be done with automatic triggers built into the IoT-platform. It would also need to be accessible online, perhaps through some sort of self hosting IoT platform as discussed previously.
Manually recorded data triggers local edge computing on the device, which processes the data and makes it ready for publishing via MQTT to Adafruit IO.
# Finalizing the design
I did design an enclosure for 3D-printing as seen below. However, I only had old crusty filament to print with, which resulted in a non usable final print. Due to time constraints, I won't be able to print a new enclosure, so for now, this is a breadboard project. I've included the STEP files for 3D printing in the github repo if you are interested though.
| LCD Side | Back Side |
| -------- | -------- |
| |  |
Printed version of the enclosure rendered non-usable by either bad filament or some issue with the hotend/extruder of the printer. See picture below

See the picture below for my device in action. In this tutorial I've discussed specific opportunities for future development and improvements of the design. The biggest points of improvement would be the successful construction of a housing for the project, enabling it to be further tested in real world environments. The next big step would be to develop a more sophisticated way of visualising the data on a dashboard of my own design. The codebase could also do with some further structuring, right now it is dangerously close to being too much spaghetti code to have a good overview.

Here is a video of how to use the device: https://youtu.be/JYZdhd4g208. The LCD-screen in the lower left corner is an indication of what is displayed on the LCD during each phase of use. The example of the dashboard in this tutorial is taken during this demo.