Posted on October 30, 2026
Category: Technology
Tags: android, flutter, dart, sensors, gyroscope, accelerometer, signal-processing, golf, gps, motion-detection, field-testing
Views: 14
GPS4Golf, my Android golf GPS app, measures drive distance with two taps. You tap Mark where you hit from, walk to the ball, and tap Mark again. The app measures the distance between the two points.
The weak point is the human. On a busy tee, with a playing partner talking and a glove to put back on, the first tap is the one that gets forgotten. Without it there is no drive distance for that hole, and a drive is the number the app exists to record.
The phone has a gyroscope and an accelerometer, and it is in my pocket for the whole round. So the obvious idea was to let the phone notice the swing and Mark it automatically. This post is about why that idea did not survive real rounds, and about the much narrower feature that did.
The phone lives in my right front pocket for the whole round. I am right-handed, so that is the trail leg, which turns hard toward the target in the downswing. Detection runs on rotation magnitude, so it does not matter which way up the phone sits in the pocket.
The first version logged only. Whenever the gyroscope saw a fast rotation, the app wrote a swing row to the round's event log with the peak rotation, the peak acceleration and how long the signal stayed above the trigger. Nothing was marked automatically. The plan was to play rounds, compare the rows with my manual Marks, and only then decide on a rule.
The first log was mostly walking. While I walked, a row appeared roughly every 3 seconds, with peak rotation between 5 and 8 rad/s and less than 100 ms above the trigger. Real tee swings peaked between 10 and 17 rad/s and stayed above the trigger for 250 to 450 ms.
That looked like a clean split until the walking rows were removed. Then the remaining rows near real shots and the rows everywhere else had almost the same distributions. The reason was practice swings. I take one or two between shots, and from the pocket a practice swing and a real one produce the same rotation, for the same duration.
One tee made it plain. On the 17th I hit five tee shots, and the roughly 20 rows logged while I stood there all sat between 5 and 9.2 rad/s. Nothing in them said which five had hit a ball.
A rule based on position worked better than one based on motion. A spot where I stayed within 12 m for 30 seconds and then moved more than 50 m within 90 seconds reproduced all 27 of my manual Marks. It also produced 99 candidates for a round of about 46 full shots, so it could not be trusted to add strokes on its own.
Rotation cannot separate a practice swing from a real one, but one thing does differ: a real swing hits a ball. Impact should show up as a short jolt in the accelerometer right at the bottom of the swing, where the rotation peaks.
So the app started recording raw waveforms from both sensors whenever a fast rotation happened while GPS said I was standing still. From each waveform it computes one number, the spike: how far the acceleration jumps above its local baseline in a short window around the rotation peak. Comparing against the local baseline cancels out the slow, large acceleration of the leg turning, and leaves the sharp jolt of the strike.
With a cut-off of 15, this was the first measurement that separated practice from play. Across two rounds no practice swing reached 15. The cost was recall:
Real shots with a spike of 15 or more:
From a pocket, half of all drives and almost no other shots produced a jolt that big. That rules out automatic Marks for every shot. A feature that catches one fairway shot in five is worse than none, because the user stops trusting the Marks it did make.
The useful part of those numbers is the first line. On a driver tee, a spike almost always means a real shot, and a driver tee is exactly where the forgotten Mark costs the most. The app already had a check for that case: when the first Mark of a hole is far from the course's tee, it asks whether to add the tee shot. Swing detection now makes that check better instead of replacing it:
The detected spot is better than the course data, because it is the tee box I actually played from rather than the one OpenStreetMap recorded. In the first round with this logic, the one automatic insertion landed 0.4 m from where the swing had been detected.
The next round inserted nothing. Every forgotten tee Mark fell back to the question.
The log explained it. That day's tee shots had spikes between 10 and 14. None reached 15. The cut-off had been chosen from the two rounds where it worked, and it did not hold up on a third day. A different pair of trousers, the phone sitting differently in the pocket or a slightly different strike could each account for a few units.
The fix was to stop treating 15 as meaningful. The cut-off is now far lower, just high enough to filter out footsteps. Lowering it so far is safe because of where it applies: a false positive at that point is a practice swing on the same tee box, so the inserted tee shot is still in the right place, give or take a few metres, and Undo is right there. The strict threshold was protecting against a mistake that costs almost nothing.
Some courses in OpenStreetMap have greens but no tees, so "near the course tee" has nothing to measure against. For those holes, a standing swing counts as a tee shot when it is far enough from the green for the hole's par, a longer distance on a par 5 than on a par 4.
That rule has a hole of its own. A short drive on a long par 5 can leave the second shot still far enough from the green to pass, so the second swing would replace the tee spot. Once a spot has been detected, later swings can replace it only if they are within roughly a tee box of it. Mulligans still overwrite it, while the second shot down the fairway cannot.
Log before you decide. The first version recorded rows and acted on none of them. Every rule in this post came from comparing those rows with what actually happened, and two of my early guesses (that rotation alone would do, and that 15 was a safe cut-off) were wrong.
Ask what a mistake costs before tuning for precision. Automatic Marks on every shot would put wrong strokes on the scorecard. A wrong tee position on a tee box that the player was standing on anyway costs nothing. The second case does not need a strict threshold.
A threshold from one or two rounds is a guess. Signal strength from a pocket changes from day to day. Any cut-off that sits close to the values it was fitted on will fail on some other day.
Make the user's correction cheap. Undo is what made the low threshold acceptable.
Know whose data it is. Every number here comes from one right-handed player with the phone on the trail leg. The detection uses only the size of the signals, not their direction, so nothing in it is right-handed. But a left-hander with the phone in the same pocket carries it on the lead leg, which braces rather than turns through the downswing, and I have no data on how that leg moves. If the swing is not detected, the app falls back to asking, so the cost is that the feature helps less, not that it adds wrong shots.
The first post in this series covered how the course data is built, in From OpenStreetMap to a Golf Course API. The app itself is GPS4Golf, available on Google Play.
Disclaimer: This blog post was created with assistance from Claude, an AI developed by Anthropic, under my direct supervision and guidance to ensure accuracy and alignment with my vision for the content.