負載需求和限制

本指南將說明 loadDemandsloadLimits,以及它們之間的關係。

如「取貨和送達時間限制」一文所述,OptimizeToursRequest 訊息 (RESTgRPC) 包含多個屬性,可針對要最佳化的問題指定限制。幾個 OptimizeToursRequest 屬性代表載入限制

車輛和貨物都有物理屬性,因此在規劃路線時必須考量這些屬性。

  • 車輛loadLimits 屬性會明確指出車輛可處理的最大負載量。請參閱 Vehicle 訊息 (RESTgRPC) 的說明文件。
  • ShipmentsloadDemands 屬性會指定指定出貨項目會消耗多少負載。請參閱 Shipment 訊息 (RESTgRPC) 的說明文件。

這兩項限制條件結合後,最佳化器就能根據車隊容量和運送需求,適當地將貨物指派給車輛。

本文件的其餘部分會詳細說明 loadLimitsloadDemands

負載需求和限制:類型

您可以使用類型來表示每個負載需求和限制。

您可以提供自己的一組載入類型,如下列範例所示:

  • 重量
  • 磁碟區
  • 線性測量
  • 運送的物品或設備名稱

本指南使用 weightKg 做為示例類型。

Shipment.loadDemandsVehicle.loadLimits 都使用 Protocol Buffers map 類型,其中 string 鍵代表負載類型。

Shipment.loadDemands 值會使用 Load 訊息 (RESTgRPC)。Load 訊息含有單一 amount 屬性,代表在指定類型中完成出貨所需的容量。

Vehicle.loadLimits 值會使用 LoadLimit 訊息 (RESTgRPC)。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 訊息 (RESTgRPC) routes.transitions 項目中查看車輛的負載。順序如下:

  1. 運送作業所需的負載容量會定義為 loadDemand
  2. 系統會指派車輛來取貨,並將貨物的 loadDemand 數量加進車輛的 vehicleLoads。這項轉移作業會在回應訊息中以 positive visits.loadDemands 表示。
  3. 車輛交付貨物,車輛的 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] 的負載需求為 50 weightKg
  • shipments[1] 的負載需求為 10 weightKg
  • shipments[2] 的負載需求為 80 weightKg
  • 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 的順序:

  1. 已接收 shipment[0]
  2. 已接收 shipment[1]
  3. 已送達 shipment[0]
  4. 已送達 shipment[1]
  5. shipment[2]已抵達
  6. shipment[2] 已送達

這份訂單反映出三個貨件無法同時由車輛完成運送,因為其總 loadDemands 超過車輛的 loadLimits

每個 visits 項目都包含從 Visit 完成產生的車輛負載變化。正載量值代表貨物裝載,負載量值則代表貨物卸載。

每個 transitions 項目都包含 Transition 期間的總車輛負載量。舉例來說,transitions[2]weightKg 負載為 60,代表 shipment[0]shipment[1] 的總負載。

指標物件 routes[0].metricsmetrics.aggregatedRouteMetrics 包含 maxLoads 屬性。類型 weightKg 的值為 80,代表車輛路線中將 shipments[2] 運送至送達地點的部分。

軟性負載限制

如同「上車和下車時間窗口限制」一節所述,載客限制有硬式和軟式變化版本。LoadLimit 訊息的 maxLoad 屬性會表達硬性限制:車輛不得載運超過指定類型 maxLoad 值的負載。屬性 softMaxLoadcostPerUnitAboveSoftMax 表示軟限制,每個超過 softMaxLoad 的單位都會產生 costPerUnitAboveSoftMax 費用。

軟負載限制有以下幾種用途:

  • 在成本效益可接受的情況下,將貨物分配給比必要數量更多的車輛
  • 表達駕駛員在特定路線上可輕鬆接送的物品數量偏好設定
  • 將車輛載重量控制在其物理最大容量以下,以減少磨損並降低維護成本

您可以同時使用硬性和軟性負載限制限制。舉例來說,硬負載限制可能會表示車輛可安全載運的最大貨物重量,或一次可放入車輛的最大物品數量,而軟負載限制則可能是駕駛員可將所有物品放入車輛的最大重量或數量。