Skip to content

mdwasserman/RasPi_VPS

Repository files navigation

RasPi Visual Positioning System

VPS on Drone

This project provides a proof-of-concept Raspberry Pi Visual Positioning System (VPS) that generates simple non-GNSS geolocation through LoFTR matching a query image against offline Google Maps tiles. It is based on the drone_photo_geolocate pipeline but adapted for offline operation on a Pi. The project provides a simple LoRa communication interface for the sending and recieving of commands between transmit and recieve nodes.

Please make sure to read Gotchas and Troubleshooting.

Contents

Hardware

Pi VPS

  • transmit node:
    • Raspberry Pi 4
    • Waveshare SX1268 433M LoRa HAT
  • recieve node:
    • Raspberry Pi 4
    • Waveshare SX1268 433M LoRa HAT
    • Raspberry Pi Camera Module v1.3
    • Adafruit ICM-20948 IMU
    • A small power bank
  • Airframe:
    • any UAS that can carry the receiver payload (my DJI Mini 4K struggled)

Quickstart (Fresh Install)

Receiver Setup

Use this on recieve after cloning:

cd <REPO_ROOT>
python3 -m venv .venv_loftr
source .venv_loftr/bin/activate
python -m pip install --upgrade pip setuptools wheel
pip install --index-url https://download.pytorch.org/whl/cpu torch==2.11.0+cpu torchvision==0.26.0+cpu
pip install -r requirements.txt

Sanity check:

python -c "import torch, torchvision; print(torch.__version__, torchvision.__version__)"

Expected:

  • 2.11.0+cpu
  • 0.26.0+cpu

Important:

  • do not mix apt/system torch with this venv
  • service/runtime must use the same .venv_loftr

Edit service template and replace <REPO_ROOT> with your actual clone path.

File:

  • services/lora-camera-rx.service

Install/restart:

cd <REPO_ROOT>
sudo cp services/lora-camera-rx.service /etc/systemd/system/lora-camera-rx.service
sudo systemctl daemon-reload
sudo systemctl enable lora-camera-rx
sudo systemctl restart lora-camera-rx

Verify:

sudo systemctl status lora-camera-rx --no-pager
sudo journalctl -u lora-camera-rx -f

Transmitter Setup

The transmit node currently uses a one-shot command sender, not a long-running service. A minimal setup looks like this:

cd <REPO_ROOT>
python3 -m venv .venv_tx
source .venv_tx/bin/activate
python -m pip install --upgrade pip setuptools wheel
pip install pyserial RPi.GPIO

Then use commands directly:

cd <REPO_ROOT>
python3 lora/transmitter/send_lora_command.py "SET_POS <LAT> <LON> [ALT_M]"
python3 lora/transmitter/send_lora_command.py "TAKE_PICTURE_IMU"
python3 lora/transmitter/send_lora_command.py "GEOLOCATE_NOW 20"

Pre-Flight (Online): Build Offline Tile Archive

Run this while online before flight:

cd <REPO_ROOT>
source .venv_loftr/bin/activate
PYTHONPATH=src python -m photo_geolocate.run_prepare_offline_tiles \
  --config configs/search_area.current.yaml \
  --center-lat <LAT> --center-lon <LON> \
  --radius-m <RADIUS_M> \
  --zoom 20 \
  --out-dir data/archive/offline_tileset

Notes:

  • set your initial location first in configs/search_area.current.yaml:
    • prior_location.latitude
    • prior_location.longitude
  • alternatively, pass --center-lat and --center-lon on the command line (overrides config)
  • writes index.json + tile images to data/archive/offline_tileset
  • if center/radius omitted, defaults come from config
  • this pre-flight center is for tile archive generation only (not IMU runtime init)

Operating Defaults

Current runtime defaults used in this project:

  • offline tile source only: --offline-only --tiles-dir data/archive/offline_tileset
  • shortlist mode: --shortlist-k all (0) so all spatially filtered tiles get LoFTR
  • retrieval is still computed/logged, but not trusted for candidate pruning

First End-to-End Test

From the transmit node, send the following commands. I'd recommend keeping the radius as small as possible, about 50m:

python3 lora/transmitter/send_lora_command.py "SET_POS <LAT> <LON> [ALT_M]"
python3 lora/transmitter/send_lora_command.py "TAKE_PICTURE_IMU"
python3 lora/transmitter/send_lora_command.py "GEOLOCATE_NOW <RADIUS>"

After GEOLOCATE_NOW, inspect the latest run in:

  • data/archive/mission_runs/

Expected Output

Run Artifacts

Path What it contains What to look at first
winner.json Final selected tile + run metadata winner.estimated_query_center_latitude, winner.estimated_query_center_longitude, winner.score
tile_match_summary.json Ranked candidate tiles Top few entries and their score
interactive_diagnostics.json Per-tile matching diagnostics branches and patch diagnostics for debugging
match_visualizations/ Top rank match overlay images Quick visual sanity check
patch_visualizations/ Patch-level match overlays Patch behavior / failure modes

Coordinate Fields

  • winner.center_latitude / winner.center_longitude: center of the winning tile.
  • winner.estimated_query_center_latitude / winner.estimated_query_center_longitude: refined query-center estimate from LoFTR homography on the winning tile.

Receiver Logs

Use:

sudo journalctl -u lora-camera-rx -f

You should see:

  • LoRa command receipt (SET_POS, TAKE_PICTURE_IMU, GEOLOCATE_NOW)
  • periodic IMU position updates
  • camera capture success and image save path

Manual Pipeline Run (No LoRa)

cd <REPO_ROOT>
source .venv_loftr/bin/activate
PYTHONPATH=src python -m photo_geolocate.run_pipeline \
  --config configs/search_area.current.yaml \
  --query-image /path/to/query.jpg \
  --center-lat <LAT> --center-lon <LON> \
  --radius-m 50 --zoom 20 \
  --shortlist-k all \
  --offline-only --tiles-dir data/archive/offline_tileset \
  --fixed-out-dir --out-dir data/archive/mission_runs/manual_test

Useful flags:

  • --skip-match-visualizations for faster Pi CPU runs
  • --no-offline-spatial-filter if radius filtering removes all candidates

'Gotchas' and Troubleshooting

  • The Pi is slow to run this, so be patient. For a functional VPS, GPU compute is necessary.
  • If LoFTR hangs/crashes, confirm torch/torchvision versions in .venv_loftr.
  • If service fails at boot, check ExecStart and WorkingDirectory paths in service file.
  • If no tiles found, verify data/archive/offline_tileset/index.json exists.

About

This project provides a proof-of-concept Raspberry Pi Visual Positioning System (VPS) that generates simple non-GNSS geolocation through LoFTR matching a query image against offline Google Maps tiles.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages