Putting Launch Monitor using Arduino

Mac Padilla
11 min readMay 5, 2024

I have created a small project that has single handedly helped me have less three putts and better over all control in my putting game. My project is a DIY Launch monitor for “putting only” that has 4 parameters including: Ball speed, Ball distance, Club face angle, and Club attack angle. Below is all my documentation for how to set the project up along with the cost of everything in amazon.

1) Set Up

First you need to purchase all the materials to make this project work. Some of the products you might not need to purchase, however get what you want/need. This spreadsheet has the list of materials which also tells you what certain aspect of the project it controls.

Disclaimer***** For the Gyroscope the prongs and gyroscope come separate. You will need to solder these together to hold them in place (tape will not work). This will add an extra $10–$40 to the total price according to which soldering kit you would purchase.

Once all materials are in your hands you are ready to start building your own putting launch monitor.

Second you need to download Arduino IDE on your mac or computer device, this will hold the code for how the project works. https://www.arduino.cc/en/software once downloaded follow the picture steps below.

2) Lasers

The lasers are the heart and sole of the project, these will help you determine speed and distance of each putt you hit. First grab 1 of the lasers, it looks like a golden cylinder.

Next grab the laser receiver which is what grabs the laser data and sees when something passes in front of it.

It will come in two parts, you will have to place the sensor in the three holes like it looks above. The flat face should be pointing away from the prongs like it looks above.

Next you want to position them about 3 inches away from each other like so and start plugging them in. For the golden laser you want to grab two female to male wires and plug them into the first one and the third one. The prong with the S next to it needs to be plugged into any of the numbered holes in the Arduino, lets do “2” to get you started. The other prong close to the negative sign need to go to a GND hole (ground) which can be any of the three.

Next place the laser receiver 3 inches away from the laser. Three prongs for three different wires, the first is the VCC which is power and should go in the 5v hole. Next is the out pin which will send the Arduino the signal, this goes to hole 5 close to where the other wire is. The last which is labeled GND which should be placed in any other GND labeled hole. Lastly upload this code to a new file on Arduino IDE and name it Lasers.

const int pinLaser = 2; // output signal pin of laser module/laser pointer
const int pinReceiver = 5; // input signal pin of receiver/detector (the used module does only return a digital state)

void setup() {
pinMode(pinLaser, OUTPUT); // set the laser pin to output mode
pinMode(pinReceiver, INPUT); // set the laser pin to output mode
digitalWrite(pinLaser, HIGH); // emit red laser
Serial.begin(9600); // Setup serial connection for print out to console
}

void loop() {
int value = digitalRead(pinReceiver); // receiver/detector send either LOW or HIGH (no analog values!)
Serial.println(value); // send value to console
delay(1000); // wait for 1000ms
}

On the top left there will be a button to upload the code to the Arduino to make it work, click it. The laser will start to emit and you will need to angle the laser with some tape or even you hand and make sure it hits the receiver. Once this is done on the top right there will be a button that looks like a magnify glass and will say “Serial Monitor”. Once clicked you should see only 1s, however once you put your hand in front of it, it will change to 0. If this happens you can move on. Here is a video demonstrating how to set this up.

3) Gyroscope

The first part is soldering the Gyroscope to the prongs, there are a bunch of tutorials online on how to solder but the best advice I can give is make sure that the prongs look like Hershey kisses, this will make sure that the prong and gyroscope are together.

After soldering you will need to grab 4 female to male wires and start plugging them into the Arduino. The first would be the VCC (power) which again will go into the 5v hole. Next is GND which again would go into a ground hole. The next two are the SCL and SDA prongs which can be connected to the same holes on the Arduino (located next to the red reset button). ***You only need 4 prongs out of the 8***

You then need to download an library which is very simple, first in Arduino IDE go to the left side and click the icon that looks like books. In the search look up MPU6050_light and install that library.

Once completed upload the code below which help you see how the gyroscope works.

/* Get tilt angles on X and Y, and rotation angle on Z
* Angles are given in degrees
*
* License: MIT
*/

#include "Wire.h"
#include <MPU6050_light.h>

MPU6050 mpu(Wire);
unsigned long timer = 0;

void setup() {
Serial.begin(9600);
Wire.begin();

byte status = mpu.begin();
Serial.print(F("MPU6050 status: "));
Serial.println(status);
while(status!=0){ } // stop everything if could not connect to MPU6050

Serial.println(F("Calculating offsets, do not move MPU6050"));
delay(1000);
// mpu.upsideDownMounting = true; // uncomment this line if the MPU6050 is mounted upside-down
mpu.calcOffsets(); // gyro and accelero
Serial.println("Done!\n");
}

void loop() {
mpu.update();

if((millis()-timer)>10){ // print data every 10ms
Serial.print("X : ");
Serial.print(mpu.getAngleX());
Serial.print("\tY : ");
Serial.print(mpu.getAngleY());
Serial.print("\tZ : ");
Serial.println(mpu.getAngleZ());
timer = millis();
}
}

4) Lasers pt. 2

This new setup will be able to control ball distance and speed within Arduino IDE, you first need to position everything according to the photo below. This will ensure the data is accurate when you putt. Use duck tape to make sure lines are accurate. You want to make sure you have enough room for your putter to go through without hitting a lasers and breaking it. I used 6 inches from each line.

The lasers need to be 4 inches apart from each other and the golf ball needs to be hit at least 4 inches behind the first lasers. If you purchased a breadboard you will then be able to use this breadboard so you can organize the wires. Here are multiple angles and multiple pictures so that you can have the exact same setup.

The first laser pin should be in hole 2, second laser pin should be in hole 3, first receiver pin should be in hole 5 and the second receiver pin should be in hole 6. Ground and power pins accordingly and after uploading this new code you should be able to see the distance and speed of each putt you have.

const int pinLaser1 = 2; // output signal pin of laser module/laser pointer 1
const int pinLaser2 = 3; // output signal pin of laser module/laser pointer 2
const int pinReceiver1 = 5; // input signal pin of receiver/detector 1
const int pinReceiver2 = 6; // input signal pin of receiver/detector 2

unsigned long startTime = 0;
unsigned long endTime = 0;
unsigned long lastResetTime = 0;
float elapsedTime = 0;
double friction = 0;
double velo = 0;
double distance = 0;

bool measurementDone = false;

void setup() {
pinMode(pinLaser1, OUTPUT);
pinMode(pinLaser2, OUTPUT);
pinMode(pinReceiver1, INPUT);
pinMode(pinReceiver2, INPUT);
digitalWrite(pinLaser1, HIGH);
digitalWrite(pinLaser2, HIGH);
Serial.begin(9600);
lastResetTime = millis();
}

void loop() {
unsigned long currentTime = millis();


if (currentTime - lastResetTime >= 30000) {
measurementDone = false;
lastResetTime = currentTime;
Serial.println("Resetting experiment...");
}

if (!measurementDone) {
int value1 = digitalRead(pinReceiver1);
int value2 = digitalRead(pinReceiver2);

if (value1 == LOW && value2 == HIGH) {
startTime = millis();
}

if (value1 == HIGH && value2 == LOW) {
endTime = millis();
elapsedTime = endTime - startTime;
friction = 0.983 / 8; //8 is the green speed
velo = 4 / ((elapsedTime / 1000) * 12);
distance = (pow(velo, 2)) / (2 * friction * 32.2) + 0.5;
Serial.print("###############################\n");
Serial.print(velo, 6);
Serial.print(" f/s\n");
Serial.print(distance);
Serial.print(" feet\n");
Serial.print("###############################\n");
Serial.println();
measurementDone = true;
}
}
}

You can use this code and set up to help with putting distance and speed control. It will reset after 30 seconds so make sure you have multiple balls for the best experience.

5) Gyroscope pt.2

This second part to the gyroscope and will help you see the last two parameters before we put it all together at the end. Set up the Gyroscope the same way as last time with the all the pins in order. You will now need to attach this gyroscope to the back of your putter. I did this with velcro but tape can be used and even glue if you’re crazy enough.

Once this is attached find a place where you are comfortably able to hit some putts. First copy and upload the code. Once you do you will see the serial monitor display ”Calculating offsets, do not move MPU6050” which means keep your putter where you want to start your swing. If you have a forward tilt press when you putt the ball, start there. If you start with your face a little open then do that. This will set your putter so that when you come in contact with the ball it will tell you your club face angle and attack angle upon impact and the difference from when you calculated the offsets.

#include "Wire.h"
#include <MPU6050_light.h>

MPU6050 mpu(Wire);
unsigned long timer = 0;
float attackangle = 0;
float faceangle = 0;

void setup() {
Serial.begin(9600);
Wire.begin();

byte status = mpu.begin();
Serial.print(F("MPU6050 status: "));
Serial.println(status);
while(status!=0){ } // stop everything if could not connect to MPU6050

Serial.println(F("Calculating offsets, do not move MPU6050"));
delay(1000);
mpu.calcOffsets(); // gyro and accelero
Serial.println("Done!\n");
}

void loop() {
mpu.update();

faceangle = mpu.getAngleY();
attackangle = mpu.getAngleZ();

if (mpu.getAccX() < -1.5){
Serial.print(faceangle);
Serial.print('. ');
Serial.print(attackangle);
return;
}
}

Disclaimer**** the Gyroscope stops responding after 30–60 seconds and you have to reset it in order for it to work again which means you have to upload the code again. Its a bummer but focus for the first two putts so you can get the best results.

6) Serial Control setup

I have created an interface to where you can see all the data after a putt but it first needs to be installed on your computer.

This repository has all the information that will transfer the Arduino data to the p5.js sketch I have created. First you need to go to the link and click assets. Download the zip file according to your system and opening it. At first it won’t let you open it because your computer doesn’t trust it. You will have to allow it in settings. After this you will be able to open it and see this program.

You will have to rescan the ports in order for it to see your Arduino. Select your port and connect to it.

7) The end

This is the last part to make my project. The code below is a combination of the lasers pt.2 and gyroscope pt.2 to where you can see all the data at once. Create a new file and paste the code into and call it something.

#include "Wire.h"
#include <MPU6050_light.h>

const int pinLaser1 = 2;
const int pinLaser2 = 3;
const int pinReceiver1 = 5;
const int pinReceiver2 = 6;

unsigned long startTime = 0;
unsigned long endTime = 0;
unsigned long lastResetTime = 0;
float elapsedTime = 0;
double friction = 0;
double velo = 0;
double distance = 0;
double stimpspeed = 10;

MPU6050 mpu(Wire);
float faceAngle = 0;
float attackAngle = 0;

bool measurementDone = false;
bool isCalibrating = false; // Flag to indicate if we're currently calibrating the MPU

void setup() {
pinMode(pinLaser1, OUTPUT);
pinMode(pinLaser2, OUTPUT);
pinMode(pinReceiver1, INPUT);
pinMode(pinReceiver2, INPUT);
digitalWrite(pinLaser1, HIGH);
digitalWrite(pinLaser2, HIGH);
Serial.begin(9600);

Wire.begin();
byte status = mpu.begin();
Serial.print("MPU6050 status: ");
Serial.println(status);
while(status != 0) {} // Stop everything if could not connect to MPU6050

lastResetTime = millis();
startCalibration(); // Start initial calibration
}

void startCalibration() {
Serial.println("Calculating offsets, do not move MPU6050");
mpu.calcOffsets(true, true); // Calculate offsets for gyro and accelerometer, true to verbose
Serial.println("Calibration Done!\n");
isCalibrating = false; // Calibration complete
}

void loop() {
unsigned long currentTime = millis();
mpu.update();

if (isCalibrating) {
return; // Do not proceed with measurements while calibrating
}

// Reset the experiment every 30 seconds
if (currentTime - lastResetTime >= 30000) {
measurementDone = false;
lastResetTime = currentTime;
isCalibrating = true; // Set calibrating flag
startCalibration(); // Recalculate offsets to reset gyroscope readings
Serial.println("Resetting experiment...");
return; // Skip further processing to allow calibration to complete
}

if (!measurementDone) {
int value1 = digitalRead(pinReceiver1);
int value2 = digitalRead(pinReceiver2);

if (value1 == LOW && value2 == HIGH) {
startTime = millis();
}

if (value1 == HIGH && value2 == LOW) {
endTime = millis();
elapsedTime = endTime - startTime;
friction = 0.983 / stimpspeed;
velo = 4 / ((elapsedTime / 1000) * 12);
distance = (pow(velo, 6)) / (2 * friction * 32.2) + 0.5;

faceAngle = mpu.getAngleY();
attackAngle = mpu.getAngleZ();

Serial.print(velo, 2);
Serial.print(",");
Serial.print(distance);
Serial.print(",");
Serial.print(faceAngle);
Serial.print(",");
Serial.print(attackAngle);
Serial.print(",");
Serial.print(stimpspeed);

measurementDone = true;
}
}
}

Once uploaded make sure the serial monitor is not open on the Arduino IDE. I’ll repeat MAKE SURE THE SERIAL MONITOR IS NOT OPEN ON ARDUINO IDE. Open the yellow p5.serialcontrol icon. Once open click the second white bar which will allow you to pick your port that is connected to the Arduino. Mine that Iuse is “/dev/tty.usbmodem14401” which is just one of the ports on my computer. Next go to the link below.

This looks crazy however all you have to do is scroll to line 27 on the skectch.js file and whatever your serialcontrol says import it. So mine says “/dev/tty.usbmodem14401" and I have it in that line thats the only thing you will need to change in this code. Next click the big hot pink play button. Now putt! It resets every 30 seconds so just wait till it says reset and putt again!

Hope you enjoy!

--

--