Last Updated or created 2025-05-27
Or anything else. ( idea from a reddit post )
UPDATE: 20250523
Combining a GPS module, compass, a LED ring and some code, I want to make a little device which shows you the way to the nearest … something.
To make it completely standalone, I have to use a SIM module. (Same as I have used before) This POC will use my phone as hotspot.
The LED ring will show the direction to go.
Edit: Maybe not a LED ring but a little display.



As previously posted, I was playing with Overpass turbo.
Using an API, I can use code to query this.
- Arduino sends latitude, longitude to my webserver
- Webserver queries API for neastest POIs and calculates distance.
- Send data from webserver to arduino
- Arduino uses heading data to light up direction LED
(also on secondary display with distance info?)
edit: and shop info
Test code for my web server to query the data
import overpy
import math
api = overpy.Overpass()
# This location will be filled with data from GPS module on Arduino.
latitude = 52.2270745 # Center latitude (e.g. Berlin)
longitude = 5.177519 # Center longitude
box_size = 0.05 # Box size in degrees (about ~5 km)
south = latitude - box_size
north = latitude + box_size
west = longitude - box_size
east = longitude + box_size
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # Earth radius in km
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
d_phi = math.radians(lat2 - lat1)
d_lambda = math.radians(lon2 - lon1)
a = math.sin(d_phi / 2)**2 + math.cos(phi1) * math.cos(phi2) * math.sin(d_lambda / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return R * c # Distance in kilometers
# Calculate bearing in degrees (0-360)
def bearing(lat1, lon1, lat2, lon2):
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
delta_lon = math.radians(lon2 - lon1)
x = math.sin(delta_lon) * math.cos(phi2)
y = math.cos(phi1) * math.sin(phi2) - math.sin(phi1) * math.cos(phi2) * math.cos(delta_lon)
initial_bearing = math.atan2(x, y)
compass_bearing = (math.degrees(initial_bearing) + 360) % 360 # Normalize to 0–360
return compass_bearing
# Overpass QL query
query = f"""
[out:json];
node
["shop"="alcohol"]
({south}, {west}, {north}, {east});
out body;
>;
out skel qt;
"""
try:
result = api.query(query)
# Collect and sort places by distance
places = []
for node in result.nodes:
node_lat = float(node.lat)
node_lon = float(node.lon)
distance = haversine(latitude, longitude, node_lat, node_lon)
direction = bearing(latitude, longitude, node_lat, node_lon)
name = node.tags.get("name", "Unnamed")
places.append((distance, direction, name, node_lat, node_lon))
places.sort()
print(f"Found {len(places)} alcohol-related places sorted by distance:")
for dist, dir_deg, name, lat, lon in places:
print(f"- {name} at ({lat:.5f}, {lon:.5f}) — {dist:.2f} km, {dir_deg:.0f}°")
except Exception as e:
print(f"Error: {e}")
Output:
Found 10 alcohol-related places sorted by distance:
- The Skiff at (52.22583, 5.17860) — 0.16 km, 152°
- Onzewijnen at (52.22612, 5.17045) — 0.49 km, 258°
- Gall & Gall at (52.23244, 5.19204) — 1.15 km, 59°
- Gall & Gall at (52.21536, 5.16735) — 1.48 km, 208°
- Eric's Beer Craft at (52.21549, 5.16632) — 1.50 km, 211°
- Slijterij at (52.21082, 5.15692) — 2.29 km, 218°
- Gall & Gall at (52.21590, 5.14074) — 2.80 km, 244°
- Gall & Gall at (52.25422, 5.22705) — 4.53 km, 48°
- Gall & Gall at (52.26808, 5.18348) — 4.58 km, 5°
- Il DiVino at (52.27507, 5.16414) — 5.41 km, 350°
Example using Overpass Turbo to find breweries
Other ideas
- Geocaching (Thanks Vincent)
- Find each other at festivals?
UPDATE
Building the hardware : First design
Some test code
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"
// Overrule stuff
#define TFT_CS 18 // Chip select
#define TFT_DC 5 // Data/command mode
#define TFT_BL 4 // Backlight control
#define TFT_MOSI 12 // SPI Out AKA SDA
#define TFT_SCLK 13 // Clock out AKA SCL
#define TFT_MISO -1 // pin not used
#define TFT_RST 23 // Reset ################# IMPORTANT, won't work without!! Took me a hour!
// Need this changed from example also
Adafruit_GC9A01A tft(TFT_CS, TFT_DC,TFT_MOSI,TFT_SCLK,TFT_RST,TFT_MISO);
float angle = 0;
void setup() {
tft.begin();
tft.setRotation(0);
tft.fillScreen(GC9A01A_BLACK);
drawCompassFace();
}
void loop() {
drawNeedle(angle, GC9A01A_RED);
delay(1000);
drawNeedle(angle, GC9A01A_BLACK); // Erase previous needle
angle += 15;
if (angle >= 360) angle = 0;
tft.setCursor(60, 100);
tft.setTextColor(GC9A01A_WHITE); tft.setTextSize(2);
tft.println("230 Meters");
}
// Draw static compass face
void drawCompassFace() {
int cx = tft.width() / 2;
int cy = tft.height() / 2;
int radius = 100;
tft.drawCircle(cx, cy, radius, GC9A01A_WHITE);
tft.setTextColor(GC9A01A_WHITE);
tft.setTextSize(1);
tft.setCursor(cx - 3, cy - radius + 5); tft.print("N");
tft.setCursor(cx - 3, cy + radius - 10); tft.print("S");
tft.setCursor(cx - radius + 5, cy - 3); tft.print("W");
tft.setCursor(cx + radius - 10, cy - 3); tft.print("E");
}
// Draw compass needle
void drawNeedle(float angleDeg, uint16_t color) {
int cx = tft.width() / 2;
int cy = tft.height() / 2;
float angleRad = angleDeg * DEG_TO_RAD;
int x = cx + cos(angleRad) * 90;
int y = cy + sin(angleRad) * 90;
tft.drawLine(cx, cy, x, y, color);
}



