Optimization
Case 01 / 10
Autonomous technician dispatch
Nightly route optimization that grew a vending-robot fleet 67% with no added field headcount and 31% less driving.
Crave Robotics · 2026 · Sole designer, builder, and operator
- Fleet grew 67%. Field headcount stayed at 4.
- Miles driven fell 31% in absolute terms.
- Daily route planning went from 2 hours to 10 minutes.
- Built the whole thing myself: solver, data pipeline, deployment.
The numbers
- 25+67%from 15Machines in fleet
- 132−32%from 194Technician hours per month
- 1,312−31%from 1,900Miles driven per month
- 5.3−59%from 12.9Hours per machine
- 52.5−59%from 126.7Miles per machine
- 4from 4Field technicians
- ~10 min−92%from ~2 hrsDaily planning time
- Google OR-Tools
- Node.js
- PostgreSQL
- Google Maps API
- GitHub Actions
- Slack API
Route the fleet yourself
Interactive — synthetic dataAdjust the controls below. The map, the numbers, and the explanation all update live.
What's happening: 14 machines are at or below 50% full — those must be visited. Because clustering is on, the solver also swings by 5 more that a technician is already driving past, rather than paying for a dedicated trip later. That combination is 40% shorter than visiting the same stops in list order.
- Depot
- Below threshold
- Added by clustering
- Not serviced
- Stops serviced
- 19
- Total distance
- 171.7 mi
- Miles per stop
- 9.0
- Against unoptimised
- −40%
14 triggered + 5 clustered
Unoptimised sequence: 286.3 mi
Turn clustering off and watch this rise
Same stops and split, sequenced by list order
- Technician 17 stops74.2 mi5.0 h
- Technician 27 stops51.8 mi4.1 h
- Technician 35 stops45.6 mi3.3 h
Production runs Google OR-Tools with live traffic travel times, time-window, and fairness constraints, none of which can execute in a browser. This demo uses a nearest-neighbour construction with 2-opt improvement over straight-line distance — the same class of heuristic, at a scale small enough to solve instantly on the client. Locations, fill levels, and the depot are synthetic.
How it fits together
- 1Machine telemetry
- 2Sell-through velocity
- 3Stockout projection
- 4Time-window & fairness constraints
- 5Live traffic travel times
- 6VRP solve
- 7Routes to Slack
- 8Human re-optimization
Read the full case study Hide the case study
The problem
Restocking and service routes for a growing fleet of automated frozen-food vending machines were planned by hand every day — around two hours of work, based on judgment and a spreadsheet. Plans went stale as soon as reality intervened. Technicians were re-routed mid-day, backtracked across the metro area, and never knew their next day’s work until that morning.
Why it mattered
Field labour and mileage are the dominant controllable cost in a physical fleet business. Every machine added multiplied a planning process that already did not scale, and the company was adding machines faster than it was adding technicians. The instability was also a retention problem — technicians were visibly frustrated by the churn.
What I built
A nightly optimizer that ingests live machine telemetry, computes per-machine per-product sell-through velocity, projects which machines will hit stockout thresholds, and solves a capacitated vehicle-routing problem across available technicians and shift constraints. Optimized routes post to the team’s chat channel the evening before, so technicians know their day in advance. A human-in-the-loop path re-solves in under 30 seconds when something changes.
Three constraints were added after the initial version shipped, once the gap between the model and the street became obvious: time windows for locations with restricted access hours, so a route no longer assumes a site is reachable whenever it’s convenient; live traffic travel times from the Google Maps API in place of straight-line estimates, since a mile in stop-and-go traffic and a mile on a freeway are not the same cost; and a fairness term so route quality doesn’t quietly concentrate on whichever technician’s territory happens to optimize best.
The decision that mattered most was choosing geographic clustering over strict threshold discipline. A machine at 51% does not trip a 50% restock flag, but if a technician is already in that cluster, servicing it now is cheaper than a dedicated return trip later. Letting the optimizer make that trade — rather than treating the threshold as a hard rule — is where most of the drive-time reduction came from. The demo below lets you turn that behaviour off and watch the total distance move.
Much of the iteration went into failure modes that only appear in production: keying velocity by machine serial number rather than location, because machines get relocated; PLC alert detection; product-ID casing normalization across data sources; top-sellers-out prioritization; and cron timing against telemetry refresh.
On attributing the numbers. Per-machine improvements are not attributable to routing alone. Growing from 15 to 25 machines increased geographic density, which reduces per-machine drive time independent of route quality, and the two months compared differ seasonally for campus-adjacent locations. The defensible claim is the joint one: the fleet grew 67% while absolute labour hours and mileage fell roughly 31% and headcount stayed flat. Optimization and density together made that possible.
Beyond the numbers, stockouts went to zero — remaining lost sales trace to hardware failures owned by a separate team. Routes became stable enough to publish the night before, and the fleet ran two weeks at three technicians instead of four without service degradation.
What I learned
The solver was the easy part. Most of the work was data hygiene and modelling the constraints technicians actually operate under — and the largest cost win came from relaxing a business rule rather than tuning the optimizer.
What I would do next
Automated back-testing of threshold changes against historical velocity, so a change to the clustering radius or restock threshold can be evaluated against real history before it ships, rather than judged after the fact.
Described without confidential information. The demo and any figures inside it use synthetic data.