← All posts

Why a running tour guide can't trust the compass

A phone in a pocket knows which way the phone is facing. It does not know which way you are going. Here is how U-tour works out direction, and why the compass is the fallback rather than the source.

Every audio guide has to answer one question before it says a word: which way is the listener facing? Get it wrong and the app narrates a church you passed a minute ago, or tells you the fountain is on your left when it is on your right. Nothing else about the experience survives that.

For a walking-tour app the answer is usually the magnetometer. The phone is in your hand, held up like a map, and the compass reading is the direction you are looking. For a running app that assumption breaks on the first stride. The phone is in a pocket, an armband, or a running belt. The compass faithfully reports which way the phone is pointing, which is some angle off your hip, and that angle changes with every step.

Two sources, opposite failure modes

There are two signals a phone can give you, and they fail in opposite conditions.

Course over ground is the primary signal in U-tour. The compass is what the app reaches for only when you are too slow for course to mean anything. That is the reverse of how most guides are built, and it is the single decision the rest of the direction stack rests on.

What happens at a red light

Reversing the priority creates a new problem. You are running east along the Embankment, you stop at a crossing, and your speed drops to zero. Course over ground has nothing to say. The compass says the phone is pointing roughly north, because that is how it sits in your pocket. A naive engine would swap to the compass and, for the thirty seconds you stand there, believe you are facing north. Anything it queued up in that window would be wrong.

U-tour keeps two ideas separate. There is the heading estimate, which is the best guess right now and is allowed to say "stationary, compass says north-ish". And there is the direction of travel, which is only ever set from course fixes and is held through a stop. The held direction stays east at the red light, so the landmarks queued ahead of you stay the landmarks ahead of you.

The hold is not a timer. It is argued down by evidence: a couple of course fixes that contradict it, once you are moving again, and it turns with you. A hold that expires on a clock would either drop too early at a long light or cling too long after you turned a corner.

Not claiming what it doesn't know

The last piece is being honest about confidence. When the heading is shaky, U-tour widens the cone it looks in and drops the directional language. A landmark is "nearby" rather than "on your right". That reads as a small loss of polish, and it is far better than confidently sending someone the wrong way.

The cone widens to eighty-five degrees either side, and deliberately not past ninety. Beyond a right angle a landmark is behind your shoulder, and you would have to turn round to see it. A wider cone would not be generosity. It would be breaking the promise that the guide talks about what is in front of you.

Why it is testable at all

All of this math lives in a module with no CoreLocation import. It takes plain coordinates, speeds and timestamps, which means a whole run can be replayed on the command line against a synthetic track with no phone, no simulator and no Xcode. Direction is the part of the product that everything else depends on, so it is the part we wanted to be able to prove rather than eyeball.