本指南將說明 loadDemands
和 loadLimits
,以及它們之間的關係。
如「取貨和送達時間限制」一文所述,OptimizeToursRequest
訊息 (REST、gRPC) 包含多個屬性,可針對要最佳化的問題指定限制。幾個 OptimizeToursRequest
屬性代表載入限制。
車輛和貨物都有物理屬性,因此在規劃路線時必須考量這些屬性。
- 車輛:
loadLimits
屬性會明確指出車輛可處理的最大負載量。請參閱Vehicle
訊息 (REST、gRPC) 的說明文件。 - Shipments:
loadDemands
屬性會指定指定出貨項目會消耗多少負載。請參閱Shipment
訊息 (REST、gRPC) 的說明文件。
這兩項限制條件結合後,最佳化器就能根據車隊容量和運送需求,適當地將貨物指派給車輛。
本文件的其餘部分會詳細說明 loadLimits
和 loadDemands
。
負載需求和限制:類型
您可以使用類型來表示每個負載需求和限制。
您可以提供自己的一組載入類型,如下列範例所示:
- 重量
- 磁碟區
- 線性測量
- 運送的物品或設備名稱
本指南使用 weightKg
做為示例類型。
Shipment.loadDemands
和 Vehicle.loadLimits
都使用 Protocol Buffers map
類型,其中 string
鍵代表負載類型。
Shipment.loadDemands
值會使用 Load
訊息 (REST、gRPC)。Load
訊息含有單一 amount
屬性,代表在指定類型中完成出貨所需的容量。
Vehicle.loadLimits
值會使用 LoadLimit
訊息 (REST、gRPC)。LoadLimit
訊息包含多個屬性,其中 maxLoad
代表指定類型中車輛的最大載重量。
只有在兩者具有相符的負載類型鍵時,運送作業的 loadDemands
才會使用其指派的車輛 loadLimits
。例如,出貨項目的 loadDemands
為:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
需要 weightKg
類型的 50 個負載單位,才能完成出貨作業。車輛的 loadLimits
為:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
可以完成運送,因為 weightKg
類型中的車輛 maxLoad
大於或等於運送 weightKg
類型中的 loadDemands
。不過,如果車輛的 loadLimits
為:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
由於沒有 weightKg
負載限制,因此車輛會隱含地擁有無限 weightKg
容量,因此不會受到貨物重量需求的限制。
移轉貨運和車輛之間的負載
當車輛取貨及送貨時,貨物會在貨物和車輛之間傳輸 loadDemand
。您可以在特定車輛的 OptimizeToursResponse
訊息 (REST、gRPC) routes.transitions
項目中查看車輛的負載。順序如下:
- 運送作業所需的負載容量會定義為
loadDemand
。 - 系統會指派車輛來取貨,並將貨物的
loadDemand
數量加進車輛的vehicleLoads
。這項轉移作業會在回應訊息中以 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]
的載入上限為 100weightKg
。
查看對要求的回應,其中包含負載需求和限制
{ "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]
的 weightKg
負載為 60,代表 shipment[0]
和 shipment[1]
的總負載。
指標物件 routes[0].metrics
和 metrics.aggregatedRouteMetrics
包含 maxLoads
屬性。類型 weightKg
的值為 80,代表車輛路線中將 shipments[2]
運送至送達地點的部分。
軟性負載限制
如同「上車和下車時間窗口限制」一節所述,載客限制有硬式和軟式變化版本。LoadLimit
訊息的 maxLoad
屬性會表達硬性限制:車輛不得載運超過指定類型 maxLoad
值的負載。屬性 softMaxLoad
和 costPerUnitAboveSoftMax
表示軟限制,每個超過 softMaxLoad
的單位都會產生 costPerUnitAboveSoftMax
費用。
軟負載限制有以下幾種用途:
- 在成本效益可接受的情況下,將貨物分配給比必要數量更多的車輛
- 表達駕駛員在特定路線上可輕鬆接送的物品數量偏好設定
- 將車輛載重量控制在其物理最大容量以下,以減少磨損並降低維護成本
您可以同時使用硬性和軟性負載限制限制。舉例來說,硬負載限制可能會表示車輛可安全載運的最大貨物重量,或一次可放入車輛的最大物品數量,而軟負載限制則可能是駕駛員可將所有物品放入車輛的最大重量或數量。