refactor: change task
This commit is contained in:
parent
0c5954f96c
commit
b8db2fe6ee
@ -9,12 +9,7 @@
|
||||
|
||||
### Підготовка робочого середовище, встановлення проекту
|
||||
|
||||
Клонування репозиторію
|
||||
```
|
||||
git clone git@git.comsys.kpi.ua:Diana_Tymoshenko/MapView.git
|
||||
cd MapView
|
||||
```
|
||||
Створення віртуального середовища. Пакет virtualenv повинен бути встановлений в системі!
|
||||
Створення віртуального середовища
|
||||
|
||||
`python -m venv ./venv`
|
||||
|
||||
@ -28,49 +23,28 @@ cd MapView
|
||||
|
||||
Встановлення необхідних бібліотек
|
||||
|
||||
`pip install kivy mapview`
|
||||
`pip install -r requirements.txt`
|
||||
|
||||
### Завдання
|
||||
|
||||
Для початку необхідно отримати дані з датчиків: дані акселерометра знаходяться в файлі data.csv,
|
||||
GPS дані можна згенерувати за допомогою цього [ресурсу](https://www.nmeagen.org/) та записати їх у csv файл.
|
||||
|
||||
Для відображення мапи використовується віджет [Mapview](https://mapview.readthedocs.io/en/1.0.4/) для Kivy.
|
||||
|
||||
Для візуалізації руху машини можна використовувати MapMarker та рухати його відповідно GPS даних.
|
||||
|
||||
Для визначення стану дорожнього покриття потрібно накопичити певну кількість показників акселерометра (наприклад, 100) та
|
||||
проаналізувати їх певним чином на нерівності дороги (наприклад, великі та маленькі ями, бордюр).
|
||||
Для їх позначення на дорозі також використовувати маркери. Зображення для маркерів можна знайти в папці images.
|
||||
Для візуалізації руху машини можна використовувати MapMarker та рухати його відповідно GPS даних.
|
||||
Для позначення нерівностей на дорозі також використовувати маркери. Зображення для маркерів можна знайти в папці images.
|
||||
|
||||
Для створення та редагування маршруту машини на мапі використовуйте клас LineMapLayer та функцію
|
||||
`add_point()` з файлу lineMapLayer.py. Для додавання лінії на мапу – `mapview.add_layer()` з `mode="scatter"`.
|
||||
`add_point()` з файлу lineMapLayer.py. Додавання лінії на мапу:
|
||||
|
||||
Щоб створити затримку у відображення руху машини можна використовувати
|
||||
функцію `kivy.clock.Clock.schedule_once()`.
|
||||
```python
|
||||
map_layer = LineMapLayer()
|
||||
mapview.add_layer(map_layer, mode="scatter")
|
||||
```
|
||||
|
||||
### Аналіз даних акселерометра
|
||||
Щоб створити затримку при відображенні руху машини можна використовувати
|
||||
функцію `kivy.clock.Clock.schedule_once()` або `kivy.clock.Clock.schedule_interval()`.
|
||||
|
||||
Будемо використовувати дані тільки по осі z. В стані спокою значення по осі z становить
|
||||
приблизно 16667 одиниць (або 1 g = 9.8 м/с²) (1 од = 0.00006 g).
|
||||
|
||||
Для аналізу нерівностей дороги можна використати функцію `scipy.signal.find_peaks()`, що
|
||||
знаходить локальні максимуми (піки) вхідних даних. Локальні максимуми вказують на наявність
|
||||
бордюрів або лежачих поліцейських, локальні мінімуми - на ями.
|
||||
|
||||
Для налаштування алгоритму знаходження максимумів використовуються такі параметри:
|
||||
- `height`: мінімальна висота піків.
|
||||
- `distance`: мінімальна відстань між піками.
|
||||
- `prominence`: мінімальна висота піку відносно його сусідів (помітність піку).
|
||||
- `width`: мінімальна ширина піку.
|
||||
|
||||
Важливо підібрати оптимальні параметри, щоб відсіяти шум та залишити тільки ті піки, що дійсно відображають
|
||||
якість дорожнього покриття. Для більшої наочності при підбиранні параметрів можна показники акселерометра та
|
||||
результати аналізу відобразити на графіку.
|
||||
|
||||
Для знаходження мінімуму треба відзеркалити дані (помножити на -1) та вказати негативне значення висоти.
|
||||
|
||||
За бажанням можна використовувати будь-який інший спосіб аналізу показників акселерометра.
|
||||
Дані для відображення на мапі (координати та стан дороги) зчитуються з бази даних через вебсокет.
|
||||
Для їх отримання використовуйте функцію `get_new_points()` з datasource.py.
|
||||
|
||||
**Шаблон основного файлу проєкту**
|
||||
|
||||
@ -96,12 +70,6 @@ class MapViewApp(App):
|
||||
Викликається регулярно для оновлення мапи
|
||||
"""
|
||||
|
||||
def check_road_quality(self):
|
||||
"""
|
||||
Аналізує дані акселерометра для подальшого визначення
|
||||
та відображення ям та лежачих поліцейських
|
||||
"""
|
||||
|
||||
def update_car_marker(self, point):
|
||||
"""
|
||||
Оновлює відображення маркера машини на мапі
|
||||
@ -132,120 +100,3 @@ class MapViewApp(App):
|
||||
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. Зокрема за допомогою цього [ресурсу](https://www.nmeagen.org/)
|
||||
можна також згенерувати NMEA файл.
|
||||
|
||||
**Використання gpsd**
|
||||
|
||||
gpsd використовує JSON для зв’язку зі своїми клієнтами. Відповіді містять класи, а їх імена відповідають
|
||||
типу повідомлення NMEA. Важливо зазначити, що ці об’єкти JSON можуть бути неповними,
|
||||
якщо значення не визначено. Це може статися, коли GPS-приймач ще не отримав координати.
|
||||
У такому випадку поле просто опускається. Ви можете знайти повний список команд і більш
|
||||
детальний опис [тут](https://gpsd.gitlab.io/gpsd/gpsd_json.html).
|
||||
|
||||
Більше про gpsd, його методи та приклади використання можна дізнатися [тут](https://gpsd.io/client-howto.html).
|
||||
|
||||
Треба зазначити, що запускати gpsd треба в окремому потоці, бо він не може працювати в одному
|
||||
циклі подій Kivy.
|
||||
|
||||
Нижче наведений приклад коду для використання gpsd.
|
||||
|
||||
```python
|
||||
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 # для перевірки режиму
|
||||
```
|
||||
|
||||
### Корисні посилання:
|
||||
|
||||
- [Kivy](https://kivy.org/doc/stable/)
|
||||
- [Mapview](https://mapview.readthedocs.io/en/1.0.4/)
|
||||
- [scipy.signal.find_peaks](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks.html)
|
||||
- [gpsfake](https://gpsd.gitlab.io/gpsd/gpsfake.html)
|
||||
- [gpsd](https://gpsd.io/gpsd.html)
|
||||
- [threading](https://docs.python.org/uk/3/library/threading.html)
|
||||
@ -3,6 +3,7 @@ from kivy.app import App
|
||||
from kivy_garden.mapview import MapMarker, MapView
|
||||
from kivy.clock import Clock
|
||||
from lineMapLayer import LineMapLayer
|
||||
from datasource import Datasource
|
||||
|
||||
|
||||
class MapViewApp(App):
|
||||
@ -20,11 +21,6 @@ class MapViewApp(App):
|
||||
Викликається регулярно для оновлення мапи
|
||||
"""
|
||||
|
||||
def check_road_quality(self):
|
||||
"""
|
||||
Аналізує дані акселерометра для подальшого визначення
|
||||
та відображення ям та лежачих поліцейських
|
||||
"""
|
||||
|
||||
def update_car_marker(self, point):
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user