Tutorial: Routenplanung für Elektrofahrzeuge mit Azure Notebooks (Python)
Azure Maps ist ein Portfolio von Geodienst-APIs, die in Azure integriert sind, damit Entwickler standortbezogene Anwendungen für verschiedene Szenarien wie IoT, Mobilität und Ressourcennachverfolgung erstellen können.
REST-APIs von Azure Maps unterstützen Sprachen wie Python und R für Geodatenanalyse und maschinelles Lernen und bieten robuste Routenplanungs-APIs zur Berechnung von Routen auf der Grundlage von Bedingungen wie Fahrzeugtyp oder erreichbarem Bereich.
Dieses Tutorial führt Benutzer durch die Routenplanung für Elektrofahrzeuge mithilfe von Azure Maps-APIs in Verbindung mit Jupyter Notebook-Instanzen in VS Code und Python, um bei niedrigem Akkustand die nächstgelegene Ladestation zu finden.
In diesem Lernprogramm lernen Sie Folgendes:
- Erstellen und Ausführen eines Jupyter Notebooks in VS Code
- Aufrufen von Azure Maps-REST-APIs in Python
- Suchen nach einem erreichbaren Bereich auf Grundlage des Verbrauchsmodells des Elektrofahrzeugs
- Suchen nach Ladestationen für Elektrofahrzeuge in Reichweite bzw. in der Isochrone
- Rendern der Grenze des erreichbaren Bereichs und der Ladestationen auf einer Karte
- Ermitteln und Visualisieren einer Route zur nächstgelegenen Ladestation basierend auf der Fahrtzeit
Voraussetzungen
- Ein Azure Maps-Konto
- Ein Abonnementschlüssel
- Visual Studio Code
- Fundierte Kenntnisse von Jupyter Notebooks in VS Code
- Eingerichtete Umgebung für die Arbeit mit Python in Jupyter Notebooks. Weitere Informationen finden Sie unter Einrichten Ihrer Umgebung.
Hinweis
Weitere Informationen zur Authentifizierung in Azure Maps finden Sie unter Verwalten der Authentifizierung in Azure Maps.
Installieren von Paketen auf Projektebene
Das Projekt EV Routing and Reachable Range ist von den Python-Bibliotheken aiohttp und IPython abhängig. Sie können diese im Visual Studio-Terminal mit pip installieren:
pip install aiohttp
pip install ipython
Öffnen von Jupyter Notebook in Visual Studio Code
Laden Sie das Notebook herunter, das in diesem Tutorial verwendet wird, und öffnen Sie es:
Öffnen Sie die Datei EVrouting.ipynb im AzureMapsJupyterSamples-Repository in GitHub.
Wählen Sie auf dem Bildschirm oben rechts die Schaltfläche Rohdatei herunterladen aus, um die Datei lokal zu speichern.
Öffnen Sie das heruntergeladene Notebook in Visual Studio Code, indem Sie mit der rechten Maustaste auf die Datei klicken und dann Öffnen mit > Visual Studio Code auswählen, oder verwenden Sie den VS Code-Explorer.
Laden der erforderlichen Module und Frameworks
Sobald Ihr Code hinzugefügt wurde, können Sie eine Zelle über das Symbol Ausführen links neben der Zelle ausführen. Die Ausgabe wird unterhalb der Codezelle angezeigt.
Führen Sie das folgende Skript aus, um alle erforderlichen Module und Frameworks zu laden:
import time
import aiohttp
import urllib.parse
from IPython.display import Image, display
Anfordern der Grenze des erreichbaren Bereichs
Die Fahrzeugflotte eines Paketzustellers umfasst auch einige Elektrofahrzeuge. Diese Fahrzeuge müssen im Laufe des Tages aufgeladen werden, ohne dafür zum Lager zurückkehren zu müssen. Wenn die Restkapazität auf unter eine Stunde fällt, wird nach erreichbaren Ladestationen gesucht. Anschließend werden die Grenzinformationen für die in Frage kommenden Ladestationen abgerufen.
Der anforderte routeType
ist eco, um ein ausgewogenes Verhältnis zwischen Wirtschaftlichkeit und Geschwindigkeit zu erhalten. Mit dem folgenden Skript wird die API Get Route Range des Azure Maps-Routenplanungsdiensts aufgerufen. Dabei werden Parameter im Zusammenhang mit dem Verbrauchsmodell des Fahrzeugs verwendet. Das Skript analysiert dann die Antwort, um ein Polygonobjekt im GeoJSON-Format zu erstellen, das die maximale Reichweite des Fahrzeugs darstellt.
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={}¤tChargeInkWh={}&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
]
}
}
Suchen nach Ladestationen für Elektrofahrzeuge im erreichbaren Bereich
Nach Bestimmung der Reichweite (Isochrone) des Elektrofahrzeugs können Sie innerhalb dieses Bereichs nach Ladestationen suchen.
Das folgende Skript verwendet die Azure Maps-API Post Search Inside Geometry, um nach Ladestationen innerhalb der maximalen Reichweite des Fahrzeugs zu suchen. Anschließend analysiert es die Antwort, um ein Array mit erreichbaren Standorten zu erhalten.
# 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)
Rendern der Ladestationen und des erreichbaren Bereichs auf einer Karte
Rufen Sie den Dienst zum Abrufen des Kartenbilds von Azure Maps auf, um die Ladestationen sowie die Grenze der maximalen Reichweite auf dem statischen Kartenbild zu rendern. Führen Sie dazu das folgende Skript aus:
# 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)
polyBoundsFormatted = ('|'.join(map(str, polyBounds))).replace('[','').replace(']','').replace(',','')
reachableLocationsFormatted = ('|'.join(map(str, reachableLocations))).replace('[','').replace(']','').replace(',','')
path = "lcff3333|lw3|la0.80|fa0.35||{}".format(polyBoundsFormatted)
pins = "custom|an15 53||{}||https://raw.githubusercontent.com/Azure-Samples/AzureMapsCodeSamples/e3a684e7423075129a0857c63011e7cfdda213b7/Static/images/icons/ev_pin.png".format(reachableLocationsFormatted)
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))
Finden der optimalen Ladestation
Identifizieren zuerst alle potenziellen Ladestationen innerhalb der Reichweite des Fahrzeugs. Bestimmen Sie als Nächstes, welche dieser Stationen am schnellsten genutzt werden kann.
Mit dem folgenden Skript wird die API für die Matrixroutenplanung von Azure Maps aufgerufen. Diese gibt die Position des Fahrzeugs, die Fahrtzeit und die Entfernung zu den einzelnen Ladestationen zurück. Das folgende Skript analysiert diese Antwort, um die nächstgelegene Ladestation zu identifizieren, die am schnellsten erreichbar ist:
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)
Berechnen der Route zur nächstgelegenen Ladestation
Verwenden Sie nach Ermittlung der nächstgelegenen Ladestation die API Get Route Directions, um eine detaillierte Wegbeschreibung für den aktuellen Standort des Fahrzeugs zu erhalten. Führen Sie das Skript in der nächsten Zelle aus, um ein GeoJSON-Objekt, das die Route darstellt, zu generieren und zu analysieren.
# 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
}
Visualisieren der Route
Verwenden Sie zum Visualisieren der Route die API Get Map Image, um sie auf der Karte zu rendern.
destination = route[-1]
#destination[1], destination[0] = destination[0], destination[1]
routeFormatted = ('|'.join(map(str, route))).replace('[','').replace(']','').replace(',','')
path = "lc0f6dd9|lw6||{}".format(routeFormatted)
pins = "default|codb1818||{} {}|{} {}".format(str(currentLocation[1]),str(currentLocation[0]),destination[0],destination[1])
# Get boundaries for the bounding box.
minLon, maxLon = (float(destination[0]),currentLocation[1]) if float(destination[0])<currentLocation[1] else (currentLocation[1], float(destination[0]))
minLat, maxLat = (float(destination[1]),currentLocation[0]) if float(destination[1])<currentLocation[0] else (currentLocation[0], 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))
In diesem Tutorial haben Sie erfahren, wie Sie REST-APIs von Azure Maps direkt aufrufen und Azure Maps-Daten mit Python visualisieren.
Weitere Informationen zu den in diesem Tutorial verwendeten Azure Maps-APIs finden Sie unter:
- Abrufen von Wegbeschreibungen
- Abrufen des Routenbereichs
- Veröffentlichen der Routenmatrix
- Veröffentlichen einer Suche innerhalb der Geometrie
- Rendern: Abrufen des Kartenbilds
Eine vollständige Liste mit den Azure Maps-REST-APIs finden Sie unter Azure Maps-Dokumentation.