Build a Truck-Safe Route Planner
A Python CLI that plans routes between cities, scans for low bridges and weight restrictions, and finds truck stops along the way.
Regular routing apps send trucks under low bridges. This CLI plans a route between two cities, then scans the corridor for low clearance bridges, weight-restricted roads, and truck stops — a safety audit layer on top of routing.
What you’ll use
Section titled “What you’ll use”- Geocoding to resolve city names to coordinates
- Routing to plan the driving route
- PlazaQL to scan for bridge clearances, weight limits, and truck stops along the route corridor
Key code
Section titled “Key code”After getting a route, we build a bounding box around it with a 5km buffer on each side and run three PlazaQL scans against that corridor.
The low bridge scan queries everything with a maxheight tag:
query = f'$$ = search(maxheight: *).bbox({bbox[0]:.6f}, {bbox[1]:.6f}, {bbox[2]:.6f}, {bbox[3]:.6f});'fc = plaza.query(query)Then we parse the heights and keep only bridges lower than the truck. OSM’s maxheight tag is a mess — people tag it every way imaginable, so the parser handles metric, imperial, and edge cases:
# Handles: "4.5", "4.5 m", "14'6\"", "15'", "none", "default"_IMPERIAL_RE = re.compile(r"""(\d+)'(?:\s*(\d+)(?:"|''|in)?)?""")
def parse_height(value): m = _IMPERIAL_RE.match(value) if m: feet = int(m.group(1)) inches = int(m.group(2)) if m.group(2) else 0 return feet * 0.3048 + inches * 0.0254 # ... fallback to metricIf your parser chokes on 14'6" and skips it, you miss a low bridge. The imperial format is common in the US and UK.
Truck stops use a clean two-tag filter — fuel stations tagged as HGV-friendly:
query = f'$$ = search(amenity: "fuel", hgv: "yes").bbox({bbox[0]:.6f}, {bbox[1]:.6f}, {bbox[2]:.6f}, {bbox[3]:.6f});'We also pull amenity tags like shower=yes, restaurant=yes, and hgv:parking=yes to show what services each stop has.
How it works
Section titled “How it works”- Geocode both cities, then route between them.
- Build a bounding box around the route coordinates with a 5km buffer, giving a corridor roughly 10km wide. The buffer matters for curved routes — a tight box around a straight line misses hazards where the road bends.
- Three PlazaQL scans against the corridor:
maxheightfor low bridges,maxweightfor weight restrictions, andamenity=fuel + hgv=yesfor truck stops. - Parse and filter the results. Low bridges below the truck’s height get flagged with how much clearance is missing.
- Print a summary with hazard counts and worst-case clearance.
Full source
Section titled “Full source”The complete working app is at github.com/plazafyi/example-apps/truck-router. It’s a Python CLI with separate modules for the Plaza API client, corridor scanning, and height/weight parsing.
git clone https://github.com/plazafyi/example-appscd example-apps/truck-routeruv syncexport PLAZA_API_KEY=your-key-herepython main.py "Chicago, IL" "Detroit, MI" 4.1Variations to try
Section titled “Variations to try”Add height to the route request. If Plaza’s routing engine supports vehicle profiles in the future, you could pass vehicle_height directly and get a route that avoids low bridges automatically. For now, the scan-and-warn approach works.
Score the route. Assign a danger score based on how many hazards were found. 0 bridges = green, 1-2 = yellow, 3+ = red.
Export as GPX. Truckers use GPS units that import GPX files. Convert the route geometry to GPX format and the hazard points as waypoints. The driver loads it into their GPS and sees warnings as they approach each bridge.
Multi-stop trips. If the truck has multiple delivery stops, geocode each one, use the optimize endpoint to find the best visit order, then scan each leg independently.