البرنامج التعليمي: طريق السيارات الكهربائية باستخدام Azure Notebooks (Python)

خرائط Azure هي مجموعة من واجهات برمجة التطبيقات APIs للخدمات الجغرافية المكانية التي تم دمجها في Azure. تمكن واجهات برمجة التطبيقات APIs هذه المطورين والمؤسسات و ISVs من تطوير التطبيقات، و IoT، وحلول التنقل، والخدمات اللوجستية، وتتبع الأصول.

يمكن استدعاء واجهات برمجة التطبيقات APIs REST لخرائط Azure من لغات مثل Python، وR؛ لتمكين تحليل البيانات الجغرافية المكانية، وسيناريوهات التعلم الآلي. يوفر خرائط Azure مجموعة قوية من واجهات برمجة التطبيقات للتوجيه التي تسمح للمستخدمين بحساب المسارات بين عدة نقاط بيانات. وتستند الحسابات إلى شروط مختلفة؛ مثل: نوع السيارة، أو المنطقة التي يمكن الوصول إليها.

في هذا البرنامج التعليمي، يمكنك مساعدة السائق الذي يقود سيارة كهربائية ذو بطارية منخفضة. يحتاج السائق إلى العثور على أقرب محطة شحن ممكنة من موقع السيارة.

في هذا البرنامج التعليمي، سوف نتعلم:

  • إنشاء ملف Jupyter Notebook وتشغيله على دفاتر ملاحظات Azure في السحابة.
  • اتصل بخرائط Azure واجهات REST APIs في Python.
  • ابحث عن نطاق يمكن الوصول إليه استنادًا إلى طراز استهلاك السيارة الكهربائية.
  • ابحث عن محطات لشحن السيارات الكهربائية ضمن النطاق الذي يمكن الوصول إليه، أو isochrone.
  • قم بعرض حدود النطاق القابلة للوصول، ومحطات الشحن على الخريطة.
  • ابحث واعرض مسار إلى أقرب محطة شحن للسيارات الكهربائية استنادًا إلى وقت القيادة.

المتطلبات الأساسية

إشعار

ولمزيد من المعلومات حول مصادقة Azure Maps، راجع إدارة المصادقة في Azure Maps.

إنشاء مشروع Azure Notebooks

لمتابعة هذا البرنامج التعليمي، تحتاجون إلى إنشاء مشروع Azure Notebooks، وتنزيل وتشغيل ملف Jupyter دفتر الملاحظات. يحتوي ملف Jupyter Notebook على رمز Python، الذي ينفذ السيناريو في هذا البرنامج التعليمي. لإنشاء مشروع Azure Notebooks، وتحميل مستند Jupyter Notebook إليه، قم بالخطوات التالية:

  1. انتقل إلى دفاتر ملاحظات Azure وسجل الدخول. لمزيد من المعلومات، راجع التشغيل السريع: تسجيل الدخول وتعيين معرف مستخدم.

  2. في أعلى صفحة ملف التعريف العام، حدد المشاريع الخاصة بي.

    The My Projects button

  3. في صفحة المشاريع الخاصة بي، حدد مشروع جديد.

    The New Project button

  4. في جزء إنشاء مشروع جديد، أدخل اسم المشروع ومعرف المشروع.

    The Create New Project pane

  5. حدد إنشاء.

  6. بعد إنشاء المشروع، قم بتنزيل ملف مستند Jupyter Notebook هذا من مستودع دفتر ملاحظات خرائط Azure Jupyter.

  7. في قائمة المشاريع في صفحة المشاريع الخاصة بي، حدد مشروعك، ثم حدد تحميل لتحميل ملف مستند Jupyter Notebook.

    upload Jupyter Notebook

  8. قم بتحميل الملف من الكمبيوتر، ثم حدد تم.

  9. بعد انتهاء التحميل بنجاح، يتم عرض الملف على صفحة المشروع الخاصة بكم. انقر نقرًا مزدوجًا فوق الملف لفتحه كـ Jupyter Notebook.

حاول فهم الوظيفة التي يتم تنفيذها في ملف Jupyter Notebook. قم بتشغيل التعليمات البرمجية في ملف Jupyter Notebook خلية واحدة في كل مرة. يمكنك تشغيل التعليمات البرمجية في كل خلية عن طريق تحديد الزر Run في أعلى تطبيق Jupyter Notebook.

The Run button

تثبيت حزم مستوى المشروع

لتشغيل التعليمات البرمجية في Jupyter Notebook، يرجى تثبيت الحزم على مستوى المشروع عن طريق تنفيذ الخطوات التالية:

  1. قم بتنزيل الملف requirements.txt من مستودع دفتر ملاحظات خرائط Azure Jupyter، ثم قم بتحميله إلى مشروعك.

  2. في لوحة معلومات المشروع، حدد Project الإعدادات.

  3. في جزء Project الإعدادات، حدد علامة التبويب البيئة، ثم حدد إضافة.

  4. ضمن "Environment Setup Steps"، قم بما يلي: أ. في القائمة المنسدلة الأولى، حدد Requirements.txt.
    ب. في القائمة المنسدلة الثانية، حدد الملف requirements.txt.
    جـ. في القائمة المنسدلة الثالثة، حدد Python Version 3.6 كإصدارك.

  5. حدد حفظ.

    Install packages

تحميل الوحدات النمطية، والأطر المطلوبة

لتحميل كافة الوحدات النمطية المطلوبة، وأطر العمل، قم بتشغيل البرنامج النصي التالي.

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

قم بطلب حدود النطاق القابلة للوصول

شركة توصيل الطرود لديها بعض السيارات الكهربائية في أسطولها. خلال النهار، تحتاج السيارات الكهربائية إلى إعادة شحنها دون الحاجة إلى العودة إلى المستودع. في كل مرة تنخفض فيها الشحنة المتبقية إلى أقل من ساعة، تبحثون عن مجموعة من محطات الشحن التي تقع ضمن نطاق يمكن الوصول إليه. في الأساس، يمكنك البحث عن محطة شحن عندما تكون البطارية منخفضة الشحن. وتحصل على معلومات الحدود لهذه المجموعة من محطات الشحن.

نظرا لأن الشركة تفضل استخدام المسارات التي تتطلب توازنا في الاقتصاد والسرعة، فإن routeType المطلوب هو eco. يستدعي البرنامج النصي التالي واجهة برمجة تطبيقات Get Route Range لخدمة التوجيه خرائط Azure. ويستخدم معلمات لنموذج استهلاك السيارة. ثم يقوم البرنامج النصي بتحليل الاستجابة لإنشاء كائن مضلع لتنسيق 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) للسيارة الكهربائية، يمكنك البحث عن محطات الشحن ضمن هذا النطاق.

يستدعي البرنامج النصي التالي خرائط Azure Post Search Inside Geometry API. وهي تبحث عن محطات شحن للسيارة الكهربائية، ضمن حدود الحد الأقصى لنطاق السيارة الذي يمكن الوصول إليه. ثم يقوم البرنامج النصي بتحليل الاستجابة إلى مصفوفة من المواقع التي يمكن الوصول إليها.

للبحث عن محطات شحن السيارات الكهربائية ضمن النطاق الذي يمكن الوصول إليه، قم بتشغيل البرنامج النصي التالي:

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

تحميل النطاق القابل للوصول ونقاط الشحن

من المفيد تصور محطات الشحن والحد الأقصى للنطاق الذي يمكن الوصول إليه من السيارة الكهربائية على الخريطة. اتبع الخطوات الموضحة في مقالة كيفية إنشاء سجل البيانات لتحميل بيانات الحدود وبيانات محطات الشحن ككائنات geojson إلى حساب تخزين Azure الخاص بك ثم تسجيلها في حساب خرائط Azure الخاص بك. تأكد من تدوين قيمة المعرف الفريد (udid)، ستحتاج إليها. udid هي الطريقة التي تشير بها إلى كائنات geojson التي قمت بتحميلها إلى حساب تخزين Azure الخاص بك من التعليمات البرمجية المصدر.

قم بعرض محطات الشحن والنطاق القابل للوصول على الخريطة

بعد تحميل البيانات إلى حساب تخزين Azure، اتصل بخدمة خرائط Azure Get Map Image. يتم استخدام هذه الخدمة لتقديم نقاط الشحن والحد الأقصى؛ للوصول على صورة الخريطة الثابتة عن طريق تشغيل البرنامج النصي التالي:

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

path = "lcff3333|lw3|la0.80|fa0.35||udid-{}".format(rangeUdid)
pins = "custom|an15 53||udid-{}||https://raw.githubusercontent.com/Azure-Samples/AzureMapsCodeSamples/master/AzureMapsCodeSamples/Common/images/icons/ev_pin.png".format(poiUdid)

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

A map showing the location range

العثور على محطة الشحن الأمثل

أولاً، يجب تحديد جميع محطات الشحن المحتملة ضمن النطاق الذي يمكن الوصول إليه. ثم، يجب معرفة أي منها يمكن الوصول إليها في الحد الأدنى من الوقت.

يستدعي البرنامج النصي التالي واجهة برمجة تطبيقات توجيه مصفوفة خرائط Azure. وهو يعيد موقع المركبة المحدد، ووقت السفر، والمسافة إلى كل محطة شحن. يقوم البرنامج النصي في الخلية التالية بتوزيع الاستجابة لتحديد موقع أقرب محطة شحن يمكن الوصول إليها فيما يتعلق بالوقت.

للعثور على أقرب محطة شحن يمكن الوصول إليها التي يمكن الوصول إليها في أقل قدر من الوقت، قم بتشغيل البرنامج النصي في الخلية التالية:

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)

حساب المسار إلى أقرب محطة شحن

الآن بعد أن وجدت أقرب محطة شحن، يمكنك الاتصال بواجهة برمجة تطبيقات Get Route Directions لطلب المسار التفصيلي من الموقع الحالي للسيارة الكهربائية إلى محطة الشحن.

للحصول على المسار إلى محطة الشحن، وتحليل الاستجابة لإنشاء كائن 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
     }

عرض المسار

للمساعدة في تصور المسار، اتبع الخطوات الموضحة في مقالة كيفية إنشاء سجل البيانات لتحميل بيانات المسار ككائن geojson إلى حساب تخزين Azure الخاص بك ثم قم بتسجيله في حساب خرائط Azure الخاص بك. تأكد من تدوين قيمة المعرف الفريد (udid)، ستحتاج إليها. udid هي الطريقة التي تشير بها إلى كائنات geojson التي قمت بتحميلها إلى حساب تخزين Azure الخاص بك من التعليمات البرمجية المصدر. بعد ذلك، استدع خدمة العرض، احصل على Map Image API، لعرض المسار على الخريطة، وتصوره.

للحصول على صورة للمسار المقدم على الخريطة، قم بتشغيل البرنامج النصي التالي:

# Upload the route data to Azure Maps Data service .
routeUploadRequest = await session.post("https://atlas.microsoft.com/mapData?subscription-key={}&api-version=2.0&dataFormat=geojson".format(subscriptionKey), json = routeData)

udidRequestURI = routeUploadRequest.headers["Location"]+"&subscription-key={}".format(subscriptionKey)

while True:
    udidRequest = await (await session.get(udidRequestURI)).json()
    if 'udid' in udidRequest:
        break
    else:
        time.sleep(0.2)

udid = udidRequest["udid"]

destination = route[-1]

destination[1], destination[0] = destination[0], destination[1]

path = "lc0f6dd9|lw6||udid-{}".format(udid)
pins = "default|codb1818||{} {}|{} {}".format(str(currentLocation[1]),str(currentLocation[0]),destination[1],destination[0])


# Get boundaries for the bounding box.
minLat, maxLat = (float(destination[0]),currentLocation[0]) if float(destination[0])<currentLocation[0] else (currentLocation[0], float(destination[0]))
minLon, maxLon = (float(destination[1]),currentLocation[1]) if float(destination[1])<currentLocation[1] else (currentLocation[1], 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))

A map showing the route

في هذا البرنامج التعليمي، تعلمتم كيفية استدعاء واجهات برمجة التطبيقات REST APIs في خرائط Azure مباشرة، وعرض بيانات Azure الخرائط باستخدام Python.

لاستكشاف واجهات برمجة تطبيقات Azure Maps المستخدمة في هذا البرنامج التعليمي، راجع:

تنظيف الموارد

لا توجد موارد تتطلب التنظيف.

الخطوات التالية

لمعرفة المزيد حول Azure Notebooks، يرجى مراجعة: