Kurz: Směrování elektrických vozidel pomocí Azure Notebooks (Python)

Azure Mapy je portfolio geoprostorových rozhraní API služeb, která jsou nativně integrovaná do Azure. Tato rozhraní API umožňují vývojářům, podnikům a isvům vyvíjet aplikace podporující polohu, IoT, mobilitu, logistiku a řešení pro sledování prostředků.

Rozhraní AZURE Mapy REST API je možné volat z jazyků, jako jsou Python a R, a umožnit tak geoprostorovou analýzu dat a scénáře strojového učení. Azure Mapy nabízí robustní sadu rozhraní API pro směrování, která uživatelům umožňují vypočítat trasy mezi několika datovými body. Výpočty jsou založené na různých podmínkách, jako je typ vozidla nebo dosažitelná oblast.

V tomto kurzu vám pomůže řidič, jehož elektrická baterie vozidel je nízká. Řidič musí najít nejbližší možnou závozní stanici z místa ve vozidle.

V tomto kurzu:

  • Vytvořte a spusťte soubor Jupyter Notebook na Azure Notebooks v cloudu.
  • Volání rozhraní REST API Mapy Azure v Pythonu
  • Vyhledejte dostupný rozsah založený na modelu spotřeby elektrického vozidla.
  • Vyhledejte čerpací stanice pro elektrická vozidla v dosažitelném rozsahu nebo izochronu.
  • Vykreslíte dosažitelnou hranici rozsahu a stanice zpoplatnění na mapě.
  • Vyhledejte a vizualizujte trasu k nejbližší nájezdové stanici pro elektrická vozidla na základě doby jízdy.

Požadavky

  1. Vytvořte účet Azure Mapy a zvolte cenovou úroveň Gen 2 nebo S1.
  2. Získejte primární klíč předplatného, označované také jako primární klíč nebo klíč předplatného.

Další informace o ověřování v Azure Mapy najdete v tématu Správa ověřování v Azure Mapy.

Vytvoření Azure Notebooks projektu

Pokud chcete postupovat podle tohoto kurzu, musíte vytvořit projekt Azure Notebooks a stáhnout a spustit Jupyter Notebook souboru. Soubor Jupyter Notebook obsahuje kód Pythonu, který implementuje scénář v tomto kurzu. Pokud chcete vytvořit Azure Notebooks a nahrát do Jupyter Notebook dokument, proveďte následující kroky:

  1. Přejděte na Azure Notebooks a přihlaste se. Další informace najdete v tématu Rychlý start: Přihlášení a nastavení ID uživatele.

  2. V horní části stránky veřejného profilu vyberte My Projects (Moje projekty).

    Tlačítko Moje projekty

  3. Na stránce Moje projekty vyberte Nový Project.

    Tlačítko New Project

  4. V podokně Vytvořit nový Project zadejte název projektu a ID projektu.

    Podokno Vytvořit nový Project

  5. Vyberte Vytvořit.

  6. Po vytvoření projektu si tento soubor Jupyter Notebook z úložiště Azure Mapy Jupyter Notebook .

  7. V seznamu projektů na stránce Moje projekty vyberte svůj projekt a pak Upload soubor Jupyter Notebook dokumentu.

    nahrání Jupyter Notebook

  8. Upload ze svého počítače a pak vyberte Hotovo.

  9. Po úspěšném dokončení nahrávání se soubor zobrazí na stránce projektu. Poklikejte na soubor a otevřete ho jako Jupyter Notebook.

Zkuste porozumět funkcím, které jsou implementované v Jupyter Notebook souboru. Spusťte kód v souboru Jupyter Notebook po jedné buňce. Kód můžete spustit v každé buňce výběrem tlačítka Spustit v horní části Jupyter Notebook aplikace.

Tlačítko Spustit

Instalace balíčků na úrovni projektu

Pokud chcete kód spustit v Jupyter Notebook, nainstalujte balíčky na úrovni projektu pomocí následujících kroků:

  1. Stáhněte sirequirements.txt z úložiště azure Mapy Jupyter Notebook apak ho nahrajte do projektu.

  2. Na řídicím panelu projektu vyberte Project Nastavení.

  3. V Project Nastavení vyberte kartu Prostředí a pak vyberte Přidat.

  4. V části Kroky nastavení prostředí proveďte následující: a. V prvním rozevíracím seznamu vyberte Requirements.txt.
    b. V druhém rozevíracím seznamu vyberte svůj requirements.txt.
    c. Ve třetím rozevíracím seznamu vyberte jako verzi Python verze 3.6.

  5. Vyberte Uložit.

    Instalace balíčků

Načtení požadovaných modulů a architektur

Pokud chcete načíst všechny požadované moduly a architektury, spusťte následující skript.

import time
import aiohttp
import urllib.parse
from IPython.display import Image, display

Vyžádání hranice dosažitelné oblasti

Ve vozovém parku má firma pro doručování balíčků elektrická vozidla. Během dne je potřeba elektrická vozidla nabíjet, aniž by se museli vracet do skladu. Pokaždé, když zbývající poplatek klesne na méně než hodinu, vyhledáte sadu zpoplatněných stanic, které jsou v dosahu. V podstatě můžete hledat stanice, která se nabíjí, když je baterie málo nabitá. A získáte informace o hranici pro tento rozsah stanic zpoplatnění.

Vzhledem k tomu, že společnost preferuje použití tras, které vyžadují rovnováhu ekonomiky a rychlosti, požadovaný typ trasy je úspora. Následující skript volá rozhraní API Pro získání rozsahu tras služby Azure Mapy směrování. Používá parametry pro model spotřeby vozidla. Skript pak parsuje odpověď a vytvoří mnohoúhelníkový objekt ve formátu geojson, který představuje maximální dosažitelný rozsah vozu.

Pokud chcete určit hranice pro dosažitelný dojezd elektromobilů, spusťte skript v následující buňce:

subscriptionKey = "Your Azure Maps key"
currentLocation = [34.028115,-118.5184279]
session = aiohttp.ClientSession()

# Parameters for the vehicle consumption model 
travelMode = "car"
vehicleEngineType = "electric"
currentChargeInkWh=45
maxChargeInkWh=80
timeBudgetInSec=550
routeType="eco"
constantSpeedConsumptionInkWhPerHundredkm="50,8.2:130,21.3"


# Get boundaries for the electric vehicle's reachable range.
routeRangeResponse = await (await session.get("https://atlas.microsoft.com/route/range/json?subscription-key={}&api-version=1.0&query={}&travelMode={}&vehicleEngineType={}&currentChargeInkWh={}&maxChargeInkWh={}&timeBudgetInSec={}&routeType={}&constantSpeedConsumptionInkWhPerHundredkm={}"
                                              .format(subscriptionKey,str(currentLocation[0])+","+str(currentLocation[1]),travelMode, vehicleEngineType, currentChargeInkWh, maxChargeInkWh, timeBudgetInSec, routeType, constantSpeedConsumptionInkWhPerHundredkm))).json()

polyBounds = routeRangeResponse["reachableRange"]["boundary"]

for i in range(len(polyBounds)):
    coordList = list(polyBounds[i].values())
    coordList[0], coordList[1] = coordList[1], coordList[0]
    polyBounds[i] = coordList

polyBounds.pop()
polyBounds.append(polyBounds[0])

boundsData = {
               "geometry": {
                 "type": "Polygon",
                 "coordinates": 
                   [
                      polyBounds
                   ]
                }
             }

Vyhledání čerpacích stanic pro elektrická vozidla v dosažitelném rozsahu

Po tom, co určíte dosažitelný dojezd (isochron) pro elektrická vozidla, můžete vyhledat čerpací stanice v tomto rozsahu.

Následující skript volá rozhraní API Mapy rozhraní API pro postškálování v Rámci geometrie. Hledá čerpací stanice pro elektrická vozidla v rámci hranic maximálního dosahu automobilu. Skript pak parsuje odpověď do pole dostupných umístění.

Pokud chcete vyhledat čerpací stanice pro elektrická vozidla v dosahu, spusťte následující skript:

# Search for electric vehicle stations within reachable range.
searchPolyResponse = await (await session.post(url = "https://atlas.microsoft.com/search/geometry/json?subscription-key={}&api-version=1.0&query=electric vehicle station&idxSet=POI&limit=50".format(subscriptionKey), json = boundsData)).json() 

reachableLocations = []
for loc in range(len(searchPolyResponse["results"])):
                location = list(searchPolyResponse["results"][loc]["position"].values())
                location[0], location[1] = location[1], location[0]
                reachableLocations.append(location)

Upload dosažitelný rozsah a body účtování do Azure Mapy Data

Na mapě budete chtít vizualizovat čerpací stanice a hranici pro maximální dosažitelný rozsah elektrického vozidla. Pokud to chcete udělat, nahrajte data hranic a data stanice zpoplatnění jako objekty geojson do Azure Mapy Data. Použijte rozhraní DATA Upload API.

Pokud chcete nahrát data hranice a bodu účtování do Azure Mapy Data, spusťte následující dvě buňky:

rangeData = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          polyBounds
        ]
      }
    }
  ]
}

# Upload the range data to Azure Maps Data service.
uploadRangeResponse = await session.post("https://us.atlas.microsoft.com/mapData?subscription-key={}&api-version=2.0&dataFormat=geojson".format(subscriptionKey), json = rangeData)

rangeUdidRequest = uploadRangeResponse.headers["Location"]+"&subscription-key={}".format(subscriptionKey)

while True:
    getRangeUdid = await (await session.get(rangeUdidRequest)).json()
    if 'udid' in getRangeUdid:
        break
    else:
        time.sleep(0.2)
rangeUdid = getRangeUdid["udid"]
poiData = {
    "type": "FeatureCollection",
    "features": [
      {
        "type": "Feature",
        "properties": {},
        "geometry": {
            "type": "MultiPoint",
            "coordinates": reachableLocations
        }
    }
  ]
}

# Upload the electric vehicle charging station data to Azure Maps Data service.
uploadPOIsResponse = await session.post("https://us.atlas.microsoft.com/mapData?subscription-key={}&api-version=2.0&dataFormat=geojson".format(subscriptionKey), json = poiData)

poiUdidRequest = uploadPOIsResponse.headers["Location"]+"&subscription-key={}".format(subscriptionKey)

while True:
    getPoiUdid = await (await session.get(poiUdidRequest)).json()
    if 'udid' in getPoiUdid:
        break
    else:
        time.sleep(0.2)
poiUdid = getPoiUdid["udid"]

Vykreslení stanic s účtováním a dosažitelný rozsah na mapě

Po nahrání dat do datové služby zavolejte službu Azure Mapy Get Map Image. Tato služba se používá k vykreslení bodů zpoplatnění a maximální dosažitelné hranice na obrázku statické mapy spuštěním následujícího skriptu:

# Get boundaries for the bounding box.
def getBounds(polyBounds):
    maxLon = max(map(lambda x: x[0], polyBounds))
    minLon = min(map(lambda x: x[0], polyBounds))

    maxLat = max(map(lambda x: x[1], polyBounds))
    minLat = min(map(lambda x: x[1], polyBounds))
    
    # Buffer the bounding box by 10 percent to account for the pixel size of pins at the ends of the route.
    lonBuffer = (maxLon-minLon)*0.1
    minLon -= lonBuffer
    maxLon += lonBuffer

    latBuffer = (maxLat-minLat)*0.1
    minLat -= latBuffer
    maxLat += latBuffer
    
    return [minLon, maxLon, minLat, maxLat]

minLon, maxLon, minLat, maxLat = getBounds(polyBounds)

path = "lcff3333|lw3|la0.80|fa0.35||udid-{}".format(rangeUdid)
pins = "custom|an15 53||udid-{}||https://raw.githubusercontent.com/Azure-Samples/AzureMapsCodeSamples/master/AzureMapsCodeSamples/Common/images/icons/ev_pin.png".format(poiUdid)

encodedPins = urllib.parse.quote(pins, safe='')

# Render the range and electric vehicle charging points on the map.
staticMapResponse =  await session.get("https://atlas.microsoft.com/map/static/png?api-version=1.0&subscription-key={}&pins={}&path={}&bbox={}&zoom=12".format(subscriptionKey,encodedPins,path,str(minLon)+", "+str(minLat)+", "+str(maxLon)+", "+str(maxLat)))

poiRangeMap = await staticMapResponse.content.read()

display(Image(poiRangeMap))

Mapa zobrazující rozsah umístění

Vyhledání optimální stanice pro dojení

Nejprve chcete určit všechny potenciální stanice zpoplatnění v dosažitelném rozsahu. Pak chcete vědět, ke kterým z nich můžete dosáhnout v minimálním časovém limitu.

Následující skript volá rozhraní API pro směrování Azure Mapy Matrix. Vrátí zadanou polohu vozidla, dobu cesty a vzdálenost ke každé zájezdové stanici. Skript v další buňce parsuje odpověď a vyhledá nejbližší dosažitelnou zpoplatněnou stanici s ohledem na čas.

Pokud chcete najít nejbližší dosažitelnou zpoplatněnou stanici, ke které se dostanete co nejméně času, spusťte skript v následující buňce:

locationData = {
            "origins": {
              "type": "MultiPoint",
              "coordinates": [[currentLocation[1],currentLocation[0]]]
            },
            "destinations": {
              "type": "MultiPoint",
              "coordinates": reachableLocations
            }
         }

# Get the travel time and distance to each specified charging station.
searchPolyRes = await (await session.post(url = "https://atlas.microsoft.com/route/matrix/json?subscription-key={}&api-version=1.0&routeType=shortest&waitForResults=true".format(subscriptionKey), json = locationData)).json()

distances = []
for dist in range(len(reachableLocations)):
    distances.append(searchPolyRes["matrix"][0][dist]["response"]["routeSummary"]["travelTimeInSeconds"])

minDistLoc = []
minDistIndex = distances.index(min(distances))
minDistLoc.extend([reachableLocations[minDistIndex][1], reachableLocations[minDistIndex][0]])
closestChargeLoc = ",".join(str(i) for i in minDistLoc)

Vypočítejte trasu k nejbližší stanice pro účtování.

Teď, když jste našli nejbližší zpoplatněnou stanici, můžete zavolat rozhraní API Get Route Directions a požádat o podrobnou trasu z aktuální polohy elektromobilu do stanice pro účtování.

Pokud chcete získat trasu k stanici zpoplatnění a parsovat odpověď a vytvořit objekt geojson představující trasu, spusťte skript v následující buňce:

# Get the route from the electric vehicle's current location to the closest charging station. 
routeResponse = await (await session.get("https://atlas.microsoft.com/route/directions/json?subscription-key={}&api-version=1.0&query={}:{}".format(subscriptionKey, str(currentLocation[0])+","+str(currentLocation[1]), closestChargeLoc))).json()

route = []
for loc in range(len(routeResponse["routes"][0]["legs"][0]["points"])):
                location = list(routeResponse["routes"][0]["legs"][0]["points"][loc].values())
                location[0], location[1] = location[1], location[0]
                route.append(location)

routeData = {
         "type": "LineString",
         "coordinates": route
     }

Vizualizace trasy

Pokud chcete trasu vizualizovat, nejprve nahrajte data trasy jako objekt geojson do Azure Mapy Data . K tomu použijte rozhraní API služby Azure Mapy Data Upload. Potom zavolejte vykreslovací službu Get Map Image APIa vykreslujte trasu na mapě a vizualizujte ji.

Pokud chcete získat obrázek pro vykreslenou trasu na mapě, spusťte následující skript:

# Upload the route data to Azure Maps Data service .
routeUploadRequest = await session.post("https://atlas.microsoft.com/mapData?subscription-key={}&api-version=2.0&dataFormat=geojson".format(subscriptionKey), json = routeData)

udidRequestURI = routeUploadRequest.headers["Location"]+"&subscription-key={}".format(subscriptionKey)

while True:
    udidRequest = await (await session.get(udidRequestURI)).json()
    if 'udid' in udidRequest:
        break
    else:
        time.sleep(0.2)

udid = udidRequest["udid"]

destination = route[-1]

destination[1], destination[0] = destination[0], destination[1]

path = "lc0f6dd9|lw6||udid-{}".format(udid)
pins = "default|codb1818||{} {}|{} {}".format(str(currentLocation[1]),str(currentLocation[0]),destination[1],destination[0])


# Get boundaries for the bounding box.
minLat, maxLat = (float(destination[0]),currentLocation[0]) if float(destination[0])<currentLocation[0] else (currentLocation[0], float(destination[0]))
minLon, maxLon = (float(destination[1]),currentLocation[1]) if float(destination[1])<currentLocation[1] else (currentLocation[1], float(destination[1]))

# Buffer the bounding box by 10 percent to account for the pixel size of pins at the ends of the route.
lonBuffer = (maxLon-minLon)*0.1
minLon -= lonBuffer
maxLon += lonBuffer

latBuffer = (maxLat-minLat)*0.1
minLat -= latBuffer
maxLat += latBuffer

# Render the route on the map.
staticMapResponse = await session.get("https://atlas.microsoft.com/map/static/png?api-version=1.0&subscription-key={}&&path={}&pins={}&bbox={}&zoom=16".format(subscriptionKey,path,pins,str(minLon)+", "+str(minLat)+", "+str(maxLon)+", "+str(maxLat)))

staticMapImage = await staticMapResponse.content.read()

await session.close()
display(Image(staticMapImage))

Mapa zobrazující trasu

V tomto kurzu jste zjistili, jak přímo volat rozhraní REST API služby Azure Mapy a vizualizovat azure Mapy data pomocí Pythonu.

Pokud chcete prozkoumat rozhraní API služby Azure Mapy, která se používají v tomto kurzu, projděte si:

Vyčištění prostředků

Neexistují žádné prostředky, které by vyžadovaly vyčištění.

Další kroky

Další informace o Azure Notebooks najdete v tématu