У меня есть физический радар детектор — коробочка на стекле. И есть купленное приложение-антирадар. Что общего у них двух? В каждом чего-то не хватает. В одном не нравится одно, в другом другое. Годами я ловил себя на мысли, вот бы взять лучшее из обоих, а раздражающее просто не тащить.
В какой-то момент я перестал мечтать и сел писать своё. Наивно думая, что это несложно Ну что там, показывай точку из базы да пикай при подъезде. (Спойлер) Я ошибался почти в каждом своём предположении. Эта статья про то, как «тут же нечего делать» превратилось в фьюжн сенсоров, счисление пути в тоннелях, геодезию проездов и краудбазу с криптозащитой. И про то, чему меня научила каждая набитая шишка.
«УГОЛ ПОКРЫТИЯ» — И ПОЧЕМУ ЭТОГО МАЛО
Первая, самая наивная версия детектора работала в лоб. Есть камера в базе, есть мой курс, если камера в секторе передо мной, предупреждаем. Угол покрытия, сектор, всё логично.
Первая же трасса всё расставила по местам. На встречной полосе, за разделителем, стоят свои камеры, и мой узкий сектор их радостно ловил. Приложение орало на камеры, которые снимают встречный поток и до меня им нет дела. А расширишь сектор поуже, начнёшь пропускать свои на поворотах.
Стало понятно,что угол это слишком грубо. Камеру «мою» от «чужой» нельзя отличить одним сектором, тем более без карты дорог (а карты я принципиально не хотел, они тянут интернет, лицензии и мегабайты, а в дороге связь пропадает именно там, где нужнее всего).
Пришлось городить три независимых признака:
-
Коридор, который гнётся. Близко — угловой сектор, далеко — предел по боковому смещению в метрах (потому что на 400+ метрах угловой сектор шире соседней улицы). А в повороте коридор «гнётся» по гироскопу: смотрим не туда, куда торчит нос сейчас, а туда, где окажемся по дуге.
-
Подтверждение по сближению (CPA — точка наибольшего сближения). У камеры на твоей дороге расстояние сокращается почти со скоростью движения, а боковое смещение стягивается к нулю по мере подъезда. У параллельной улицы боковое стабильно большое. За короткое окно пути эти случаи уверенно расходятся.
-
Сторона (для трассы). Точка, стабильно левее линии движения за разделителем, — это встречная проезжая часть.
И бонусом, автокалибровка бокового сноса GPS. GPS почти всегда смещён вбок на пару метров, и снос каждый день разный. Но у меня есть бесплатный эталон, честный проезд камеры. В момент проезда истинный бок мал, а измеренный не равен текущему сносу. Несколько проездов, медиана с отсевом выбросов, и все боковые пороги становятся точнее. Живёт только в памяти поездки, потому что снос дрейфует.
Вот на этом моменте я и понял, что делаю не «просмотрщик базы», а обработку сигналов. И как-то втянулся.
КОГДА GPS ВРЁТ (а он врёт постоянно)
Чем дальше, тем яснее. Сырым данным GPS верить нельзя вообще.
Курс. GPS курс медленный, шумный и на малой скорости просто выдумывает. Стоишь на светофоре, а он показывает вращение. Гироскоп ловит повороты мгновенно и без задержки, но «плывёт». Классика — комплементарный фильтр: гироскоп ведёт быстрые повороты, GPS раз в секунду подтягивает абсолют и убирает дрейф. Тонкость, на которой я застрял, телефон в держателе лежит как угодно, а поворот машины это вращение вокруг вертикали. Значит, берём проекцию угловой скорости гироскопа на вектор гравитации, и получаем «поворот машины» независимо от того, как лежит телефон.
Скорость. GPS скорость запаздывает почти на секунду и пропадает в тоннеле, а там-то и стоят камеры. Добавил фьюжн с акселерометром. И тут загвоздка. Где в осях телефона «вперёд»? Крепление любое. Ось «вперёд» пришлось выучивать корреляцией, когда GPS фиксирует заметный разгон или торможение, горизонтальное ускорение этого момента и есть «вперёд». Дальше между фиксами и в тоннеле скорость честно интегрируется по ускорению. Тормозишь в темноте, и отсчёт до камеры замедляется правильно.
Телепорты. В городе GPS отражается от зданий и прыгает на десятки метров. И фильтр тут точка, до которой физически нельзя было доехать. Но если GPS реально «переехал» (после долгого тоннеля), прыжок принимается только когда его подтверждает второй согласный фикс.
ЗАХОТЕЛОСЬ УМНОГО — И ПОЯВИЛАСЬ ГЕОДЕЗИЯ ПРОЕЗДОВ
Когда база и физика более-менее заработали, захотелось чего-то, чего нет ни у кого. Так родилась геодезия проездов.
Идея простая, но интересная. У телефона нет глаз, и камеру на столбе он не видит. Зато он идеально видит свою траекторию. Каждый честный проезд оставляет точку, «вот где я был при проезде камеры». Один проезд — шум. Но десяток проездов, в разные дни, из разных полос, дают облако. И его устойчивый центр, это место где камера реально контролирует дорогу.
Тем же приёмом (медиана, отсев выбросов), что и калибровка сноса, только повёрнутым с телефона на камеру. Так лечится главная болезнь народных баз — точки, воткнутые в стороне от дороги. Ездишь мимо, и координата сама подтягивается к реальной траектории. И это уже твоё собственное измерение, а не переписанная чужая цифра.
ГЛАВНАЯ БОЛЬ: БАЗЫ У ВСЕХ ОДИНАКОВЫЕ И НЕ ИДЕАЛЬНЫЕ
Тут я дошёл до корня. Радар-детекторов вагон, но база почти у всех одна и та же, и она не идеальна. Координаты натыканы пальцем, направления перепутаны, у половины камер вообще не написано, куда они смотрят. Все просто читают один и тот же неинформативный файл.
Приложение работает из коробки на встроенной базе OpenStreetMap (открытая лицензия), это честный старт. Можно подключить и свои файлы базы, если ты их где-то собрал (модель «принеси своё», данные остаются у тебя). Но их качество, ровно та проблема, ради которой я всё и затеял. Поэтому главная ставка на свою базу, которую делают лучше сами водители.
В этой базе у каждой камеры есть биография. Кто добавил, сколько раз подтвердили, куда смотрит, с какой стороны стоит, когда последний раз её видели. Не просто точка, а анкета.
Дальше пошли уже продуктовые грабли, каждая из которых отдельный урок:
Спам. Как только даёшь людям добавлять камеры, кто-то захочет накидать мусора. Решение было простым. Камеру можно добавить только с телефона, физически находясь в этом месте. Плюс временные баны для тех, кто системно накидывает мусор (по паттерну из разных точек и разных голосующих, а не по одному «нет»).
Дубли. Две базы, два человека. Легко получить две «камеры» в одном месте. Приложение понимает, что это одна и та же камера, и не озвучивает дважды. Причём в приоритете — точка из нашей базы, она вернее. Чем больше пользователей добавляет и подтверждает, тем приятнее ездить. Свои данные вытесняют “не идеальные” импортированные.
Перпендикулярные камеры. Это вылезло уже когда своя база наполнилась. Едешь к перекрёстку, а на нём камера, которая снимает поперечный поток тех, кто едет слева направо. Ты проезжаешь её боком машины, ей до тебя нет дела, а приложение честно про неё говорит. Раздражает. Теперь если направление камеры в нашей базе достоверно известно и ты едешь поперёк её оси, то молчим. А если направление неизвестно (чужие базы, «не знаю»), то предупреждаем как раньше, на всякий случай. Эта фича заработает в полную силу, когда база наполнится анкетами, ставка на вырост.
МАГИЯ НАПРАВЛЕНИЯ (моя любимая мелочь)
Вот что мне самому нравится больше всего. Когда камеру заносят в базу правильно, приложение начинает понимать её в пространстве.
Пример. Добавили камеру, которая бьёт «в спину» — снимает уезжающих. Едешь как ехал — приложение скажет «в спину». А развернулся и поехал по встречной (для двусторонней камеры), то же самое поле теперь читается как «спереди». Одна запись в базе, две правды для двух направлений, и обе честные. Приложение само переворачивает анкету под того, кто едет. Единственное условие — чтобы камеру внесли верно при добавлении.
И визуальная изюминка. Во время анимации дороги, когда впереди камера, сбоку от полотна едет иконка камеры, и она движется на основании вашей скорости, плавно приближаясь, как настоящая. А когда своя база подрастёт, эта иконка будет ехать с той стороны, с которой камера реально стоит — слева или справа. Мелочь, а при взгляде на экран уже знаешь, куда смотреть на дороге.
БЭКЕНД И КРИПТОПРОВЕРКА СВОИМИ РУКАМИ
База живёт на Cloudflare Worker + D1 (SQLite на edge). Голос за камеру, кластеризация по расстоянию, созревание до доверенной по нетто подтверждениям, скрытие по консенсусу.
Но самое интересное, как убедиться, что голос пришёл от настоящего экземпляра приложения на реальном устройстве, а не от скрипта. Apple даёт для этого App Attest: криптоключ в Secure Enclave, заверенный Apple. Проблема — проверять его надо на сервере, а на воркере нет готовых библиотек. Пришлось написать проверку с нуля на голом WebCrypto, минимальный декодер CBOR, минимальный парсер X.509/DER, проверка цепочки сертификатов до корневого CA Apple, сверка счётчика (анти-реплей), и пер-запросная проверка ECDSA-подписи над телом каждого голоса. Отдельный квест на пару дней — зато накрутить базу без реального устройства практически невозможно.
ЗВУК, ОЗВУЧКА И ОДНА НЕСБЫВШАЯСЯ ХОТЕЛКА
Звук хотелось «по-навигаторски». Музыка играет, на время предупреждения мягко приглушается и возвращается без щелчков и без съеденного первого слога. Секрет — держать аудио-сессию активной всю поездку, а приглушение включать переключением категории на живой сессии. Плюс поздняя привязка дистанции: «Камера, шестьдесят, через триста метров» собирается из кусочков, и «триста» подставляется в последний момент по живому расстоянию.
А была и несбывшаяся хотелка. Я хотел озвучку голосами, как у любимых студий перевода сериалов. Написал им. На удивление ответ получил в этот же вечер. Озвученная сумма для бесплатного проекта оказалось предсказуемо большой(относительно), и вкладываться в это пока не вижу смысла. Поэтому сделал по-другому, можно подключить свою озвучку, записать файлы самому. Или например сгенерировать нейросетью для личного пользования, положить папку и импортировать. Каждый соберёт голос под себя.
ДИЗАЙН НЕ ПОД КОПИРКУ
Отдельно пришлось поломать голову над внешним видом. Открываешь любой антирадар — и они как под копирку. Хотелось своего. Ночная сцена дороги, знак с «дыханием» в такт приближению, тёплое зарево, срочная виньетка по краям экрана, когда превышаешь у камеры (её ловит боковое зрение, не отрывая взгляд от дороги). Не берусь судить, получилось ли идеально, но точно получилось не как у всех,и это уже была отдельная маленькая победа.
ЧТО Я НЕ СДЕЛАЛ И ПОЧЕМУ
CarPlay. Честно, очень хотелось бы вывести детектор на экран машины. Но тут упираешься в правила Apple. CarPlay открыт навигаторам с построением маршрутов, а «просто радар-детектор» туда, скорее всего, не пустят. Чтобы получить статус навигации, надо делать полноценные карты и маршруты, а это отдельный огромный пласт работы, несопоставимый с самим детектором, и не факт, что оправданный ради него одного. Полноценный создание в одиночку — задача, которую я сейчас честно боюсь не потянуть. Разрешение у Apple я наверное всё равно попробую запросить, за спрос денег не берут, но иллюзий не строю.
ФИНАЛ
Я начинал с наивного «да что там делать» и с раздражения, что у меня два устройства для одного действия(поездки без штрафов), и в каждом чего-то не хватает. А закончил приложением, которое ведёт цель по физике, чинит за GPS его враньё, держится в тоннеле по акселерометру, само калибрует боковой снос, отличает свою камеру от встречной и с каждым проездом делает базу точнее.
Оно бесплатное, без рекламы, работает офлайн, данные остаются на телефоне. Это помощник, а не гарантия — он не заменяет внимание за рулём. Но с ним спокойнее знаешь про камеру заранее и успеваешь плавно сбросить, без внезапных писем со штрафами. А главное, чем больше людей добавляют камеры правильно, тем приятнее ездить всем. База растёт вместе с нами.
Doroga : радар-детектор в AppStore
ссылка на оригинал статьи https://habr.com/ru/articles/1058712/