ITSkillsCenter
الأعمال الرقمية

تحسين جولات التوصيل بـ OSRM وVROOM: درس عملي 2026

4 دقائق للقراءة

📍 المقالة الرئيسية للمجموعة: Stack لوجستية 2026.

ساعي مع 15 توصيلاً = 15! = 1,307,674,368,000 ترتيبات ممكنة. اختيار الترتيب المثالي بشكل يدوي مستحيل. VRP (Vehicle Routing Problem) هو مشكلة كلاسيكية NP-hard. حلول مفتوحة المصدر: VROOM (VRP solver) + OSRM (محرك توجيه) = تخفيض المسافة 25-40% مقارنة بالاستخدام اليدوي. هذا الدرس يفصل التثبيت الكامل، تحضير خرائط OSM إفريقيا، تكوين matrix calculator، تكامل VROOM في API.

المتطلبات

VPS Hetzner CCX13 minimum (8 جيجابايت RAM لـ OSRM + خرائط بلد). Docker. خرائط OSM (تنزيل مجاني). المستوى المتوقع: متقدم. الوقت المقدر: 4-6 ساعات للإعداد + 1 ساعة لتحضير الخرائط لكل بلد.

الخطوة 1 — تنزيل خرائط OSM

Geofabrik يوفر خرائط OSM مُحدَّثة يومياً، مقسمة حسب البلد. للسنغال 100 ميغابايت، للمغرب 200 ميغابايت، لكوت ديفوار 250 ميغابايت. تنزيل:

mkdir -p /opt/osrm/data
cd /opt/osrm/data

# السنغال
wget https://download.geofabrik.de/africa/senegal-and-gambia-latest.osm.pbf

# المغرب
wget https://download.geofabrik.de/africa/morocco-latest.osm.pbf

# كوت ديفوار
wget https://download.geofabrik.de/africa/ivory-coast-latest.osm.pbf

الخطوة 2 — تحضير الخرائط لـ OSRM

OSRM يتطلب 3 خطوات تحضير: extract (استخراج)، partition (تقسيم)، customize (تخصيص). كل ذلك عبر Docker. تستغرق 15-30 دقيقة لـ بلد متوسط.

cd /opt/osrm/data

# 1. Extract
docker run --rm -v "${PWD}:/data" osrm/osrm-backend:latest \
  osrm-extract -p /opt/car.lua /data/senegal-and-gambia-latest.osm.pbf

# 2. Partition (لـ MLD = Multi-Level Dijkstra، الأسرع لطلبات routing متعددة)
docker run --rm -v "${PWD}:/data" osrm/osrm-backend:latest \
  osrm-partition /data/senegal-and-gambia-latest.osrm

# 3. Customize
docker run --rm -v "${PWD}:/data" osrm/osrm-backend:latest \
  osrm-customize /data/senegal-and-gambia-latest.osrm

الخطوة 3 — تشغيل OSRM Server

OSRM يستمع على المنفذ 5000. يدعم 4 endpoints: /route (مسار)، /table (matrix المسافات)، /match (map matching)، /trip (TSP solver).

docker run -d --name osrm \
  -p 5000:5000 \
  -v /opt/osrm/data:/data \
  --restart unless-stopped \
  osrm/osrm-backend:latest \
  osrm-routed --algorithm mld /data/senegal-and-gambia-latest.osrm

الخطوة 4 — اختبار OSRM

اختبار route بين Plateau Dakar و Almadies:

# Route
curl "http://localhost:5000/route/v1/driving/-17.4467,14.6928;-17.4946,14.7491?overview=full"
# Output: distance, duration, polyline

# Table (matrix لـ 5 نقاط)
curl "http://localhost:5000/table/v1/driving/-17.44,14.69;-17.46,14.70;-17.48,14.72;-17.49,14.74;-17.50,14.75"
# Output: matrix 5x5 من الأوقات

الخطوة 5 — تثبيت VROOM

VROOM هو VRP solver. يأخذ jobs (التوصيلات) و vehicles (السعاة) و matrix من OSRM، يعيد ترتيب optimal.

docker run -d --name vroom \
  -p 3000:3000 \
  -e VROOM_ROUTER=osrm \
  -e OSRM_URL=http://osrm:5000 \
  --link osrm \
  --restart unless-stopped \
  vroomvrp/vroom-docker:latest

الخطوة 6 — حل VRP أول

مثال: 1 ساعٍ، 5 توصيلات، تحسين الجولة. VROOM يقبل JSON بسيط:

curl -X POST http://localhost:3000 -H "Content-Type: application/json" -d '{
  "vehicles": [
    {
      "id": 1,
      "start": [-17.4467, 14.6928],
      "end": [-17.4467, 14.6928],
      "capacity": [10],
      "time_window": [28800, 64800]
    }
  ],
  "jobs": [
    {"id": 1, "location": [-17.4546, 14.7091], "service": 300, "amount": [1]},
    {"id": 2, "location": [-17.4720, 14.7212], "service": 300, "amount": [1]},
    {"id": 3, "location": [-17.4823, 14.7345], "service": 300, "amount": [1]},
    {"id": 4, "location": [-17.4654, 14.7478], "service": 300, "amount": [1]},
    {"id": 5, "location": [-17.4499, 14.7589], "service": 300, "amount": [1]}
  ]
}'

الإخراج: ترتيب التوصيلات (مثلاً 3 → 1 → 5 → 2 → 4)، المسافة الإجمالية، المدة، تكلفة. التحسين 25-40% مقابل الترتيب الإدخالي.

الخطوة 7 — قيود متقدمة

VROOM يدعم قيوداً واقعية: نوافذ زمنية، أولويات، مهارات السعاة، السعة الإجمالية.

{
  "vehicles": [
    {
      "id": 1,
      "skills": [1, 2],  // مؤهل لـ مبرّد و الأدوية
      "capacity": [25],   // 25 كغ كحد أقصى
      "time_window": [28800, 64800]  // 8h-18h
    }
  ],
  "jobs": [
    {
      "id": 1,
      "location": [...],
      "service": 600,
      "amount": [3],  // 3 كغ
      "skills": [1],  // يتطلب مبرّد
      "time_windows": [[36000, 39600]],  // التسليم 10h-11h
      "priority": 100  // أولوية عالية
    }
  ]
}

الخطوة 8 — تكامل في Stack TMS

Backend يستدعي VROOM كل صباح لتخطيط جولات اليوم.

// schedule-routes.ts
async function planDailyRoutes(date: string) {
  const couriers = await sql`SELECT * FROM couriers WHERE status = 'available'`;
  const deliveries = await sql`
    SELECT * FROM deliveries 
    WHERE scheduled_date = ${date} AND status = 'pending'
  `;
  
  const vroomInput = {
    vehicles: couriers.map((c, i) => ({
      id: i + 1,
      start: [c.start_lng, c.start_lat],
      end: [c.start_lng, c.start_lat],
      capacity: [c.max_capacity],
      time_window: [28800, 64800]  // 8h-18h
    })),
    jobs: deliveries.map((d, i) => ({
      id: i + 1,
      location: [d.dropoff_lng, d.dropoff_lat],
      service: 300,  // 5 دقائق لكل توصيل
      amount: [d.weight_kg]
    }))
  };
  
  const res = await fetch('http://localhost:3000', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(vroomInput)
  });
  const solution = await res.json();
  
  // حفظ التخصيص
  for (const route of solution.routes) {
    const courierId = couriers[route.vehicle - 1].id;
    for (const [i, step] of route.steps.entries()) {
      if (step.type === 'job') {
        const deliveryId = deliveries[step.job - 1].id;
        await sql`
          UPDATE deliveries 
          SET courier_id = ${courierId}, sequence = ${i}, eta = ${step.arrival}
          WHERE id = ${deliveryId}
        `;
      }
    }
  }
}

الخطوة 9 — تحديث ديناميكي

طلب جديد يصل في منتصف اليوم. لا يجب إعادة حساب كل شيء. VROOM يدعم incremental optimization: حافظ على الجولات الجارية، أدرج الطلب الجديد في أفضل موقع.

// إدراج job جديد في route نشط
const currentRoute = await sql`SELECT * FROM deliveries WHERE courier_id = ${courierId} AND status IN ('picked_up', 'in_transit')`;
const newJob = { id: 99, location: [lng, lat], service: 300 };

const reoptimizeInput = {
  vehicles: [{
    id: 1,
    start: courierCurrentLocation,  // الموقع الحالي
    capacity: [remaining_capacity]
  }],
  jobs: [...currentRoute, newJob]
};

const result = await fetch('http://localhost:3000', { method: 'POST', body: JSON.stringify(reoptimizeInput) });

الخطوة 10 — تصور الجولات

عرض كل جولة على Leaflet مع ألوان مختلفة. polyline من OSRM لكل جزء:

const courierColors = ['blue', 'red', 'green', 'orange', 'purple'];

solution.routes.forEach((route, i) => {
  const color = courierColors[i % courierColors.length];
  const stops = route.steps.filter(s => s.type === 'job');
  
  // OSRM polyline لكل جزء
  for (let j = 0; j < stops.length - 1; j++) {
    fetch(`http://osrm:5000/route/v1/driving/${stops[j].location[0]},${stops[j].location[1]};${stops[j+1].location[0]},${stops[j+1].location[1]}`)
      .then(r => r.json())
      .then(data => {
        const polyline = decodePolyline(data.routes[0].geometry);
        L.polyline(polyline, { color }).addTo(map);
      });
  }
});

الأخطاء الشائعة

الخطأ السبب الحل
OSRM extract OOM RAM < 4GB لخريطة بلد CCX13 لـ 8GB
VROOM يفشل بـ NoSolution قيود متناقضة تحقق time_windows + capacity
matrix لـ 100 نقاط بطيء OSRM يحسب 100×100 كاش في Redis
Polyline encoding OSRM يستخدم Polyline5 استخدم decodePolyline5
عنوان Geocoding خاطئ OSM لا يحتوي على عنوان دقيق Plus Codes أو manual entry
روابط Wave مكسورة VROOM لا يرى Webhook استدعِ Wave بعد VROOM

التكيف مع السياق

أربع توضيحات. الأزقة الإفريقية. OSM يحتوي على بعض الأزقة فقط. تحديثات community مع MapSwipe، KaartGroup. ساهم محلياً. الزحمة المرورية. OSRM لا يدير الزحمة في الوقت الحقيقي افتراضياً. تكامل HERE Traffic API أو Google Routes API لـ ETA حقيقي. الموتورسيكلات vs السيارات. profile «motorcycle» في OSRM يدير الأزقة الضيقة. لـ Yamaha 125، أسرع 30% من السيارة. وقود. أضف cost = distance × consumption × price. السنغال diesel 700 XOF/L، essence 850 XOF/L. تحسين يقلل الفاتورة 25%.

دروس الإخوة

الأسئلة المتكررة

OSRM vs Google Maps API؟ Google: 7 USD/1000 طلب route. OSRM ذاتي الاستضافة: 0 USD. لـ 10,000 طلب/يوم = 70 USD/يوم Google = 2,100 USD/شهر. OSRM = 4.51 يورو/شهر.

VROOM vs OR-Tools؟ VROOM REST API بسيط، production-ready. OR-Tools (Google) أكثر قوة لكنه مكتبة Python/C++.

معدل التحسين؟ 25-40% على المسافة. أكثر إذا الجولات اليدوية كانت سيئة جداً.

عدد jobs الأقصى؟ VROOM يحل 100-200 jobs في < 5 ثوان. ما بعد 500 jobs، vroom-cli + clustering مسبق.

للاستزادة

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité