Sdílet prostřednictvím


Kurz: Směrování elektrických vozidel pomocí poznámkových bloků Jupyter (Python)

Azure Maps je portfolio geoprostorových rozhraní API služeb integrované do Azure, které vývojářům umožňuje vytvářet aplikace pracující s umístěním pro různé scénáře, jako je IoT, mobilita a sledování prostředků.

Rozhraní REST API služby Azure Maps podporují jazyky, jako je Python a R pro analýzu geoprostorových dat a strojové učení, a nabízí robustní rozhraní API směrování pro výpočet tras na základě podmínek, jako je typ vozidla nebo dosažitelná oblast.

Tento kurz provede uživatele směrováním elektrických vozidel pomocí rozhraní API služby Azure Maps spolu s aplikacemi Jupyter Notebooks ve VS Code a Pythonu, aby našli nejbližší nabíjecí stanici, když je baterie nízká.

V tomto kurzu:

  • Vytvořte a spusťte poznámkový blok Jupyter v editoru VS Code.
  • Volání rozhraní REST API služby Azure Maps v Pythonu
  • Vyhledejte dosažitelný rozsah na základě modelu spotřeby elektrického vozidla.
  • Vyhledejte nabíjecí stanice elektrických vozidel v dosahu nebo isochronu.
  • Vykreslení hranice dosažitelného rozsahu a nabíjecích stanic na mapě
  • Najděte a vizualizujete trasu k nejbližší nabíjecí stanici pro elektrické vozidlo na základě doby jízdy.

Požadavky

Poznámka:

Další informace o ověřování ve službě Azure Maps najdete v tématu správa ověřování v Azure Maps.

Instalace balíčků na úrovni projektu

Projekt SMĚROVÁNÍ EV a dosažitelného rozsahu má závislosti na knihovnách pythonu Aiohttp a IPython . Můžete je nainstalovat do terminálu sady Visual Studio pomocí nástroje pip:

pip install aiohttp
pip install ipython

Otevření poznámkového bloku Jupyter v editoru Visual Studio Code

Stáhněte si poznámkový blok použitý v tomto kurzu:

  1. Otevřete soubor EVrouting.ipynb v úložišti AzureMapsJupyterSamples na GitHubu.

  2. Výběrem tlačítka Stáhnout nezpracovaný soubor v pravém horním rohu obrazovky soubor uložte místně.

    Snímek obrazovky znázorňující, jak stáhnout soubor poznámkového bloku s názvem EVrouting.ipynb z úložiště GitHub

  3. Otevřete stažený poznámkový blok v editoru Visual Studio Code tak, že kliknete pravým tlačítkem myši na soubor a pak vyberete Otevřít v > editoru Visual Studio Code nebo v Průzkumník souborů editoru VS Code.

Načtení požadovaných modulů a architektur

Po přidání kódu můžete buňku spustit pomocí ikony Spustit vlevo od buňky a výstup se zobrazí pod buňkou s kódem.

Spuštěním následujícího skriptu načtěte všechny požadované moduly a architektury.

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

Snímek obrazovky znázorňující, jak stáhnout první buňku v poznámkovém bloku obsahující požadované příkazy importu se zvýrazněným tlačítkem Spustit

Vyžádání hranice dosažitelného rozsahu

Společnost pro doručování zásilek provozuje flotilu, která zahrnuje některá elektrická vozidla. Tato vozidla musí být dobíjená během dne bez návratu do skladu. Když zbývající poplatek klesne pod hodinu, provede se hledání a vyhledá nabíjecí stanice v dosažitelné vzdálenosti. Informace o hranicích pro rozsah těchto nabíjecích stanic se pak získávají.

Požadováno routeType je eco pro vyvážení ekonomiky a rychlosti. Následující skript volá rozhraní API get Route Range služby Azure Maps pomocí parametrů souvisejících s modelem spotřeby vozidla. Skript pak parsuje odpověď na vytvoření mnohoúhelníku ve formátu GeoJSON, který představuje maximální dosažitelný rozsah vozu.

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

Vyhledání nabíjecích stanic pro elektrické vozidlo v dosahu

Po určení dosažitelného rozsahu elektrického vozidla (isochron) můžete vyhledat nabíjecí stanice v této oblasti.

Následující skript používá rozhraní API služby Azure Maps Post Search Inside Geometry k vyhledání nabíjecích stanic v maximálním dosahu vozidla. Pak parsuje odpověď do pole dosažitelných umístění.

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

Vykreslení nabíjecích stanic a dosažitelného rozsahu na mapě

Voláním služby Azure Maps Get Map Image vykreslíte nabíjecí body a maximální dosažitelnou hranici na obrázku statické mapy spuštěním následujícího skriptu:

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

Snímek obrazovky znázorňující rozsah umístění

Vyhledání optimální nabíjecí stanice

Nejprve identifikujte všechny potenciální nabíjecí stanice v dosahu vozidla. Dále určete, které z těchto stanic lze získat přístup v nejkratší možné době.

Následující skript volá rozhraní API pro směrování matice Azure Maps. Vrátí polohu, dobu jízdy a vzdálenost vozidla do každé nabíjecí stanice. Následující skript analyzuje tuto odpověď tak, aby identifikoval nejbližší nabíjecí stanici, která se dá dosáhnout v nejmenším časovém intervalu.

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)

Výpočet trasy k nejbližší nabíjecí stanici

Po vyhledání nejbližší nabíjecí stanice použijte rozhraní API Get Route Directions API k získání podrobných pokynů z aktuální polohy vozidel. Spuštěním skriptu v další buňce vygenerujte a parsujte objekt GeoJSON představující trasu.

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

Vizualizace trasy

Pokud chcete vizualizovat trasu, vykreslíte ji na mapě pomocí rozhraní API Získat mapové obrázky .

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

Snímek obrazovky znázorňující mapu znázorňující trasu

V tomto kurzu jste zjistili, jak volat rozhraní REST API služby Azure Maps přímo a vizualizovat data Azure Maps pomocí Pythonu.

Další informace o rozhraních API služby Azure Maps používaných v tomto kurzu najdete tady:

Úplný seznam rozhraní REST API služby Azure Maps najdete v tématu Rozhraní REST API služby Azure Maps.

Další kroky