Поделиться через


Руководство по маршрутизации электрических транспортных средств с помощью Записных книжек Jupyter (Python)

Azure Maps — это портфель api геопространственных служб, интегрированных в Azure, что позволяет разработчикам создавать приложения с учетом расположения для различных сценариев, таких как IoT, мобильность и отслеживание ресурсов.

REST API Azure Maps поддерживают такие языки, как Python и R для геопространственного анализа данных и машинного обучения, предлагая надежные API маршрутизации для вычисления маршрутов на основе таких условий, как тип транспортного средства или доступная область.

В этом руководстве пользователи по маршрутизации электрических транспортных средств с помощью API Azure Maps, а также Jupyter Notebook в VS Code и Python, чтобы найти ближайшую зарядную станцию при низком уровне батареи.

При работе с этим руководством вы сделаете следующее:

  • Создайте и запустите Jupyter Notebook в VS Code.
  • Вызывать REST API Azure Maps с помощью Python.
  • Находить доступный диапазон с учетом модели использования электрического транспортного средства.
  • Поиск зарядных станций электрических транспортных средств в пределах доступного диапазона или изохрона.
  • Отрисовывать границы доступного диапазона и зарядные станции на карте.
  • Находить и визуализировать маршрут к ближайшей зарядной станции для электрических транспортных средств с учетом времени поездки.

Необходимые компоненты

Примечание.

Дополнительные сведения о проверке подлинности в Azure Maps см. в этой статье.

Установка пакетов на уровне проекта

Проект маршрутизации и доступного диапазона EV имеет зависимости от библиотек python aiohttp и IPython . Их можно установить в терминале Visual Studio с помощью pip:

pip install aiohttp
pip install ipython

Открытие Jupyter Notebook в Visual Studio Code

Затем скачайте записную книжку, используемую в этом руководстве:

  1. Откройте файл EVrouting.ipynb в репозитории AzureMapsJupyterSamples в GitHub.

  2. Нажмите кнопку "Скачать необработанный файл" в правом верхнем углу экрана, чтобы сохранить файл локально.

    Снимок экрана: скачивание файла Notebook с именем EVrouting.ipynb из репозитория GitHub.

  3. Откройте скачаемую записную книжку в Visual Studio Code, щелкнув правой кнопкой мыши файл, а затем выберите "Открыть с > помощью Visual Studio Code" или проводник VS Code.

Загрузка необходимых модулей и платформ

После добавления кода можно запустить ячейку с помощью значка запуска слева от ячейки, а выходные данные отображаются под ячейкой кода.

Выполните следующий скрипт, чтобы загрузить все необходимые модули и платформы.

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

Снимок экрана: скачивание первой ячейки в записной книжке, содержащей необходимые инструкции импорта с выделенной кнопкой запуска.

Запрос границы доступного диапазона

Компания по доставке пакетов управляет парком, включающим некоторые электрические автомобили. Эти транспортные средства необходимо заряжать в течение дня, не возвращаясь в склад. Когда оставшаяся плата снижается ниже часа, поиск проводится для поиска зарядных станций в пределах доступного диапазона. Затем получается информация о границе для диапазона этих зарядных станций.

Запрашивается routeType эко для балансировки экономики и скорости. Следующий сценарий вызывает API получения диапазона маршрутов службы маршрутизации Azure Maps, используя параметры, связанные с моделью потребления транспортного средства. Затем скрипт анализирует ответ на создание объекта многоугольника в формате GeoJSON, представляющего максимальный доступный диапазон автомобиля.

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

Поиск зарядных станций для электрических транспортных средств в пределах доступного диапазона

Определив доступный диапазон электрического транспортного средства (isochrone), можно найти зарядные станции в этой области.

В следующем скрипте используется API службы "Поиск после поиска Azure Maps Внутри геометрии" для поиска зарядных станций в максимально доступном диапазоне транспортного средства. Затем он анализирует ответ в массив доступных расположений.

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

Отрисовка зарядных станций и доступного диапазона на карте

Вызовите службу изображений карты Azure Maps, чтобы отобразить точки зарядки и максимальную доступную границу на статическом изображении карты, выполнив следующий скрипт:

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

Снимок экрана, на котором показан диапазон расположений.

Поиск оптимальной зарядной станции

Во-первых, определите все потенциальные зарядные станции в доступном диапазоне транспортного средства. Затем определите, к каким из этих станций можно получить доступ в ближайшее время.

Следующий скрипт вызываетAPI матричной маршрутизации Azure Maps. Он возвращает расположение транспортного средства, время путешествия и расстояние до каждой зарядной станции. Последующий скрипт анализирует этот ответ, чтобы определить ближайшие зарядные станции, которые можно достичь в наименьшее время.

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)

Расчет маршрута до ближайшей зарядной станции

После поиска ближайшей зарядной станции используйте API получения маршрутов для получения подробных направлений от текущего расположения транспортных средств. Запустите скрипт в следующей ячейке, чтобы создать и проанализировать объект GeoJSON, представляющий маршрут.

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

Визуализация маршрута

Чтобы визуализировать маршрут, используйте API получения изображения карты для отрисовки на карте.

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

Снимок экрана, на котором показана карта с маршрутом.

В рамках этого руководства вы узнали, как напрямую вызывать REST API Azure Maps и визуализировать данные Azure Maps с помощью Python.

Дополнительные сведения об API Azure Maps, используемых в этом руководстве, см. в следующих руководствах.

Полный список API-интерфейсов Azure Maps вы найдете на этой странице.

Следующие шаги