The Open Source Routing Machine or OSRM is a C++ implementation of a high-performance routing engine for shortest paths in road networks. Licensed under the permissive 2-clause BSD license, OSRM is a free network service hosting the following services: nearest, route, table, match, trip, tile.

We will see in this post how to deploy your own OSRM service in case you want to use it on your own data or just to not be limited by the number requests with responses like: {'message': 'Too Many Requests'}.

Sources:

OSRM features

  • Nearest service - Snaps a coordinate to the street network and returns the nearest n matches.
  • Route service - Finds the fastest route between coordinates in the supplied order.
  • Table service - Computes the duration of the fastest route between all pairs of supplied coordinates.
  • Match service - Map matching matches/snaps given GPS points to the road network in the most plausible way.
  • Trip service - The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm). The returned path does not have to be the fastest path, as TSP is NP-hard it is only an approximation.
  • Tile service - This service generates Mapbox Vector Tiles that can be viewed with a vector-tile capable slippy-map viewer.

You will need at least 2.5GB of RAM (in my case with 1GB OSRM build failed).

Upgrade all the packages

sudo apt-get update

Install dependencies

sudo apt-get install build-essential git cmake pkg-config \
libbz2-dev libxml2-dev libzip-dev libboost-all-dev \
lua5.2 liblua5.2-dev libtbb-dev

Create a dedicated directory and move into to keep everything tidy and clean

mkdir osrm
cd osrm

Get OSRM from the official GitHub repo

git clone https://github.com/Project-OSRM/osrm-backend.git

Compile and install OSRM binaries

cd osrm-backend
mkdir -p build
cd build
cmake ..
cmake --build .
sudo cmake --build . --target install

The map pre-processing is quite memory intensive. For this reason, OSRM uses a library called STXXL to map its internal operations on the hard disk. STXXL relies on a configuration file called .stxxl, which lives in the same directory where you are running your software, to determine how much space is dedicated to the STXXL data structures.

Configure STXXL with an .stxxl file in your osrm folder.

cd ~/osrm
vi .stxxl

Write in it

disk=/tmp/stxxl,10G,syscall

Save and close it.

Because the speed profile script might depend on some Lua functions defined in the profiles library, we also create a symbolic link to it in the same directory by running the following two commands.

ln -s osrm-backend/profiles/car.lua profile.lua
ln -s osrm-backend/profiles/lib

Get openstreetmap data

wget https://download.geofabrik.de/europe/france/ile-de-france-latest.osm.bz2
bzip2 -d ile-de-france-latest.osm.bz2

Pre-process the .osm file with the car profile

osrm-extract ile-de-france-latest.osm -p ./osrm-backend/profiles/car.lua

Build the contraction hierarchy

osrm-contract ile-de-france-latest.osrm

To keep the osrm-routed process running after ending ssh session, use tmux

tmux

Start a routing engine HTTP server on port 5000 inside the tmux session

osrm-routed ile-de-france-latest.osrm

Leave/detach the tmux session by typing Ctrl+b and then d

You have now a high performance routing engine up and running.

Get the estimated fastest route for a departure-destination pair of GPS points

Let’s take for example the following GPS points (departure’s longitude, departure’s latitude, departure’s longitude, departure’s latitude) :

2.25975,48.923557;2.262194,48.922554

To use the service with Python, you can do:

import json
import requests
from pprint import pprint

url = 'http://0.0.0.0:5000/route/v1/car/'
url += '2.25975,48.923557;2.262194,48.922554'

response = requests.get(url)
json_data = json.loads(response.text)

The service response should looks like:

pprint(json_data)
{
   "code":"Ok",
   "routes":[
      {
         "geometry":"gkriHmjxLpCkBBcILcBHB",
         "legs":[
            {
               "steps":[

               ],
               "distance":251.2,
               "duration":34,
               "summary":"",
               "weight":34
            }
         ],
         "distance":251.2,
         "duration":34,
         "weight_name":"routability",
         "weight":34
      }
   ],
   "waypoints":[
      {
         "hint":"rUAAgDMXC4AHAAAABQAAAAAAAAAmAAAAHvuhQA7XVUAAAAAAYpXVQQcAAAAFAAAAAAAAACYAAAA4BQAAInsiAKSD6gImeyIApYPqAgAArwmOS6TT",
         "distance":0.313522,
         "name":"Rue Victor Hugo",
         "location":[
            2.259746,
            48.923556
         ]
      },
      {
         "hint":"rBoNgK0aDYANAAAAAAAAAAAAAAAAAAAACWqrQAAAAAAAAAAAAAAAAA0AAAAAAAAAAAAAAAAAAAA4BQAAeYUiAESA6gKyhCIAun_qAgAADwyOS6TT",
         "distance":21.170758,
         "name":"",
         "location":[
            2.262393,
            48.922692
         ]
      }
   ]
}

To retrieve the geometry:

json_data["routes"][0]["geometry"]

For our example you will get:

gkriHmjxLpCkBBcILcBHB

You can check this geometry with the Google Interactive Polyline Encoder Utility. Copy/Paste the geometry into the Encoded Polyline field and click on Decode polyline. In my case, I get the folowing polyline:

If you feel the need to quickly visualize coordinates on a map you can use: https://mapmakerapp.com/