Självstudie: Dirigera elfordon med hjälp av Azure Notebooks (Python)

Azure Kartor är en portfölj med geospatiala tjänst-API:er som är inbyggda i Azure. Dessa API:er gör det möjligt för utvecklare, företag och ISV:er att utveckla platsmedvetna appar, IoT, mobilitet, logistik och lösningar för tillgångsspårning.

Azure Kartor REST-API:er kan anropas från språk som Python och R för att aktivera geospatiala dataanalyser och maskininlärningsscenarier. Azure Kartor erbjuder en robust uppsättning routnings-API:er som gör det möjligt för användare att beräkna vägar mellan flera datapunkter. Beräkningarna baseras på olika förhållanden, till exempel fordonstyp eller nåbart område.

I den här självstudien går du och hjälper en förare vars elbilsbatteri är lågt. Föraren måste hitta den närmaste möjliga laddningsstationen från fordonets plats.

I den här självstudien kommer vi att:

  • Skapa och kör en Jupyter Notebook-fil på Azure Notebooks i molnet.
  • Anropa Azure Kartor REST API:er i Python.
  • Sök efter ett räckviddsintervall baserat på elbilens förbrukningsmodell.
  • Sök efter laddningsstationer för elfordon inom räckvidden, eller isochron.
  • Rendera räckviddsgräns och laddningsstationer på en karta.
  • Hitta och visualisera en väg till närmaste laddningsstation för elfordon baserat på körtid.

Förutsättningar

Kommentar

Mer information om autentisering i Azure Kartor finns i Hantera autentisering i Azure Kartor.

Skapa ett Azure Notebooks-projekt

Om du vill följa med i den här självstudien måste du skapa ett Azure Notebooks-projekt och ladda ned och köra Jupyter Notebook-filen. Jupyter Notebook-filen innehåller Python-kod som implementerar scenariot i den här självstudien. Gör följande för att skapa ett Azure Notebooks-projekt och ladda upp Jupyter Notebook-dokumentet till det:

  1. Gå till Azure Notebooks och logga in. Mer information finns i Snabbstart: Logga in och ange ett användar-ID.

  2. Välj Mina projekt överst på den offentliga profilsidan.

    The My Projects button

  3. På sidan Mina projekt väljer du Nytt projekt.

    The New Project button

  4. I fönstret Skapa nytt projekt anger du ett projektnamn och projekt-ID.

    The Create New Project pane

  5. Välj Skapa.

  6. När projektet har skapats laddar du ned den här Jupyter Notebook-dokumentfilen från Azure Kartor Jupyter Notebook-lagringsplatsen.

  7. I projektlistan på sidan Mina projekt väljer du ditt projekt och sedan Ladda upp för att ladda upp Jupyter Notebook-dokumentfilen.

    upload Jupyter Notebook

  8. Ladda upp filen från datorn och välj sedan Klar.

  9. När uppladdningen har slutförts visas filen på projektsidan. Dubbelklicka på filen för att öppna den som en Jupyter Notebook.

Försök att förstå de funktioner som implementeras i Jupyter Notebook-filen. Kör koden i Jupyter Notebook-filen, en cell i taget. Du kan köra koden i varje cell genom att välja knappen Kör överst i Jupyter Notebook-appen.

The Run button

Installera paket på projektnivå

Om du vill köra koden i Jupyter Notebook installerar du paket på projektnivå genom att göra följande:

  1. Ladda ned filen requirements.txt från Lagringsplatsen Azure Kartor Jupyter Notebook och ladda sedan upp den till projektet.

  2. Välj Project Inställningar på projektinstrumentpanelen.

  3. I fönstret Projekt Inställningar väljer du fliken Miljö och sedan Lägg till.

  4. Under Installationssteg för miljö gör du följande: a. I den första listrutan väljer du Requirements.txt.
    b. I den andra listrutan väljer du filen requirements.txt .
    c. I den tredje listrutan väljer du Python Version 3.6 som version.

  5. Välj Spara.

    Install packages

Läs in de moduler och ramverk som krävs

Kör följande skript för att läsa in alla nödvändiga moduler och ramverk.

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

Begär gränsen för det nåbara intervallet

Ett paketleveransföretag har några elfordon i sin flotta. Under dagen måste elfordon laddas om utan att behöva återvända till lagret. Varje gång den återstående avgiften sjunker till mindre än en timme söker du efter en uppsättning laddningsstationer som ligger inom ett räckviddsintervall. I princip söker du efter en laddningsstation när batteriet är låg på laddning. Och du får gränsinformationen för det utbudet av laddningsstationer.

Eftersom företaget föredrar att använda vägar som kräver en balans mellan ekonomi och hastighet, är den begärda routeType eco. Följande skript anropar API:et Hämta routningsintervall för Azure Kartor routningstjänsten. Den använder parametrar för fordonets förbrukningsmodell. Skriptet parsar sedan svaret för att skapa ett polygonobjekt i geojson-formatet, vilket representerar bilens maximala räckviddsområde.

Om du vill fastställa gränserna för elfordonets räckvidd kör du skriptet i följande cell:

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
                   ]
                }
             }

Sök efter laddningsstationer för elfordon inom räckvidden

När du har fastställt räckviddsintervallet (isochron) för elfordonet kan du söka efter laddningsstationer inom det intervallet.

Följande skript anropar Azure Kartor Post Search Inside Geometry API. Den söker efter laddningsstationer för elfordon, inom gränserna för bilens maximala räckvidd. Sedan parsar skriptet svaret på en matris med nåbara platser.

Kör följande skript för att söka efter laddningsstationer för elfordon inom räckviddsområdet:

# 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)

Ladda upp räckviddsintervallet och laddningspunkterna

Det är bra att visualisera laddningsstationerna och gränsen för elfordonets maximala räckvidd på en karta. Följ stegen som beskrivs i artikeln Så här skapar du dataregister för att ladda upp gränsdata och laddningsstationsdata som geojson-objekt till ditt Azure Storage-konto och registrera dem sedan i ditt Azure Kartor-konto. Se till att anteckna värdet för den unika identifieraren (udid) och du behöver det. Det udid är så du refererar till de geojson-objekt som du laddade upp till ditt Azure Storage-konto från källkoden.

Rendera laddningsstationerna och räckviddsintervallet på en karta

När du har laddat upp data till Azure Storage-kontot anropar du tjänsten Azure Kartor Hämta kartbild. Den här tjänsten används för att återge laddningspunkterna och den maximala gränsen som kan nås på den statiska kartbilden genom att köra följande skript:

# 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=2022-08-01&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))

A map showing the location range

Hitta den optimala laddningsstationen

Först vill du fastställa alla potentiella laddningsstationer inom räckviddsintervallet. Sedan vill du veta vilken av dem som kan nås på minst en viss tid.

Följande skript anropar API:et för Azure Kartor Matrix-routning. Den returnerar den angivna fordonsplatsen, restiden och avståndet till varje laddningsstation. Skriptet i nästa cell parsar svaret för att hitta den närmaste laddningsstationen med avseende på tid.

Om du vill hitta den närmaste laddningsstationen som kan nås på minst tid kör du skriptet i följande cell:

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)

Beräkna vägen till närmaste laddningsstation

Nu när du har hittat den närmaste laddningsstationen kan du anropa API:et Get Route Directions för att begära den detaljerade vägen från elfordonets aktuella plats till laddningsstationen.

Kör skriptet i följande cell för att hämta vägen till laddningsstationen och parsa svaret för att skapa ett geojson-objekt som representerar vägen:

# 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
     }

Visualisera vägen

För att visualisera vägen följer du stegen som beskrivs i artikeln Så här skapar du dataregister för att ladda upp routningsdata som ett geojson-objekt till ditt Azure Storage-konto och sedan registrera dem i ditt Azure Kartor-konto. Se till att anteckna värdet för den unika identifieraren (udid) och du behöver det. Det udid är så du refererar till de geojson-objekt som du laddade upp till ditt Azure Storage-konto från källkoden. Anropa sedan renderingstjänsten Get Map Image API för att återge vägen på kartan och visualisera den.

Kör följande skript för att hämta en bild för den renderade vägen på kartan:

# 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=2022-08-01&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))

A map showing the route

I den här självstudien har du lärt dig hur du anropar Azure Kartor REST-API:er direkt och visualiserar Azure Kartor data med hjälp av Python.

Information om hur du utforskar Api:er för Azure Kartor som används i den här självstudien finns i:

Rensa resurser

Det finns inga resurser som kräver rensning.

Nästa steg

Mer information om Azure Notebooks finns i