Routing Tutorial – Part 1: Introduction to Routing
Intro
In this tutorial I'll show you how to set up a local instance of Open Source Routing Machine (OSRM) server using Docker.
If you don't know what Docker is or how to install it, please refer to the documentation.
Setting up OSRM in Ubuntu using Docker
Using Bash, navigate to a directory where you have permissions to read and write.
# create a directory for the data, sudo su for superuser credentials
mkdir -p data/osrm/malta
cd /data/osrm/malta
# download the OSM data for Malta
wget https://download.geofabrik.de/europe/malta-latest.osm.pbf
# run the osrm-extract command to extract the data from the PBF file
docker run -t -v $(pwd):/data osrm/osrm-backend osrm-extract -p /opt/car.lua /data/malta-latest.osm.pbf
# run the osrm-partition command to partition the graph for faster routing
docker run -t -v $(pwd):/data osrm/osrm-backend osrm-partition /data/malta-latest.osrm
# run the osrm-customize command
docker run -t -v $(pwd):/data osrm/osrm-backend osrm-customize /data/malta-latest.osrm
# run the container
docker run -t -i -p 5000:5000 -v $(pwd):/data osrm/osrm-backend osrm-routed --algorithm mld /data/malta-latest.osrm
Setting up OSRM in Windows
Please be sure that Docker is installed. Installing Docker in Windows systems may not be so straight-forward as installing it in Linux-based environments. In Windows, you'll also need to be running Docker Desktop.
Using PowerShell, navigate to a directory where you have permissions to read and write.
We'll be using Open Street Map data for the country of Malta, provided by Geofabrik as a PBF file. Download the file and place it in the directory you're working in.
md -Force C:\Users\guillermo\Documents\data\osrm\malta
cd C:\Users\guillermo\Documents\data\osrm\malta
curl.exe -O https://download.geofabrik.de/europe/malta-latest.osm.pbf
Now, we'll run the osrm-extract
and several other commands to extract the data from the PBF file, generate the data for OSRM and partition it for faster routing. The graph will be generated using the car routing profile, there are other profiles available, but we'll stick with the default for now.
# osrm-extract
docker run -t -v "$(pwd):/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/malta-latest.osm.pbf
# osrm-partition
docker run -t -v "$(pwd):/data" osrm/osrm-backend osrm-partition /data/malta-latest.osrm
# osrm-customize
docker run -t -v "$(pwd):/data" osrm/osrm-backend osrm-customize /data/malta-latest.osrm
We're now ready to run the docker run
command to start the OSRM server. We'll use the -p
flag to expose port 5000 on the host machine, and the -v
flag to mount the current directory as /data
inside the container.
# run the container
docker run -t -i -p 5000:5000 -v "$(pwd):/data" osrm/osrm-backend osrm-routed --algorithm mld /data/malta-latest.osrm
Since the exposed port is the 5000, you can check if the service is up by visiting this URL in your browser: [http://127.0.0.1:5000/]Duck Duck Go.
You should see this message:
{"message":"URL string malformed close to position 1: \"\/\"","code":"InvalidUrl"}
A proper query for testing would be something like this: http://127.0.0.1:5000/route/v1/driving/14.5035,35.8976;14.5144,35.8989?overview=full&geometries=geojson
The response is a JSON dictionary, that contains the calculated fastest route between the two input pair of coordinates, among other things.
You can also send a request to the server using curl
:
curl "http://127.0.0.1:5000/route/v1/driving/14.5035,35.8976;14.5144,35.8989?overview=full&geometries=geojson"
You can visualize this in QGIS, using the following pyQGIS code, executed for the Python console:
from qgis.core import (
QgsProject,
QgsVectorLayer,
QgsFeature,
QgsGeometry,
QgsPointXY
)
import json
import urllib.request
URL = "http://127.0.0.1:5000/route/v1/driving/14.5035,35.8976;14.5144,35.8989?overview=full&geometries=geojson"
def load_route_from_osrm(url):
"""Fetch route from OSRM server and create a QGIS line layer"""
try:
with urllib.request.urlopen(url) as response:
data = json.loads(response.read().decode('utf-8'))
if data.get('code') != 'Ok' or not data.get('routes'):
print("Error: No valid route found in response")
return None
# Extract coordinates from the first route
coordinates = data['routes'][0]['geometry']['coordinates']
# Create memory layer
layer = QgsVectorLayer("LineString?crs=EPSG:4326", "OSRM Route", "memory")
provider = layer.dataProvider()
# Create and add feature
feature = QgsFeature()
points = [QgsPointXY(lon, lat) for lon, lat in coordinates]
feature.setGeometry(QgsGeometry.fromPolylineXY(points))
provider.addFeature(feature)
# Add to project and zoom
QgsProject.instance().addMapLayer(layer)
iface.mapCanvas().setExtent(layer.extent())
iface.mapCanvas().refresh()
print(f"Route loaded with {len(points)} points")
return layer
except Exception as e:
print(f"Error: {str(e)}")
return None
# Run the function
load_route_from_osrm(URL)
Example result:
Conclusion
Now you have you own instance of OSRM! In the follow-up, will work on how to send queries and get responses using Python.