Esercitazione: Instradare veicoli elettrici con Jupyter Notebook (Python)
Mappe di Azure è un portfolio di API del servizio geospaziali integrate in Azure, consentendo agli sviluppatori di creare applicazioni con riconoscimento della posizione per diversi scenari, ad esempio IoT, mobilità e rilevamento degli asset.
Mappe di Azure API REST supportano linguaggi come Python e R per l'analisi dei dati geospaziali e l'apprendimento automatico, offrendo API di routing affidabili per calcolare le route in base a condizioni quali il tipo di veicolo o l'area raggiungibile.
Questa esercitazione guida gli utenti attraverso il routing dei veicoli elettrici usando api Mappe di Azure insieme a Jupyter Notebook in VS Code e Python per trovare la stazione di ricarica più vicina quando la batteria è scarica.
Questa esercitazione illustra come:
- Creare ed eseguire un notebook di Jupyter in VS Code.
- Chiamare le API REST di Mappe di Azure in Python.
- Cercare un'area raggiungibile in base al modello di consumo del veicolo elettrico.
- Cercare le stazioni di ricarica dei veicoli elettrici all'interno dell'intervallo raggiungibile o isocrona.
- Eseguire il rendering dei limiti dell'area raggiungibile e delle stazioni di ricarica su una mappa.
- Trovare e visualizzare un itinerario per la stazione di ricarica di veicoli elettrici più vicina in base al tempo di guida.
Prerequisiti
- Un account Mappe di Azure
- Una chiave di sottoscrizione
- Visual Studio Code
- Conoscenza pratica di Jupyter Notebook in VS Code
- Ambiente configurato per l'uso con Python in Jupyter Notebooks. Per altre informazioni, vedere Configurazione dell'ambiente.
Nota
Per altre informazioni sull'autenticazione in Mappe di Azure, vedere Gestire l'autenticazione in Mappe di Azure.
Installare i pacchetti a livello di progetto
Il progetto EV Routing and Reachable Range ha dipendenze dalle librerie python aiohttp e IPython . È possibile installarli nel terminale di Visual Studio usando pip:
pip install aiohttp
pip install ipython
Aprire Jupyter Notebook in Visual Studio Code
Scaricare quindi aprire il notebook usato in questa esercitazione:
Aprire il file EVrouting.ipynb nel repository AzureMapsJupyterSamples in GitHub.
Selezionare il pulsante Scarica file non elaborato nell'angolo superiore destro della schermata per salvare il file in locale.
Aprire il notebook scaricato in Visual Studio Code facendo clic con il pulsante destro del mouse sul file e quindi scegliendo Apri con > Visual Studio Code o tramite il Esplora file vs Code.
Caricare i moduli e i framework necessari
Dopo aver aggiunto il codice, è possibile eseguire una cella usando l'icona Esegui a sinistra della cella e l'output viene visualizzato sotto la cella di codice.
Eseguire lo script seguente per caricare tutti i moduli e i framework necessari.
import time
import aiohttp
import urllib.parse
from IPython.display import Image, display
Richiesta dei limiti dell'area raggiungibile
Una società di consegna di pacchetti gestisce una flotta che include alcuni veicoli elettrici. Questi veicoli devono essere ricaricati durante il giorno senza tornare al magazzino. Quando la carica rimanente scende al di sotto di un'ora, viene eseguita una ricerca per trovare le stazioni di ricarica all'interno di un intervallo raggiungibile. Le informazioni sui limiti per l'intervallo di queste stazioni di ricarica vengono quindi ottenute.
La richiesta routeType
è eco per bilanciare l'economia e la velocità. Lo script seguente chiama l'API Get Route Range del servizio di routing Mappe di Azure, usando i parametri correlati al modello di consumo del veicolo. Lo script analizza quindi la risposta per creare un oggetto poligono in formato GeoJSON, che rappresenta l'intervallo raggiungibile massimo dell'auto.
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
]
}
}
Cercare le stazioni di ricarica per veicoli elettrici entro l'area raggiungibile
Dopo aver determinato la portata raggiungibile del veicolo elettrico (isocrona), è possibile cercare le stazioni di ricarica all'interno di tale area.
Lo script seguente usa l'API Mappe di Azure Post Search Inside Geometry per trovare le stazioni di ricarica all'interno dell'intervallo raggiungibile massimo del veicolo. Analizza quindi la risposta in una matrice di posizioni raggiungibili.
# 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)
Eseguire il rendering delle stazioni di ricarica e dell'area raggiungibile su una mappa
Chiamare il servizio get map image di Mappe di Azure per eseguire il rendering dei punti di ricarica e del limite massimo raggiungibile nell'immagine mappa statica eseguendo lo script seguente:
# 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))
Trovare la stazione di ricarica ottimale
Prima di tutto, identificare tutte le potenziali stazioni di ricarica all'interno dell'intervallo raggiungibile del veicolo. Successivamente, determinare quale di queste stazioni è accessibile nel minor tempo possibile.
Lo script seguente chiama l'API Matrix Routing di Mappe di Azure. Restituisce la posizione del veicolo, il tempo di viaggio e la distanza per ogni stazione di ricarica. Lo script successivo analizza questa risposta per identificare la stazione di ricarica più vicina che può essere raggiunta nel minor periodo di tempo.
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)
Calcolare l'itinerario per la stazione di ricarica più vicina
Dopo aver individuato la stazione di ricarica più vicina, usare l'API Get Route Directions per ottenere indicazioni dettagliate dalla posizione corrente dei veicoli. Eseguire lo script nella cella successiva per generare e analizzare un oggetto GeoJSON che rappresenta la route.
# 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
}
Visualizzare l'itinerario
Per visualizzare il percorso, usare l'API Get Map Image (Ottieni immagine mappa) per eseguirne il rendering sulla mappa.
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 questa esercitazione si è appreso come chiamare direttamente le API REST di Mappe di Azure e visualizzare i dati di Mappe di Azure con Python.
Per altre informazioni sulle API di Mappe di Azure usate in questa esercitazione, vedere:
- Get Route Directions
- Get Route Range
- Post Route Matrix
- Post Search Inside Geometry
- Render - Get Map Image
Per un elenco completo delle API REST di Mappe di Azure, vedere: API REST di Mappe di Azure.