Condividi tramite


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

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:

  1. Aprire il file EVrouting.ipynb nel repository AzureMapsJupyterSamples in GitHub.

  2. Selezionare il pulsante Scarica file non elaborato nell'angolo superiore destro della schermata per salvare il file in locale.

    Screenshot che mostra come scaricare il file notebook denominato EVrouting.ipynb dal repository GitHub.

  3. 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

Screenshot che mostra come scaricare la prima cella del notebook contenente le istruzioni import necessarie con il pulsante Esegui evidenziato.

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={}&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
                   ]
                }
             }

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

Screenshot che mostra l'intervallo di posizioni.

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

Screenshot che mostra una mappa che mostra il percorso.

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:

Per un elenco completo delle API REST di Mappe di Azure, vedere: API REST di Mappe di Azure.

Passaggi successivi