Construimos un sistema de speed limits con OpenStreetMap. 10x más barato.

Cuando trabajas con flotas de vehículos, una de las funciones básicas que cualquier plataforma necesita es saber si un vehículo está excediendo el límite de velocidad. Parece simple. No lo es.

La solución del mercado es comprar acceso a una API comercial de mapas que te devuelve el speed limit de una coordenada GPS. El problema: cuando procesas miles de vehículos reportando posición cada 5 segundos, las llamadas a esa API se comen el margen completo del negocio.

Teníamos un problema real, un presupuesto de cero para APIs comerciales, y un deadline de dos semanas. Acá va cómo lo resolvimos.

El problema en detalle

Una plataforma de fleet management que operábamos procesaba telemetría de miles de vehículos en tiempo real. Cada vehículo enviaba su posición GPS cada 5 segundos. Para cada posición necesitábamos saber: ¿cuál es el límite de velocidad en esta calle? ¿El vehículo lo está excediendo?

La API comercial líder cobraba por consulta. Hicimos las cuentas: con nuestro volumen, el costo mensual era mayor que lo que ganábamos por cliente. No era un problema de negociación de precios. Era un modelo de negocio incompatible con el nuestro.

La decisión: build

La primera reacción del equipo fue buscar una API más barata. La segunda fue evaluar si podíamos cachear resultados. Ambas eran optimizaciones del enfoque equivocado. Lo que necesitábamos era eliminar la dependencia.

OpenStreetMap (OSM) tiene datos de speed limits. No son perfectos. La cobertura varía por país y por zona. Pero para nuestros mercados (Chile, México y Estados Unidos), la cobertura era razonablemente buena para las carreteras principales y autopistas donde los excesos de velocidad realmente importaban.

El plan: extraer los datos de speed limits de OSM, preprocesarlos, indexarlos, y servir consultas localmente. Sin API externa. Sin costo por consulta.

La implementación

Fase 1: Prueba de concepto rápida.

Antes de comprometer semanas de trabajo, armamos un prototipo en JavaScript para validar que el approach era viable. Tomamos un subset de datos de OSM, hicimos consultas básicas, y verificamos que la información de speed limits era suficiente para nuestros mercados. En un día teníamos la confianza de que valía la pena seguir.

Fase 2: Preprocesamiento e indexación.

Los datos de OSM vienen en formato PBF (Protocol Buffer Format). El archivo crudo de un país entero pesa gigabytes. Pero no necesitábamos todo. Solo los segmentos de vía con tags de maxspeed y los nodos que los componen.

Reorganizamos toda la data del PBF dentro de Redis, con la metadata comprimida a nivel de bits. Cada nodo y segmento almacenado con el mínimo de bytes necesarios: coordenadas, speed limit, tipo de vía. Preprocesado e indexado para que la consulta fuera lo más rápida posible.

Para el índice geoespacial usamos RocksDB como subíndice de puntos. Esto nos permitía hacer búsquedas por bounding box geográfica de forma extremadamente eficiente: dado un punto GPS, encontrar todos los nodos de vía candidatos en un radio determinado en microsegundos.

Fase 3: Lógica de decisión inteligente.

Acá es donde la solución dejó de ser un simple “encuentra el punto más cercano” y se volvió interesante.

Un vehículo que reporta una coordenada GPS puede estar cerca de varias calles simultáneamente. En una intersección, puede haber 4 o 5 segmentos de vía con speed limits distintos. Elegir el correcto no es trivial.

Implementamos procesamiento en la capa de aplicación con reglas de inferencia por razonamiento: ¿hacia dónde va el vehículo? ¿De dónde viene? ¿Qué puntos hacen más sentido en el contexto del trayecto? Si el auto viene por una autopista a 100 km/h, probablemente no está en la calle de servicio paralela con límite de 40.

Para tomar la decisión final del punto correcto, usamos un modelo de features y pesos. Las features incluían: distancia al segmento, ángulo entre el vector de movimiento del vehículo y la dirección del segmento, velocidad actual vs speed limit del candidato, tipo de vía, y continuidad con el segmento anterior. Cada feature tenía un peso calibrado que ajustamos empíricamente con datos reales de flotas.

No era machine learning en el sentido clásico. Era un modelo de scoring donde la combinación de factores producía la mejor decisión posible con la información disponible. Simple, rápido, y sorprendentemente preciso.

Fase 4: Fallbacks.

Para los casos donde OSM no tenía datos específicos, implementamos un sistema de fallback por jerarquía:

  1. Speed limit específico del segmento de vía
  2. Speed limit por defecto para el tipo de vía (autopista, ruta, calle urbana)
  3. Speed limit por defecto del país

No es perfecto. En una calle residencial sin datos en OSM, asumíamos el default urbano del país (60 km/h en Chile, 30 km/h en zonas escolares). Pero para el caso de uso principal (alertas de exceso en carreteras y rutas), la precisión era excelente.

Los resultados

  • Costo por consulta: Efectivamente cero. El servicio corría en la misma infraestructura que ya teníamos
  • Latencia: P99 de 2ms (vs 150-300ms de la API comercial)
  • Cobertura: ~85% de match directo con OSM, el resto cubierto por fallbacks razonables
  • Tiempo de construcción: 2 semanas, 2 ingenieros
  • Ahorro: El costo mensual de la API comercial hubiese sido equivalente al salario de un ingeniero senior. Cada mes.

El servicio sigue corriendo en producción sin cambios significativos ya por varios años.

Lo que aprendimos

1. Open source no es gratis, pero es barato. Los datos de OSM son gratuitos, pero extraerlos, procesarlos e indexarlos requiere trabajo de ingeniería real. La diferencia es que ese trabajo lo haces una vez. La API comercial te cobra cada vez.

2. La inteligencia no tiene que ser AI. El modelo de features y pesos que usamos para elegir el segmento correcto no era un modelo de deep learning. Era lógica de negocio bien pensada, calibrada con datos reales. A veces la solución más efectiva es un scoring model con reglas claras, no una red neuronal.

3. Las restricciones fuerzan creatividad. Si hubiéramos tenido presupuesto para la API, la habríamos comprado. Nunca habríamos construido algo que terminó siendo una ventaja competitiva del producto. En economía le llaman “innovación por restricción”: la escasez de recursos obliga a encontrar soluciones que la abundancia nunca habría motivado.

¿Cuándo build vs buy?

No siempre tiene sentido construir tu propia solución. La regla que usamos:

  • Buy cuando el costo de la solución externa es marginal respecto a tu ingreso
  • Buy cuando la solución requiere expertise que no tienes y no necesitas desarrollar
  • Build cuando la dependencia externa amenaza tu modelo de negocio
  • Build cuando el volumen hace que el costo por consulta sea insostenible
  • Build cuando puedes construir algo suficientemente bueno en un tiempo razonable

En nuestro caso, los tres criterios de “build” se cumplían. La decisión fue obvia en retrospectiva. Pero en el momento, decir “vamos a construir nuestro propio servicio de speed limits” sonaba como reinventar la rueda. A veces reinventar la rueda es exactamente lo correcto.