Технології, що лежать в основі Soundscape
Мета цієї сторінки — дати загальне розуміння того, як застосунок Soundscape працює зсередини. Вам не потрібно її читати, щоб користуватися застосунком, але є кілька причин, чому її було написано:
- Щоб допомогти зацікавленим новачкам розібратися, де знаходяться обмеження застосунку
- Щоб дати користувачам уявлення про те, що ще могло б бути можливим із новими функціями
- Щоб дати розробникам огляд функціональності застосунку
Є дві технології, які роблять застосунок можливим: GPS та дані OpenStreetMap. GPS дає нам гарне уявлення про те, де знаходиться телефон і де він був. Дані OpenStreetMap потім можна використати, щоб знайти, що знаходиться поблизу, і ми можемо описати це користувачеві.
Звукові маячки
Здебільшого це найпростіші речі для реалізації з технічної точки зору. Припускаючи, що ми маємо місцезнаходження телефону і напрямок телефону, ми можемо змінити аудіо маячка так, щоб воно звучало, ніби лунає з того напрямку. Ми використовуємо бібліотеку Steam Audio для позиціонування звуку, яка застосовує передавальні функції голови (head related transfer functions) для забезпечення найкращого можливого звукового позиціонування. Єдине, що ми ще робимо, — це змінюємо аудіо маячка так, щоб залежно від кута між напрямком користувача й розташуванням маячка відтворювався різний звук. Кути варіюються залежно від обраного маячка (Тактильний, Спалах, Пінг тощо), і деякі мають більшу кількість звуків, ніж інші. І це звукові маячки на найпростішому рівні.
Єдина додаткова складність — це припущення щодо місцезнаходження телефону й напрямку, у якому спрямований користувач. Розгляньмо їх по черзі.
Місцезнаходження
Місцезнаходження, яке повертає GPS, може мати досить велику похибку, і це залежить від того, яка частина неба видима для GPS телефону, і від того, скільки дерев та високих будівель відбивають GPS-сигнал на шляху до телефону.
Підхід, який ми обрали для фільтрації місцезнаходження, полягає у використанні так званого зіставлення з картою (map matching). Це передбачає, що користувач найімовірніше рухається вздовж нанесеного на карту шляху чи дороги — ми використовуємо термін «Шлях» (Way) для позначення всіх доріг, стежок та шляхів. Зіставлення з картою дивиться на те, де користувач був, і, використовуючи напрямок руху разом із локальними картографічними даними, обирає найімовірніше місцезнаходження на Шляху. Цей підхід враховує не лише похибки GPS, а й похибки в даних карти. Не всі Шляхи нанесені точно, тож вони теж мають похибки. Щоб визначити, який Шлях найімовірніше є тим, на якому перебуває користувач, алгоритм враховує:
- Наскільки близько Шлях розташований до GPS-місцезнаходження та до попередніх GPS-місцезнаходжень
- Напрямок руху — чи рухається користувач у тому ж напрямку, що й Шлях
- Чи можливо дістатися від останнього зіставленого з картою місцезнаходження до нового місцезнаходження через мережу Шляхів. Це потрібно, щоб виключити перемикання між Шляхами, які насправді не з’єднані, наприклад, один проходить над іншим через міст або під ним через тунель. Зіставлення з картою може вирішити, що поблизу немає Шляхів, або що воно не впевнене, на якому з них перебуває користувач, і в такому разі воно просто чекає на наступне GPS-місцезнаходження й намагається знову, поки не стане впевненим.
Напрямок
Є кілька напрямків, які ми відстежуємо в програмному забезпеченні:
- Напрямок, у якому спрямований телефон. Ми використовуємо його, коли телефон розблоковано й застосунок використовується, а також коли телефон заблоковано, за умови, що він тримається пласко екраном до неба. Це корисно мати на увазі, коли ви кладете телефон у сумку. Якщо його покласти пласко на дно сумки, що тримається вертикально, застосунок використовуватиме випадковий напрямок, у який спрямована ваша сумка.
- Напрямок, у якому рухається телефон.
- Напрямок від навушників із відстеженням руху голови. Наразі ми його не використовуємо, хоча застосунок на iOS його підтримував. У нас є відповідна технологія, щоб додати це в майбутньому.
Коли телефон заблоковано й він у сумці, застосунок використовуватиме напрямок руху. Однак, якщо користувач не рухається, тоді напрямок недоступний. Коли це трапляється, звукові маячки стають тихішими, щоб показати, що неможливо знати поточний напрямок маячка — користувач може повертатися, не змінюючи місцезнаходження.
Для деяких випадків використання напрямку в застосунку напрямок «прив’язується» до напрямку зіставленого з картою Шляху, тож якщо користувач іде приблизно в напрямку Шляху, тоді фактичний напрямок Шляху вважається правильним і використовується в цих обчисленнях.
Висновок
Хоча на перший погляд звукові маячки прості, використання зіставлення з картою для спроби усунути похибки місцезнаходження й напрямку привносить чималу кількість складності.
Дані карти
Дані карти, які використовує застосунок, майже всі походять із проєкту OpenStreetMap. Ми запускаємо сервер, який містить карту всього світу на кількох рівнях масштабування. Кожен рівень масштабування поділено на тайли. Рівень масштабування 0 містить 1 тайл, рівень 1 містить 4 тайли, рівень 2 містить 16 тайлів і так далі аж до рівня 14, який містить близько 268 мільйонів тайлів, щоб покрити планету. Кожен тайл містить кілька шарів, і кожен шар має точки, лінії та полігони, які можна намалювати, щоб створити графічну карту. Ця графічна карта — це те, що показується користувачеві в графічному інтерфейсі застосунку. Кожна точка, лінія та полігон мають метадані, які описують, що це таке. Це переважно безпосередньо з даних OpenStreetMap, тож лінія може бути footway, що є sidewalk, або road, що є minor
Дані перетворюються на графічну карту за допомогою «стилю», який має правила того, як малювати різні точки, лінії та полігони в кожному шарі, наприклад, як намалювати стежку, як намалювати ліс, як намалювати автобусну зупинку. Правила можуть змінюватися залежно від рівня масштабування, тому, коли ви наближаєте, дедалі більше точок і ліній стають видимими, які не видимі при віддаленні, наприклад, автобусні зупинки та стежки.
Змінюючи стиль, ми можемо змінювати вигляд карти в графічному інтерфейсі, звідки й походить «доступна карта», яку ми зараз випробовуємо. Вона прагне мати більший контраст та жирніші лінії й текст. Стиль вбудований у застосунок, тож нам не потрібно змінювати карту на сервері, щоб змінити її вигляд.
Але як ми використовуємо дані карти для аудіо?
Використання даних карти для аудіо
Наразі ми використовуємо відносно невелику частину картографічних даних для генерування звукового інтерфейсу користувача. Майже весь звуковий інтерфейс використовує лише тайли на максимальному рівні масштабування. Застосунок зшиває разом сітку 2 на 2 тайлів навколо того місця, де перебуває користувач, а потім дивиться лише на кілька шарів:
transportation— для всіх типів Шляхів, включно з дорогами, стежками, залізницями та трамвайними коліями.poi— об’єкти інтересу, наприклад, магазини, спортивні центри, лавки, поштові скриньки, автобусні зупинки тощо.building— це дляpoi, які нанесені на карту більше ніж просто як точка, наприклад, великі супермаркети чи ратуші.
Він з’єднує лінії та полігони через межі тайлів і перетворює всі Шляхи на з’єднані сегменти Шляхів та перехрестя. Це важливо, бо це дозволяє нам шукати вздовж Шляху, щоб дізнатися, куди ми можемо дістатися.
Усі розібрані дані також поміщаються у формат, зручний для пошуку, щоб застосунок міг легко знайти, які об’єкти карти знаходяться поблизу. На цьому етапі дані класифікуються за категоріями. Поточні категорії:
- Дороги
- Дороги та стежки (всі Шляхи)
- Перехрестя — точки, у яких Шляхи перетинаються
- Входи — це точки на будівлі, які позначені як вхід.
- Переходи — дорожні переходи
- Об’єкти інтересу (POI) — усі об’єкти інтересу
- Зупинки транспорту — автобусні зупинки, залізничні станції, трамвайні зупинки тощо.
- Підкатегорії POI:
- Інформація
- Об’єкт
- Місце
- Орієнтир
- Мобільність
- Безпека
- Населені пункти та підкатегорії (див. наступний розділ)
- Міста
- Містечка
- Села
- Хутори
Маючи це, для будь-якого місцезнаходження застосунок може легко знайти
- «Усі зупинки транспорту в межах 50 м» або
- «Найближче перехрестя попереду мене» або
- «Найближчий хутір, село, містечко чи місто»
Маючи це, створення звукових оповіщень — це просто питання запиту даних на основі поточного місцезнаходження й напрямку. Коли користувач рухається по сітці тайлів, вона оновлюється так, щоб центруватися навколо поточного місцезнаходження.
Більше даних
Одна з проблем нашої дуже локальної сітки даних карти полягає в тому, що це означає, що ми можемо «бачити» щонайбільше близько 1 км у будь-якому напрямку. Це нормально, коли ми описуємо те, що перед нами, але іноді ми хотіли б дати більше контексту. Головний приклад цього — коли застосунок використовується, а користувач не йде пішки.
Коли застосунок виявляє, що користувач рухається зі швидкістю понад 5 метрів на секунду, він перемикає те, як описує світ. Замість того, щоб оголошувати кожне перехрестя й POI, він робить оповіщення рідше й лише про найближчі дороги. Проблема в тому, що знати назву дороги не дуже корисно, якщо ви не знаєте, у якому містечку вона знаходиться.
Щоб спробувати вирішити це, ми тепер також розбираємо дані карти на нижчому рівні масштабування й видобуваємо дані з шару place. Він містить назви містечок, міст, районів, сіл тощо. Одна проблема з нанесенням таких речей на карту полягає в тому, що не завжди є очевидна межа між цими місцями. OpenStreetMap іноді має межі міст у своїй базі даних, але навіть коли це так, поки це доходить до нашої тайлової карти, ця інформація часто втрачається. Що ми маємо, так це місцезнаходження, де назви місць намальовані на карті. Вони класифікуються, а потім застосунок знаходить найближчий до користувача хутір, село, містечко чи місто й повідомляє про це.
Для багатьох міст фактична назва міста ніколи не буде оголошена, бо більшість міст поділені на менші підрозділи, як-от райони, але вони дають додатковий контекст, який дуже корисний. Просто пам’ятайте, що оскільки застосунок повідомляє, що ви знаходитеся поблизу вулиці в певному районі, це означає лише, що мітка для цього району є найближчою точкою, і вона може бути неправильною або навіть на іншому боці річки.
Більше контексту
Що більше контексту можна додати в описи, то краще, доки він залишається лаконічним і передбачуваним. Одна з проблем, яку ми побачили в описі перехресть, полягала в тому, що часто були задіяні «безіменні» Шляхи. Це Шляхи, які не мають назви. У картографічних даних це можуть бути просто колія, стежка чи службова дорога, але без більшого контексту це не дуже корисно в текстових описах. На щастя, ми можемо зробити краще, тож застосунок робить так: щоразу, коли він збирається оголосити безіменний Шлях, він дивиться, чи може з’ясувати для нього трохи більше контексту.
-
Це тротуар? У багатьох районах OpenStreetMap тротуари тепер нанесені на карту окремо від доріг. Зазвичай вони позначені як
sidewalk, але зазвичай не вказують, до якої дороги належить цей тротуар.Коли застосунок натрапляє на безіменний тротуар, він шукає дорогу, яка, на його думку, проходить поряд із ним, і використовує її для назви тротуару. Це виявляється дуже важливим для наших оповіщень. Замість того, щоб оголошувати кожне перехрестя тротуарів, коли ми рухаємося вздовж тротуару, оповіщення робляться так, ніби ми рухаємося вздовж пов’язаної дороги. Замість «Рух на захід вздовж стежки» ми маємо «Рух на захід вздовж Moor Road». Користувач перебуває на нанесеному на карту тротуарі, але опис має більше сенсу.
-
Чи закінчується він іменованим Шляхом? Дуже часто є пішохідні стежки, які з’єднують дві дороги. Дивлячись на обидва кінці стежки, ми можемо легко додати цей контекст, тож в одному напрямку це може бути «Стежка до Moor Road», а наближаючись з іншого кінця, це може бути «Стежка до Roselea Drive». Це робиться лише там, де стежка не розгалужується; якщо вона розгалужується на дві безіменні стежки, тоді ми не намагаємося додати цей контекст.
-
Чи закінчується він поблизу Мітки? Якщо безіменний Шлях починається або закінчується поблизу Мітки, вона використовується для його опису, наприклад, «Стежка до перехрестя біля великого дерева». Користувач може додавати Мітки де завгодно, і, додаючи Мітки вздовж мереж стежок, він може додати контекст до цілого маршруту.
-
Чи входить він до POI або виходить з нього? Якщо безіменний Шлях починається поза POI і закінчується всередині нього (або навпаки), тоді ми можемо додати цей контекст, наприклад, «Колія до Lennox Park».
-
Чи закінчується він поблизу Входу? Якщо безіменний Шлях починається або закінчується ближче до Входу, тоді ми можемо додати цей контекст, наприклад, «Службова дорога до Best Buy».
-
Чи закінчується він поблизу Орієнтира або Місця? Якщо безіменний Шлях починається або закінчується ближче до Орієнтира, тоді ми також можемо додати цей контекст, наприклад, «Службова дорога до St. Giles Cathedral».
-
Це глухий кут? Застосунок позначає як глухий кут будь-які безіменні Шляхи, які нікуди не ведуть.
-
Чи проходить він повз якісь сходи? Якщо безіменний Шлях проходить через міст, через тунель чи вгору/вниз сходами, тоді це відзначається й додається до контексту. Це окремо від позначення пункту призначення, тож можливий контекст на кшталт «Стежка через міст до Lennox Park».
Ці контексти додаються по порядку, тож можливо мати «Стежка до Park Lane через сходи» в одному напрямку й «Стежка до Lennox Park через сходи» в іншому напрямку. Іменована вулиця отримує пріоритет при виході, але парк використовується при вході до нього.
Майбутній контекст
Є різні додаткові контексти, які ми сподіваємося додати в майбутньому, зокрема:
- Контекст для Шляхів, що йдуть уздовж лінійних водних об’єктів, наприклад, «Стежка біля River Dee»
- Контекст для Шляхів, що йдуть уздовж краю водойм, «Стежка біля Milngavie reservoir»
- Контекст для Шляхів, що йдуть уздовж залізниць, наприклад, «Стежка біля залізниці». Це могло б навіть включати назву залізничної лінії
- Додати додатковий вміст до мостів і тунелів — над чим або під чим вони проходять, наприклад, «Стежка через міст над залізницею до Moor Road»
Звукові оповіщення
Тепер, коли у нас є дані карти у форматі, який ми можемо легко використовувати, генерування оповіщень справді є досить простим.
Оповіщення під час ходьби
Під час ходьби можуть відбуватися такі звукові оповіщення (у порядку пріоритету):
- Опис того, наскільки далеко знаходиться поточний пункт призначення
- Опис майбутнього перехрестя
- Опис 5 найближчих об’єктів інтересу
Усі оповіщення обмежені за частотою, щоб вони не повторювалися надто часто. Якщо користувач припиняє рухатися, оповіщення припиняються, і навіть під час руху оповіщення не повторюється на кожному новому GPS-місцезнаходженні. Частота, як у застосунку для iOS:
- Кожні 60 секунд для поточного пункту призначення
- Кожні 30 секунд для майбутнього перехрестя
- Кожні 60 секунд для об’єкта інтересу
Оповіщення можна фільтрувати через меню налаштувань, і, безперечно, є простір для розширення цієї поведінки.
Оповіщення під час швидшого руху
Під час руху зі швидкістю понад 5 метрів на секунду оповіщення про поточний пункт призначення все одно відбувається, але оповіщення про перехрестя й об’єкти інтересу замінюються оповіщенням, що описує приблизно, де перебуває користувач. Воно дає найближчу зупинку транспорту, об’єкт інтересу, який нас містить, наприклад, усередині великого парку, або найближчу дорогу й населений пункт. Вони використовують дані, описані раніше, і є очевидне місце для того, щоб дозволити налаштування цього в майбутньому.
Мітки та маршрути
Здебільшого мітки й маршрути — це просто функція інтерфейсу користувача, яка не залежить ні від GPS, ні насправді від даних карти. Мітки — це іменовані місця, які користувач хоче зберегти, а маршрути — це впорядкований список цих міток. Інтерфейс користувача для створення обох узято безпосередньо з версії для iOS.
Відтворення маршруту
Відтворення маршруту — це те, де маршрути оживають. Коли маршрут відтворюється, звуковий маячок створюється на першій мітці в маршруті. Щойно користувач наближається до цієї мітки, маршрут автоматично переміщує звуковий маячок до наступної мітки в маршруті. Якщо більше міток немає, тоді відтворення маршруту завершується.
Висновок
Сподіваємося, це дало певне розуміння того, як функціонує застосунок. Застосунок постійно розвивається на основі відгуків від користувачів, тож, будь ласка, зв’яжіться з нами, якщо є щось, що, на вашу думку, можна було б додати.