Ladeanforderungen und -limits

In diesem Leitfaden werden loadDemands und loadLimits beschrieben und ihre Beziehung zueinander erläutert.

Wie bereits unter Einschränkungen für Zeitfenster für Abhol- und Lieferzeit erwähnt, enthält die OptimizeToursRequest-Nachricht (REST, gRPC) eine Reihe von Eigenschaften, die Einschränkungen für das zu optimierende Problem angeben. Mehrere OptimizeToursRequest-Properties stehen für Ladeeinschränkungen.

Fahrzeuge und Sendungen haben physikalische Eigenschaften, die bei der Routenplanung berücksichtigt werden müssen.

  • Fahrzeuge: Mit der Property loadLimits wird die maximale Ladung angegeben, die das Fahrzeug aufnehmen kann. Weitere Informationen finden Sie in der Dokumentation zur Vehicle-Nachricht (REST, gRPC).
  • Sendungen: Mit der Property loadDemands wird angegeben, wie viel Last eine bestimmte Sendung beansprucht. Weitere Informationen finden Sie in der Dokumentation zur Shipment-Nachricht (REST, gRPC).

Zusammen ermöglichen diese beiden Einschränkungen dem Optimierer, Sendungen Fahrzeugen so zuzuweisen, dass sie am besten zu Ihrer Flottenkapazität und den Versandanforderungen passen.

Im weiteren Verlauf dieses Dokuments werden loadLimits und loadDemands ausführlich behandelt.

Lastanforderungen und -limits: Typen

Sie geben jede Lastanforderung und Grenzbeschränkung in Form eines Typs an.

Sie können eigene Ladetypen angeben, z. B.:

  • Gewicht
  • Volume
  • lineare Messungen
  • Namen der transportierten Gegenstände oder Ausrüstung

In diesem Leitfaden wird weightKg als Beispieltyp verwendet.

Sowohl Shipment.loadDemands als auch Vehicle.loadLimits verwenden den map-Typ von Protocol Buffers mit string-Schlüsseln, die die Arten der Auslastung darstellen.

Für Shipment.loadDemands-Werte wird die Load-Nachricht verwendet (REST, gRPC). Die Load-Nachricht enthält eine einzelne amount-Eigenschaft, die angibt, wie viel Kapazität für die Durchführung der Sendung vom angegebenen Typ erforderlich ist.

Für Vehicle.loadLimits-Werte wird die LoadLimit-Nachricht verwendet (REST, gRPC). Die LoadLimit-Nachricht hat mehrere Eigenschaften. maxLoad steht für die maximale Nutzlast des Fahrzeugs des angegebenen Typs.

Die loadDemands einer Sendung beansprucht die loadLimits des zugewiesenen Fahrzeugs nur, wenn die beiden übereinstimmende Schlüssel für den Ladetyp haben. Beispiel: Eine Sendung mit loadDemands von:

"loadDemands": {
  "weightKg": {
    "amount": 50
  }
}

Für die Fertigstellung der Sendung sind 50 Ladungseinheiten vom Typ weightKg erforderlich. Ein Fahrzeug mit loadLimits von:

"loadLimits": {
  "weightKg": {
    "maxLoad": 100
  }
}

Die Sendung kann möglicherweise abgeschlossen werden, da die maxLoad des Fahrzeugs vom Typ weightKg größer oder gleich der loadDemands der Sendung vom Typ weightKg ist. Bei einem Fahrzeug mit loadLimits gilt Folgendes:

"loadLimits": {
  "equipmentRackStorage": {
    "maxLoad": 10
  }
}

hat aufgrund des Fehlens eines weightKg-Nutzlastlimits implizit eine unbegrenzte weightKg-Kapazität. Das Fahrzeug ist also nicht durch das Gewicht der Sendung eingeschränkt.

Ladungsumschlag zwischen Sendungen und Fahrzeugen

Wenn Sendungen von Fahrzeugen abgeholt und zugestellt werden, wird die loadDemand der Sendung zwischen der Sendung und dem Fahrzeug übertragen. Die Ladung des Fahrzeugs finden Sie im routes.transitions-Eintrag der OptimizeToursResponse-Nachricht (REST, gRPC) für ein bestimmtes Fahrzeug. Die Abfolge sieht so aus:

  1. Die erforderliche Ladekapazität wird für den Versand als loadDemand definiert.
  2. Die Sendung wird vom zugewiesenen Fahrzeug abgeholt und die vehicleLoads des Fahrzeugs erhöht sich um den Wert der loadDemand der Sendung. Diese Übertragung wird in der Antwortnachricht durch positive visits.loadDemands dargestellt.
  3. Das Fahrzeug liefert die Sendung aus und die vehicleLoads des Fahrzeugs verringert sich um den Wert der loadDemand der gelieferten Sendung. Diese Übertragung wird in der Antwortnachricht durch ein negatives visits.loadDemands dargestellt.

Die vehicleLoads eines Fahrzeugs darf an keinem Punkt seiner Route die angegebene loadLimits überschreiten.

Vollständiges Beispiel mit Lastanforderungen und -limits

Beispielanfrage mit Lastanforderungen und ‑limits

{
  "populatePolylines": false,
  "populateTransitionPolylines": false,
  "model": {
    "globalStartTime": "2023-01-13T16:00:00Z",
    "globalEndTime": "2023-01-14T16:00:00Z",
    "shipments": [
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.789456,
              "longitude": -122.390192
            },
            "duration": "250s"
          }
        ],
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 37.794465,
              "longitude": -122.394839
            },
            "duration": "150s"
          }
        ],
        "penaltyCost": 100.0,
        "loadDemands": {
          "weightKg": {
            "amount": 50
          }
        }
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.789116,
              "longitude": -122.395080
            },
            "duration": "250s"
          }
        ],
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 37.794465,
              "longitude": -122.394839
            },
            "duration": "150s"
          }
        ],
        "penaltyCost": 15.0,
        "loadDemands": {
          "weightKg": {
            "amount": 10
          }
        }
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.795242,
              "longitude": -122.399347
            },
            "duration": "250s"
          }
        ],
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 37.794465,
              "longitude": -122.394839
            },
            "duration": "150s"
          }
        ],
        "penaltyCost": 50.0,
        "loadDemands": {
          "weightKg": {
            "amount": 80
          }
        }
      }
    ],
    "vehicles": [
      {
        "endLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "startLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "costPerHour": 40.0,
        "costPerKilometer": 10.0,
        "loadLimits": {
          "weightKg": {
            "maxLoad": 100
          }
        }
      }
    ]
  }
}
    

Die Beispielanfrage enthält mehrere leistungsbezogene Parameter:

  • shipments[0] hat eine Lastanforderung von 50 weightKg.
  • shipments[1] hat eine Lastanforderung von 10 weightKg.
  • shipments[2] hat eine Lastanforderung von 80 weightKg.
  • vehicles[0] hat ein Ladelimit von 100 weightKg.

Antwort auf die Anfrage mit Lastanforderungen und ‑limits ansehen

{
  "routes": [
    {
      "vehicleStartTime": "2023-01-13T16:00:00Z",
      "vehicleEndTime": "2023-01-13T16:43:27Z",
      "visits": [
        {
          "isPickup": true,
          "startTime": "2023-01-13T16:00:00Z",
          "detour": "0s",
          "loadDemands": {
            "weightKg": {
              "amount": "50"
            }
          }
        },
        {
          "shipmentIndex": 1,
          "isPickup": true,
          "startTime": "2023-01-13T16:02:30Z",
          "detour": "150s",
          "loadDemands": {
            "weightKg": {
              "amount": "10"
            }
          }
        },
        {
          "startTime": "2023-01-13T16:08:55Z",
          "detour": "150s",
          "loadDemands": {
            "weightKg": {
              "amount": "-50"
            }
          }
        },
        {
          "shipmentIndex": 1,
          "startTime": "2023-01-13T16:16:37Z",
          "detour": "343s",
          "loadDemands": {
            "weightKg": {
              "amount": "-10"
            }
          }
        },
        {
          "shipmentIndex": 2,
          "isPickup": true,
          "startTime": "2023-01-13T16:27:07Z",
          "detour": "1627s",
          "loadDemands": {
            "weightKg": {
              "amount": "80"
            }
          }
        },
        {
          "shipmentIndex": 2,
          "startTime": "2023-01-13T16:36:26Z",
          "detour": "0s",
          "loadDemands": {
            "weightKg": {
              "amount": "-80"
            }
          }
        }
      ],
      "transitions": [
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-13T16:00:00Z",
          "vehicleLoads": {
            "weightKg": {}
          }
        },
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-13T16:02:30Z",
          "vehicleLoads": {
            "weightKg": {
              "amount": "50"
            }
          }
        },
        {
          "travelDuration": "235s",
          "travelDistanceMeters": 795,
          "waitDuration": "0s",
          "totalDuration": "235s",
          "startTime": "2023-01-13T16:05:00Z",
          "vehicleLoads": {
            "weightKg": {
              "amount": "60"
            }
          }
        },
        {
          "travelDuration": "212s",
          "travelDistanceMeters": 791,
          "waitDuration": "0s",
          "totalDuration": "212s",
          "startTime": "2023-01-13T16:13:05Z",
          "vehicleLoads": {
            "weightKg": {
              "amount": "10"
            }
          }
        },
        {
          "travelDuration": "380s",
          "travelDistanceMeters": 1190,
          "waitDuration": "0s",
          "totalDuration": "380s",
          "startTime": "2023-01-13T16:20:47Z",
          "vehicleLoads": {
            "weightKg": {}
          }
        },
        {
          "travelDuration": "409s",
          "travelDistanceMeters": 1371,
          "waitDuration": "0s",
          "totalDuration": "409s",
          "startTime": "2023-01-13T16:29:37Z",
          "vehicleLoads": {
            "weightKg": {
              "amount": "80"
            }
          }
        },
        {
          "travelDuration": "171s",
          "travelDistanceMeters": 665,
          "waitDuration": "0s",
          "totalDuration": "171s",
          "startTime": "2023-01-13T16:40:36Z",
          "vehicleLoads": {
            "weightKg": {}
          }
        }
      ],
      "metrics": {
        "performedShipmentCount": 3,
        "travelDuration": "1407s",
        "waitDuration": "0s",
        "delayDuration": "0s",
        "breakDuration": "0s",
        "visitDuration": "1200s",
        "totalDuration": "2607s",
        "travelDistanceMeters": 4812,
        "maxLoads": {
          "weightKg": {
            "amount": "80"
          }
        }
      },
      "routeCosts": {
        "model.vehicles.cost_per_kilometer": 48.12,
        "model.vehicles.cost_per_hour": 28.966666666666665
      },
      "routeTotalCost": 77.086666666666659
    }
  ],
  "metrics": {
    "aggregatedRouteMetrics": {
      "performedShipmentCount": 3,
      "travelDuration": "1407s",
      "waitDuration": "0s",
      "delayDuration": "0s",
      "breakDuration": "0s",
      "visitDuration": "1200s",
      "totalDuration": "2607s",
      "travelDistanceMeters": 4812,
      "maxLoads": {
        "weightKg": {
          "amount": "80"
        }
      }
    },
    "usedVehicleCount": 1,
    "earliestVehicleStartTime": "2023-01-13T16:00:00Z",
    "latestVehicleEndTime": "2023-01-13T16:43:27Z",
    "totalCost": 77.086666666666659,
    "costs": {
      "model.vehicles.cost_per_hour": 28.966666666666665,
      "model.vehicles.cost_per_kilometer": 48.12
    }
  }
}
    

Die zusätzlichen Ladeeinschränkungen wirken sich auf die Reihenfolge von visits aus:

  1. shipment[0] wird abgeholt
  2. shipment[1] wird abgeholt
  3. shipment[0] wird ausgeliefert
  4. shipment[1] wird ausgeliefert
  5. shipment[2] wird abgeholt
  6. shipment[2] wird ausgeliefert

Dieser Auftrag zeigt, dass drei Sendungen nicht gleichzeitig mit dem Fahrzeug ausgeführt werden können, da ihre Gesamt-loadDemands die loadLimits des Fahrzeugs übersteigt.

Jeder visits-Eintrag enthält die Änderung der Fahrzeuglast, die durch die Ausführung der Visit verursacht wurde. Positive Ladevorgänge stehen für das Beladen der Sendung, negative für das Entladen.

Jeder transitions-Eintrag enthält die Gesamtlast des Fahrzeugs während des Transition. transitions[2] hat beispielsweise eine weightKg-Auslastung von 60, was der kombinierten Auslastung von shipment[0] und shipment[1] entspricht.

Die Messwertobjekte routes[0].metrics und metrics.aggregatedRouteMetrics enthalten die Eigenschaft maxLoads. Der Wert für den Typ weightKg ist 80. Er entspricht dem Teil der Route des Fahrzeugs, auf dem shipments[2] zum Lieferort transportiert wurde.

Einschränkungen für weiche Ladelimits

Wie bei den Zeitfenstern, die im Abschnitt Einschränkungen für Zeitfenster für Abhol- und Liefertermine beschrieben sind, gibt es auch für Ladelimits harte und weiche Varianten. Die Eigenschaft maxLoad der LoadLimit-Nachricht ist eine strenge Einschränkung: Das Fahrzeug darf niemals eine Ladung befördern, die den maxLoad-Wert im angegebenen Typ überschreitet. Die Eigenschaften softMaxLoad und costPerUnitAboveSoftMax drücken eine weiche Einschränkung aus. Für jede Einheit, die softMaxLoad überschreitet, fallen Kosten in Höhe von costPerUnitAboveSoftMax an.

Weiche Grenzwerte für die Auslastung haben mehrere Verwendungsmöglichkeiten, z. B.:

  • die Verteilung von Sendungen auf mehr Fahrzeuge als die erforderliche Mindestanzahl, wenn dies kostengünstig ist
  • die Fahrer ihre Präferenz für die Anzahl der Artikel angeben können, die sie auf einer bestimmten Route bequem abholen und zustellen können
  • Fahrzeuge unter ihrer maximalen physischen Kapazität beladen, um Verschleiß zu begrenzen und Wartungskosten zu senken

Hard- und Softlimits für die Auslastung können zusammen verwendet werden. Ein strenges Ladelimit kann beispielsweise das maximale Gewicht der Ladung sein, das ein Fahrzeug sicher tragen kann, oder die maximale Anzahl von Artikeln, die gleichzeitig in ein Fahrzeug passen. Ein weiches Ladelimit kann das maximale Gewicht oder die maximale Anzahl von Artikeln sein, die es dem Fahrer erschweren, alles in das Fahrzeug zu bringen.