79832640

Date: 2025-11-28 14:18:19
Score: 0.5
Natty:
Report link

Why your location “jumps” even when you stand still

What you’re seeing is normal behavior for phone GPS, especially:

A few key points about GPS on mobile devices:

So there is nothing “wrong” with Expo Location itself. You’re just seeing the raw limitations of consumer GPS very clearly because your map is small and your update settings are aggressive.


Issues in the current configuration

You’re doing some reasonable things already (UTM transform, simple smoothing), but a few details make the jitter very visible instead of hiding it.

1. Over-aggressive watch settings

subscription = await Location.watchPositionAsync(
  {
    accuracy: Location.Accuracy.BestForNavigation,
    timeInterval: 500,
    distanceInterval: 0.5,
  },
  (newLocation) => {
    setLocation(newLocation);
  }
);

Problems here:

You’re essentially subscribing to noise in high definition.

2. Over-optimistic accuracy filter

const acc = location.coords.accuracy;

if (acc && acc > 8) return;

You’re discarding any reading where the accuracy is worse than 8 m. In many real environments, values below 8 m are rare. So what happens?

3. Smoothing that doesn’t actually smooth much

setSmoothedUtm(prev => {
  if (!prev) return { x: rawUtm.x, y: rawUtm.y };

  const dx = rawUtm.x - prev.x;
  const dy = rawUtm.y - prev.y;
  const movement = Math.sqrt(dx * dx + dy * dy);

  if (movement < 0.3) return prev;

  const alpha = 0.8;
  return {
    x: prev.x * (1 - alpha) + rawUtm.x * alpha,
    y: prev.y * (1 - alpha) + rawUtm.y * alpha
  };
});

Two main issues:

So the filter doesn’t do much to hide the GPS wandering.


What you can realistically do

You cannot turn GPS into a centimeter-accurate indoor tracker with code. But you can:

Below are practical changes that work within the limitations.


1. Use less aggressive update settings

Relax watchPositionAsync so you don’t hammer the GPS and you don’t get spammed with tiny fluctuations.

For example:

subscription = await Location.watchPositionAsync(
  {
    accuracy: Location.Accuracy.High, // or Location.Accuracy.Balanced
    timeInterval: 2000,               // at most once every 2 seconds
    distanceInterval: 2,              // only if moved ~2 meters
  },
  (newLocation) => {
    setLocation(newLocation);
  }
);

This does two things:

In many cases, High or Balanced gives more stable behavior than BestForNavigation for walking around at low speed.


2. Filter by realistic accuracy and movement

Next, make the smoothing logic match real GPS behavior:

Example:

useEffect(() => {
  if (!rawUtm || !location) return;

  const acc = location.coords.accuracy ?? 999;

  // Ignore very noisy readings
  if (acc > 20) return;

  setSmoothedUtm(prev => {
    if (!prev) {
      return { x: rawUtm.x, y: rawUtm.y };
    }

    const dx = rawUtm.x - prev.x;
    const dy = rawUtm.y - prev.y;
    const movement = Math.sqrt(dx * dx + dy * dy);

    // Ignore small movements that are likely just jitter
    if (movement < 2) {
      return prev;
    }

    // Strong smoothing: mostly keep old position
    const alpha = 0.2; // 20% new, 80% old

    return {
      x: prev.x * (1 - alpha) + rawUtm.x * alpha,
      y: prev.y * (1 - alpha) + rawUtm.y * alpha,
    };
  });
}, [rawUtm, location]);

Now:


3. Be honest about “arrival” distance

You currently trigger arrival when:

if (distanceToDestination !== null && distanceToDestination < 3) {
  Alert.alert('Arrived!', ...)
}

If your GPS accuracy is ±5–10 m, checking for < 3 m is optimistic. The position might easily jump between 2 m and 8 m from the sculpture while the user stands in the same place.

Use a larger radius (e.g. 7–10 m) and maybe require the distance to stay under that threshold for a couple of consecutive readings:

const ARRIVAL_RADIUS = 8; // meters

useEffect(() => {
  if (distanceToDestination == null || selectedDestination == null) return;

  if (distanceToDestination < ARRIVAL_RADIUS) {
    Alert.alert('Arrived!', `You reached ${TEST_POSITIONS[selectedDestination].label}`);
    setSelectedDestination(null);
  }
}, [distanceToDestination, selectedDestination]);

It’s better UX to say “you’re here” a bit early than never say it because of GPS jitter.


4. Accept that your map scale amplifies noise

You’re mapping UTM → pixels based on sculpture coordinates that are very close together. When your entire site is, say, 30 m wide and your screen is 300 px wide:

That’s why the dot looks like it’s flying around.

There is no way around this from GPS alone. What you can do:


5. If you truly need high precision: GPS alone is not enough

For a small offline map, if you need sub-meter or 2–3 m reliable precision, you won’t get it on regular phones with only GPS, especially offline and near structures.

Real alternatives (if this were a production problem):

That’s beyond Expo Location and outside pure code solutions.


Summary

You can’t make GPS behave like a laser pointer, but you can make the experience look stable and usable for an offline sculpture map.

Reasons:
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Starts with a question (0.5): Why you
  • Low reputation (1):
Posted by: Vanshat