Partager via


Tutoriel : Router les véhicules électriques avec Azure Notebooks (Python)

Azure Maps est un portefeuille d’API de service géospatial intégré à Azure, ce qui permet aux développeurs de créer des applications prenant en charge les emplacements pour différents scénarios tels que l’IoT, la mobilité et le suivi de ressources.

Les API REST d’Azure Maps prennent en charge des langages tels que Python et R pour l’analyse des données géospatiales et le Machine Learning, offrant des API de routage robustes pour calculer des itinéraires en fonction de conditions telles que le type de véhicule ou la zone accessible.

Ce tutoriel guide les utilisateurs dans le routage de véhicules électriques en utilisant l’API Azure Maps ainsi qu’Azure Notebooks et Python pour trouver la station de recharge la plus proche quand la batterie est faible.

Ce didacticiel présente les procédures suivantes :

  • Créer et exécuter un fichier Jupyter Notebook sur Azure Notebooks dans le cloud.
  • Appeler les API REST Azure Maps en Python.
  • Rechercher une zone accessible en fonction du modèle de consommation du véhicule électrique
  • Recherchez des stations de recharge de véhicule électrique dans la zone accessible ou isochrone.
  • Afficher la limite de la zone accessible et les bornes de recharge sur une carte
  • Rechercher et visualiser une route vers la borne de recharge de véhicule électrique la plus proche en temps de conduite.

Prérequis

Notes

Pour plus d’informations sur l’authentification dans Azure Maps, voir Gérer l’authentification dans Azure Maps.

Créer un projet Azure Notebooks

Pour suivre ce tutoriel, il est nécessaire de créer un projet Azure Notebooks, et de télécharger et exécuter le fichier Jupyter Notebook. Ce fichier contient du code Python qui illustre le scénario présenté dans ce tutoriel.

Effectuez les étapes suivantes pour créer un projet Azure Notebooks et charger le document Jupyter Notebook :

  1. Accédez à Azure Notebooks et connectez-vous.

  2. En haut de votre page de profil public, sélectionnez Mes projets.

    Bouton Mes projets

  3. Dans la page Mes projets, sélectionnez Nouveau projet.

    Bouton Nouveau projet

  4. Dans le panneau Créer un projet, entrez un nom et un identifiant de projet.

    Panneau Créer un projet

  5. Sélectionnez Create (Créer).

  6. Une fois que votre projet a été créé, téléchargez ce fichier de document Jupyter Notebook à partir du dépôt Azure Maps Jupyter Notebook.

  7. Dans la liste des projets de la page Mes projets, sélectionnez votre projet, puis sélectionnez Charger pour télécharger le fichier de document Jupyter Notebook.

    chargement de Jupyter Notebook

  8. Chargez le fichier à partir de votre ordinateur, puis sélectionnez Terminé.

  9. Une fois le chargement effectué, le fichier s’affiche dans la page de votre projet. Double-cliquez sur ce fichier pour l’ouvrir en tant que notebook Jupyter.

Familiarisez-vous avec les fonctionnalités implémentées dans le fichier Jupyter Notebook. Exécutez le code dans le notebook Jupyter une cellule à la fois en sélectionnant le bouton Exécuter situé en haut de l’application Jupyter Notebook.

Bouton Exécuter

Installer des packages au niveau du projet

Pour exécuter le code dans Jupyter Notebook, installez les packages au niveau du projet en effectuant ces étapes :

  1. Téléchargez le fichier requirements.txt à partir du dépôt Azure Maps Jupyter Notebook, puis chargez-le dans votre projet.

  2. Dans le tableau de bord du projet, sélectionnez Paramètres du projet.

  3. Dans le panneau Paramètres du projet, sélectionnez l’onglet Environnement, puis Ajouter.

  4. Sous Étapes de configuration de l’environnement, effectuez les opérations suivantes : a. Dans la première liste déroulante, sélectionnez Requirements.txt.
    b. Dans la deuxième liste déroulante, sélectionnez votre fichier Requirements.txt.
    c. Dans la troisième liste déroulante, sélectionnez la version de Python. La version 3.11 a été utilisée lors de la création de ce tutoriel.

  5. Cliquez sur Enregistrer.

    Installer des packages

Charger les modules et les frameworks nécessaires

Exécutez le script suivant pour charger tous les modules et frameworks requis.

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

Demander les limites de la zone accessible

Une compagnie de livraison de colis exploite une flotte qui comprend des véhicules électriques. Ces véhicules doivent être rechargés pendant la journée sans retourner à l’entrepôt. Quand la charge restante tombe en dessous d’une heure, une recherche est effectuée pour trouver des stations de recharge à une distance accessible. Les informations de limite pour la distance de ces stations de recharge sont ensuite obtenues.

Le routeType demandé est « éco » pour équilibrer l’économie et la vitesse. Le script suivant appelle l’API Get Route Range du service de routage Azure Maps, en utilisant des paramètres pour le modèle de consommation du véhicule. Le script analyse ensuite la réponse pour créer un objet de polygone au format GeoJSON, qui représente la distance maximale accessible par le véhicule.

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

Rechercher des bornes de recharge de véhicule électrique dans la zone accessible

Après avoir déterminé la distance accessible (isochrone) par le véhicule électrique, vous pouvez rechercher les stations de recharge dans cette zone.

Le script suivant utilise l’API Post Search Inside Geometry d’Azure Maps pour rechercher des stations de recharge dans la plage de distances maximale accessible par le véhicule. Il analyse ensuite la réponse dans un tableau de lieux accessibles.

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

Afficher les bornes de recharge et la zone accessible sur une carte

Appelez le service Get Map Image d’Azure Maps pour afficher les points de recharge et la limite maximale accessible sur l’image de carte statique en exécutant le script suivant :

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

Carte représentant la zone localisée

Rechercher la borne de recharge optimale

Tout d’abord, identifiez toutes les stations de recharge potentielles dans la zone accessible par le véhicule. Ensuite, déterminez quelles stations sont accessibles dans la plus courte période possible.

Le script suivant appelle l’API de routage par matrice d’Azure Maps. Elle retourne l’emplacement du véhicule, le temps de trajet et la distance jusqu’à chaque station de recharge. Le script suivant analyse cette réponse pour identifier la station de recharge la plus proche qui peut être atteinte en un minimum de temps.

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)

Calculer l’itinéraire jusqu’à la borne de recharge la plus proche

Après avoir localisé la station de recharge la plus proche, utilisez l’API Get Route Directions pour obtenir des instructions détaillées à partir de l’emplacement actuel des véhicules. Exécutez le script de la cellule suivante pour générer et analyser un objet GeoJSON représentant l’itinéraire.

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

Visualiser l’itinéraire

Pour visualiser l’itinéraire, utilisez l’API Get Map Image pour l’afficher sur la carte.

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

Carte indiquant l’itinéraire

Dans ce tutoriel, vous avez découvert comment appeler les API REST Azure Maps directement et comment visualiser les données Azure Maps avec Python.

Pour explorer les API Azure Maps qui sont utilisées dans ce tutoriel, consultez :

Étapes suivantes

Pour en savoir plus sur Azure Notebooks, consultez