Självstudie: Dirigera elfordon med hjälp av Azure Notebooks (Python)
Azure Maps är en portfölj med geospatiala tjänst-API:er som är integrerade i Azure, vilket gör det möjligt för utvecklare att skapa platsmedvetna program för olika scenarier som IoT, mobilitet och tillgångsspårning.
Rest-API:er för Azure Maps stöder språk som Python och R för geospatial dataanalys och maskininlärning, och erbjuder robusta routnings-API:er för att beräkna vägar baserat på förhållanden som fordonstyp eller nåbart område.
Den här självstudien vägleder användare genom att dirigera elfordon med hjälp av Azure Maps-API:er tillsammans med Jupyter Notebooks i VS Code och Python för att hitta den närmaste laddningsstationen när batteriet är lågt.
I den här självstudien kommer vi att:
- Skapa och kör en Jupyter Notebook i VS Code.
- Anropa REST-API:er för Azure Maps 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
- Ett Azure Maps-konto
- En prenumerationsnyckel
- Visual Studio Code
- En fungerande kunskap om Jupyter Notebooks i VS Code
- Miljö konfigurerad för att fungera med Python i Jupyter Notebooks. Mer information finns i Konfigurera din miljö.
Kommentar
Mer information om autentisering i Azure Maps finns i Hantera autentisering i Azure Maps.
Installera paket på projektnivå
Projektet EV Routing and Reachable Range har beroenden för python-biblioteken aiohttp och IPython. Du kan installera dessa i Visual Studio-terminalen med pip:
pip install aiohttp
pip install ipython
Öppna Jupyter Notebook i Visual Studio Code
Ladda ned och öppna sedan notebook-filen som används i den här självstudien:
Öppna filen EVrouting.ipynb på lagringsplatsen AzureMapsJupyterSamples i GitHub.
Välj knappen Ladda ned råfil i det övre högra hörnet på skärmen för att spara filen lokalt.
Öppna den nedladdade notebook-filen i Visual Studio Code genom att högerklicka på filen och sedan välja Öppna med > Visual Studio Code eller via VS Code-Utforskaren.
Läs in de moduler och ramverk som krävs
När koden har lagts till kan du köra en cell med hjälp av ikonen Kör till vänster om cellen och utdata visas under kodcellen.
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 driver en flotta som innehåller vissa elfordon. Dessa fordon måste laddas under dagen utan att återvända till lagret. När den återstående avgiften sjunker under en timme utförs en sökning för att hitta laddningsstationer inom ett nåbart intervall. Gränsinformationen för intervallet för dessa laddningsstationer erhålls sedan.
Det begärda routeType
är eko för att balansera ekonomi och hastighet. Följande skript anropar API:et Hämta routningsintervall för Azure Maps-routningstjänsten med hjälp av parametrar relaterade till fordonets förbrukningsmodell. Skriptet parsar sedan svaret för att skapa ett polygonobjekt i GeoJSON-format, vilket representerar bilens maximala räckvidd.
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
]
}
}
Sök efter laddningsstationer för elfordon inom räckvidden
När du har fastställt elbilens räckvidd (isochron) kan du söka efter laddningsstationer inom det området.
Följande skript använder API:et För Azure Maps Post Search Inside Geometry för att hitta laddningsstationer inom fordonets maximala räckvidd. Svaret parsas sedan till en matris med nåbara platser.
# 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)
Rendera laddningsstationerna och räckviddsintervallet på en karta
Anropa Azure Maps Get Map Image-tjänsten 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)
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))
Hitta den optimala laddningsstationen
Identifiera först alla potentiella laddningsstationer inom fordonets räckvidd. Bestäm sedan vilken av dessa stationer som kan nås på kortast möjliga tid.
Följande skript anropar API:et för matrisroutning i Azure Maps. Den returnerar fordonets plats, restid och avstånd till varje laddningsstation. Det efterföljande skriptet parsar det här svaret för att identifiera den närmaste laddningsstationen som kan nås under minst tid.
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
När du har lokaliserat närmaste laddningsstation använder du API:et Get Route Directions för att hämta detaljerade anvisningar från fordonens aktuella plats. Kör skriptet i nästa cell för att generera och parsa 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
Om du vill visualisera vägen använder du API:et Hämta kartbild för att återge den på kartan.
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))
I den här självstudien har du lärt dig hur du anropar REST-API:er för Azure Maps direkt och visualiserar Azure Maps-data med hjälp av Python.
Mer information om Azure Maps-API:er som används i den här självstudien finns i:
- Hämta vägbeskrivningar
- Hämta routningsintervall
- Matris efter väg
- Post Search Inside Geometry
- Rendera – Hämta kartbild
En fullständig lista över REST-API:er för Azure Maps finns i Rest-API:er för Azure Maps.