本指南說明 loadDemands
和 loadLimits
,以及兩者之間的關係。
如「取貨和送貨時間範圍限制」一文所述,OptimizeToursRequest
訊息 (REST、gRPC) 包含多項屬性,可指定要最佳化問題的限制。多個 OptimizeToursRequest
屬性代表負載限制。
規劃路線時,必須考量車輛和貨物的實體特性。
- 車輛:
loadLimits
屬性會指定車輛可處理的最大負載。請參閱Vehicle
訊息的 (REST、gRPC) 說明文件。 - 出貨:
loadDemands
屬性會指定特定出貨量消耗的負載量。請參閱Shipment
訊息的 (REST、gRPC) 說明文件。
這兩項限制條件可讓最佳化工具適當將貨件指派給車輛,以最符合車隊容量和貨件需求的方式進行。
本文件其餘部分會詳細討論 loadLimits
和 loadDemands
。
負載需求和限制:類型
您會以型別表示每個負載需求和限制條件。
您可以提供自己的載入類型組合,例如:
- 重量
- 磁碟區
- 線性測量
- 運送的物品或設備名稱
本指南以 weightKg
做為範例類型。
Shipment.loadDemands
和 Vehicle.loadLimits
都使用 通訊協定緩衝區 map
類型,並以 string
鍵代表負載類型。
Shipment.loadDemands
值會使用 Load
訊息 (REST、gRPC)。Load
訊息具有單一 amount
屬性,代表完成指定類型出貨作業所需的容量。
值會使用 LoadLimit
訊息 (REST、gRPC)。Vehicle.loadLimits
LoadLimit
訊息有多個屬性,其中 maxLoad
代表指定類型車輛的最大載重能力。
只有在貨件和車輛的負載類型鍵相符時,貨件才會耗用指派車輛的loadLimits
loadDemands
loadLimits
。舉例來說,如果出貨內容為:loadDemands
"loadDemands": {
"weightKg": {
"amount": 50
}
}
需要 50 個裝載單位 (weightKg
類型) 才能完成運送。車輛:loadLimits
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
可能可以完成運送,因為車輛的 maxLoad
weightKg
類型大於或等於運送的 loadDemands
weightKg
類型。不過,如果車輛符合下列條件:loadLimits
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
由於沒有負載限制,因此隱含無限 weightKg
容量,因此車輛不受貨物重量需求的限制。weightKg
在貨運和車輛之間轉移貨物
由於貨件是由車輛收取和運送,貨件的loadDemand
會在貨件和車輛之間轉移。您可以在特定車輛的 OptimizeToursResponse
訊息 (REST、gRPC) routes.transitions
項目中查看車輛的負載。順序如下:
- 出貨的必要負載量定義為
loadDemand
。 - 指派車輛會取貨,且車輛的
vehicleLoads
會增加貨物loadDemand
。回應訊息中的 positivevisits.loadDemands
代表這項轉移。 - 車輛運送貨物後,車輛的
vehicleLoads
會減少,減少量等於運送貨物的loadDemand
。這項轉移作業在回應訊息中以負數visits.loadDemands
表示。
車輛的vehicleLoads
在路線上的任何一點都不得超過指定的loadLimits
。
完整範例,包含載入需求和限制
查看附有負載需求和限制的範例要求
{ "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 } } } ] } }
範例要求包含多個與載入相關的參數:
shipments[0]
的負載需求為 50weightKg
。shipments[1]
的負載需求為 10weightKg
。shipments[2]
的負載需求為 80weightKg
。vehicles[0]
的載入上限為 100 個weightKg
。
查看要求的回應,瞭解負載需求和限制
{ "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 } } }
新增的載入限制會影響 visits
的順序:
shipment[0]
已取貨shipment[1]
已取貨shipment[0]
已送達shipment[1]
已送達shipment[2]
已取貨shipment[2]
已送達
這項訂單顯示車輛無法同時完成三筆出貨,因為總 loadDemands
超過車輛的loadLimits
。
每個 visits
項目都包含因完成 Visit
而導致的車輛負重變化。正值代表裝載貨物,負值則代表卸載貨物。
每個 transitions
項目都包含 Transition
期間的車輛總負載。舉例來說,transitions[2]
的負載為 60,代表 shipment[0]
和 shipment[1]
的合併負載。weightKg
指標物件 routes[0].metrics
和 metrics.aggregatedRouteMetrics
包含 maxLoads
屬性。類型 weightKg
的值為 80,代表車輛將 shipments[2]
運送至交貨地點的路線部分。
軟性負載限制條件
如「取貨和送貨時間範圍限制」所述,載重限制條件也有硬性限制和軟性限制。LoadLimit
訊息的 maxLoad
屬性表示硬性限制:車輛的負載絕不可超過指定類型中的 maxLoad
值。屬性 softMaxLoad
和 costPerUnitAboveSoftMax
代表軟性限制,每超出 softMaxLoad
的單位都會產生 costPerUnitAboveSoftMax
費用。
軟性負載限制條件有多種用途,例如:
- 在成本效益允許的情況下,將貨物分配到超過必要最低數量的車輛
- 表達司機偏好在特定路線上輕鬆取貨和送貨的項目數量
- 裝載車輛時,不要超過實體容量上限,以減少磨損並降低維護成本
硬性與軟性負載限制條件可以搭配使用。舉例來說,硬性載重限制可能表示車輛可安全運送的貨物最大重量,或車輛一次可容納的最大物品數量;軟性載重限制則可能表示會超出駕駛人能力範圍的物品最大重量或數量,導致無法將所有物品裝入車輛。