1
0
mirror of https://github.com/Rhinemann/IoT-Systems.git synced 2026-03-14 20:50:39 +02:00
2024-02-26 14:54:25 +02:00
..
2024-02-26 14:53:24 +02:00
2024-02-26 14:53:24 +02:00
2024-02-26 14:53:24 +02:00
2024-02-26 14:53:24 +02:00
2024-02-26 14:54:25 +02:00
2024-02-26 14:54:25 +02:00

Лабораторна робота №5

Тема

Візуалізація якості стану дорожнього покриття за допомогою фреймворку Kivy.

Мета

Розробити програму для візуалізації руху машини на дорозі та якості дороги за допомогою даних датчиків.

Підготовка робочого середовище, встановлення проекту

Клонування репозиторію

git clone git@git.comsys.kpi.ua:Diana_Tymoshenko/MapView.git
cd MapView

Створення віртуального середовища. Пакет virtualenv повинен бути встановлений в системі!

python -m venv ./venv

Активація середовища для linux

source ./venv/bin/activate

Активація середовища для windows

venv\Scripts\activate

Встановлення необхідних бібліотек

pip install kivy mapview

Завдання

Для початку необхідно отримати дані з датчиків: дані акселерометра знаходяться в файлі data.csv, GPS дані можна згенерувати за допомогою цього ресурсу та записати їх у csv файл.

Для відображення мапи використовується віджет Mapview для Kivy.

Для візуалізації руху машини можна використовувати MapMarker та рухати його відповідно GPS даних.

Для визначення стану дорожнього покриття потрібно накопичити певну кількість показників акселерометра (наприклад, 100) та проаналізувати їх певним чином на нерівності дороги (наприклад, великі та маленькі ями, бордюр). Для їх позначення на дорозі також використовувати маркери. Зображення для маркерів можна знайти в папці images.

Для створення та редагування маршруту машини на мапі використовуйте клас LineMapLayer та функцію add_point() з файлу lineMapLayer.py. Для додавання лінії на мапу mapview.add_layer() з mode="scatter".

Щоб створити затримку у відображення руху машини можна використовувати функцію kivy.clock.Clock.schedule_once().

Аналіз даних акселерометра

Будемо використовувати дані тільки по осі z. В стані спокою значення по осі z становить приблизно 16667 одиниць (або 1 g = 9.8 м/с²) (1 од = 0.00006 g).

Для аналізу нерівностей дороги можна використати функцію scipy.signal.find_peaks(), що знаходить локальні максимуми (піки) вхідних даних. Локальні максимуми вказують на наявність бордюрів або лежачих поліцейських, локальні мінімуми - на ями.

Для налаштування алгоритму знаходження максимумів використовуються такі параметри:

  • height: мінімальна висота піків.
  • distance: мінімальна відстань між піками.
  • prominence: мінімальна висота піку відносно його сусідів (помітність піку).
  • width: мінімальна ширина піку.

Важливо підібрати оптимальні параметри, щоб відсіяти шум та залишити тільки ті піки, що дійсно відображають якість дорожнього покриття. Для більшої наочності при підбиранні параметрів можна показники акселерометра та результати аналізу відобразити на графіку.

Для знаходження мінімуму треба відзеркалити дані (помножити на -1) та вказати негативне значення висоти.

За бажанням можна використовувати будь-який інший спосіб аналізу показників акселерометра.

Шаблон основного файлу проєкту

from kivy.app import App
from kivy_garden.mapview import MapMarker, MapView
from kivy.clock import Clock
from lineMapLayer import LineMapLayer


class MapViewApp(App):
    def __init__(self, **kwargs):
        super().__init__()
        # додати необхідні змінні

    def on_start(self):
        """
        Встановлює необхідні маркери, викликає функцію для оновлення мапи
        """

    def update(self, *args):
        """
        Викликається регулярно для оновлення мапи
        """

    def check_road_quality(self):
        """
        Аналізує дані акселерометра для подальшого визначення
        та відображення ям та лежачих поліцейських
        """

    def update_car_marker(self, point):
        """
        Оновлює відображення маркера машини на мапі
        :param point: GPS координати
        """

    def set_pothole_marker(self, point):
        """
        Встановлює маркер для ями
        :param point: GPS координати
        """

    def set_bump_marker(self, point):
        """
        Встановлює маркер для лежачого поліцейського
        :param point: GPS координати
        """

    def build(self):
        """
        Ініціалізує мапу MapView(zoom, lat, lon)
        :return: мапу
        """
        self.mapview = MapView()
        return self.mapview


if __name__ == '__main__':
    MapViewApp().run()

Ідеї для підвищення оцінки

Замість читання GPS координат з файлу можна використати утиліту Linux gpsfake.

gpsd — це програма, яка збирає дані з приймача GPS і надає дані через мережу потенційно декільком клієнтським програмам. Gpsd можна запускати як фонове завдання. gpsd надає сервіс шляхом прив'язки до порту 2947 за замовчуванням.

Але оскільки в нас немає приймача GPS, його роботу імітує gpsfake. Він відкриває PTY (псевдо-TTY), запускає екземпляр gpsd, який вважає, що підлегла сторона PTY є його пристроєм GPS, і передає вміст одного або кількох тестових файлів з координатами до приймача GPS.

Встановлення пакетів:

sudo apt install gpsd-clients

Щоб додати ці пакети у віртуальне середовище, відкрийте файл конфігурації venv/pyvenv.cfg та змініть рядок

include-system-site-packages = true

В програмі треба додати рядок

import gps

Використання gpsfake

Команда gpsfake запускається в терміналі, але при бажанні можна викликати її із програми за допомогою модулю subprocess.

gpsfake [OPTIONS] logfile

Опції, які можуть знадобитись:

  • -P port: встановлює порт прослуховування.
  • -c sec: встановлює затримку між реченнями в секундах. За замовчуванням дорівнює нулю (без затримки).
  • -1: logfile інтерпретується лише один раз, а не зациклюється.

logfile - це файл, що містить коодринати в будь-якому підтримуваному форматі, включаючи, зокрема, NMEA, SiRF, TSIP або Zodiac. Зокрема за допомогою цього ресурсу можна також згенерувати NMEA файл.

Використання gpsd

gpsd використовує JSON для зв’язку зі своїми клієнтами. Відповіді містять класи, а їх імена відповідають типу повідомлення NMEA. Важливо зазначити, що ці об’єкти JSON можуть бути неповними, якщо значення не визначено. Це може статися, коли GPS-приймач ще не отримав координати. У такому випадку поле просто опускається. Ви можете знайти повний список команд і більш детальний опис тут.

Більше про gpsd, його методи та приклади використання можна дізнатися тут.

Треба зазначити, що запускати gpsd треба в окремому потоці, бо він не може працювати в одному циклі подій Kivy.

Нижче наведений приклад коду для використання gpsd.

import gps
import threading

class GpsPoller(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.gpsd_client = gps.gps(port=port, mode=gps.WATCH_ENABLE)   #  вказати потрібний порт
        self.current_gps = None    # поточні координати
        self.running = True        

    def get_gps_data(self):
        return self.current_gps

    def run(self):
        while self.running:
            response = self.gpsd_client.next()
            print('response:', response)
            if response['class'] == 'DEVICE':
                is_activated = getattr(response, 'activated')
                if is_activated == 0:    # коли logfile з координатами був повністю прочитаний
                    self.running = False
                    return

            if response['class'] == 'TPV' and hasattr(response, 'lat'):
                print("Your position: lat = " + str(response.lat) + ", lon = " + str(response.lon))
                self.current_gps = [response.lat, response.lon]

Для роботи з цим класом треба створити його екземпляр в основному класі програми та розпочати діяльність потоку за допомогою методу start(), який викликає метод run(). Для отримання координат використовувати метод get_gps_data().

Зверніть увагу, що перші координати надходять не одразу, тож слідкуйте за тим, яку затримку треба поставити, щоб перша відповідь містила поля lat та lon. Також якщо при виклику команди gpsfake ви використовуєте затримку між реченнями в 1 секунду, то між кожним зчитуванням координат від gpsd треба поставити затримку в 3 секунди, бо для однієї пари координат використовується 3 речення з logfile.

Якщо при запуску програми виникає така помилка:

gpsd:ERROR: SER: device open of /dev/pts/4 failed: Permission denied - retrying read-only
gpsd:ERROR: SER: read-only device open of /dev/pts/4 failed: Permission denied
gpsd:ERROR: /dev/pts/4: device activation failed, freeing device.

Треба змінити режим профілю безпеки AppArmor для gpsd з режиму enforced на режим complain:

sudo apt install apparmor-utils
sudo aa-complain /usr/sbin/gpsd
sudo apparmor-status  # для перевірки режиму

Корисні посилання: