I built a free route optimizer for Colombo. Now it needs real traffic data.
I spent the last few months building an open-source route optimizer for delivery riders in Colombo. It plans the best order of stops, predicts traffic by time of day and holidays, and costs nothing to run.
Go deeper1 min
The catch: it is a proof of concept. The road map is real, but the traffic it learned from is simulated. To become genuinely useful, it needs real traffic data from Sri Lankan roads. That is why I am sharing it now, unfinished, on GitHub.
Why it matters Routing is a daily cost for every courier, grocery app and distributor in Sri Lanka. The good tools charge per request, which adds up fast for a small local team. Colombo also has its own rhythm. Office rush hours, Poya days, long weekends and the Sinhala and Tamil New Year all change how the city moves. Global tools don't model those well.
The idea: combine free building blocks with a model that understands local patterns, and give it away. What I built
A dispatcher opens a web page, drops a depot and some delivery pins on the map, picks a date and a shift window, and clicks Optimize. A few seconds later they get the stop order, arrival times and the route on the map.
Under the hood, four free pieces do the work:
• The map: OpenStreetMap, with road speeds tuned for motorcycles on Sri Lankan roads.
• The router: OSRM works out how long it takes to get from any point to any other.
• The planner: VROOM decides the best order of stops within the shift.
• The traffic model: a small neural network that predicts speeds for a given hour and date, including Poya and Avurudu. The app also shows how much distance and time the plan saves compared to visiting stops in the order they were entered.
The bumpy parts Most of my time didn't go into the clever bits. It went into things breaking in ways I didn't expect.
- There is no open traffic data for Colombo. I looked for months. I tried learning from other cities instead: Beijing taxi GPS traces, California highway sensors and Porto taxis. Those cities taught me a lot about traffic models, but their data doesn't transfer neatly to a Colombo road network.
- My first model was predicting the wrong city. Its outputs were wired to Beijing road segments. I had to rebuild the graph from about 17,000 real Colombo road segments so predictions land on actual streets.
- The model quietly collapsed. A training bug meant it only ever saw midday. It learned one number and repeated it for every hour. Shuffling the training windows across the whole day fixed it.
- Local calendars are hard. Poya moves with the moon and Avurudu shifts by a day in leap years. I hard-coded one year's dates for the prototype. That works for a demo, not for production.
- Live traffic updates crashed the router. Each optimization rebuilt the road speeds and restarted the routing engine. Two requests close together could leave it reading half-written files.
- My savings number was too generous. The comparison route assumed 15 minutes per stop while the optimized one used 3. It inflated "time saved" by 12 minutes a stop until I lined them up. The lesson: a confident chart can hide a broken pipeline. I now check every number against a dumb baseline first. Where it honestly stands
The routing works today. Give it real pins in Colombo and it returns a sensible plan in under a second.
The traffic model is the part that isn't ready:
- The roads are real, the speeds are not. It was trained on one simulated year: a daily rush-hour curve, holiday effects, and random noise.
- A simple lookup still beats it. On that simulated data, "use the usual speed for this hour" is as accurate as the neural network. That is expected, because the model can only learn what the data contains.
- It is heavy for what it does. One traffic update takes over a minute and around 6 GB of memory on a laptop.
Bottom line: The plumbing is in place. What's missing is real data to make the model earn its place.
What's next, and where you come in
The next step is simple to say: train on real, time-stamped GPS traces from Colombo roads, and keep updating as new data arrives.
What would help most:
- Fleet and courier operators: Anonymized GPS pings (location, time, speed) from riders or vans. Even a few weeks of data from a handful of vehicles is a real start.
- Ride-hailing, bus, or tuk-tuk data: Any historical or live speed feed for the city.
- Engineers and students: Better map matching, a proper Poya and holiday calendar, and an honest evaluation against simple baselines.
- Dispatchers: Tell me what a routing tool must do on a real shift.
My promise: It stays free and open source, and any shared data is handled with privacy first.
If any of that is you, open an issue on GitHub or message me directly.
Go deeperThe full details behind this post, with sources.
Inside: Go deeper · The model · The routing · Known gaps worth fixing
OpenClose
The full details behind this post, with sources.
Inside: Go deeper · The model · The routing · Known gaps worth fixing
Go deeper

For engineers who want the details before they clone it.
The API asks the traffic model for the planning hour and date, the model writes predicted speeds into OSRM, and VROOM plans the stop order on top.
The model
- ST-GAT: Two graph attention layers (4 heads, hidden size 16) feed a 2-layer GRU and a small output layer. About 5,100 parameters, built in PyTorch Geometric.
- Graph: 13,499 intersections and 17,236 directed road segments, taken from OSRM routes across Colombo.
- Inputs: The last 12 hours of speed per intersection, plus five calendar flags: weekend, long weekend, Poya day, and the days before and after Avurudu.
- Output: Next-hour speed per intersection, written to OSRM as a segment speed file.
The routing
- OSRM: Runs the MLD algorithm on the Sri Lanka OpenStreetMap extract, with a motorcycle profile (primary roads 40 km/h, residential 20 km/h).
- VROOM: Solves the stop order with a 3-minute service time per drop and the user's shift window as the time limit.
- The FastAPI backend: Stores orders in PostGIS and exposes a health endpoint the UI uses to show which services are up.
Known gaps worth fixing
- The map matcher computes speed from OSRM's own estimated travel time, not the GPS timestamps. Real data needs the timestamps.
- Every traffic update rebuilds a full year of synthetic data in memory. Real data would replace this with a rolling window.
- Holiday dates are fixed for one year and need a proper lunar calendar.
- Traffic updates restart OSRM, so concurrent requests need a queue or a lock.
Run it yourself: Docker Compose for the database, OSRM, VROOM and the API, plus a Python environment for the model. Setup steps are in the README.
