Создаём систему электронного хронометража гонок
По будням, я уже 17 лет занимаюсь разработкой корпоративного софта, у меня было много разных хобби, но в итоге нашёл то, что держит уже 5 лет и не собирается отпускать. С 2013 года большую часть свободного времени я посвящаю мотокроссу и эндуро на внедорожных мотоциклах, в том числе регулярно участвовал в любительских соревнованиях. После неудачного дропа в июне 2017 года я оказался в больнице с полным переломом правой плечевой кости. Вышел из больницы, пришёл в себя и стало ясно, что ездить не получится ещё месяца два — три, а привычка к активной деятельности осталась. Тогда и решил, что надо попробовать самому организовать гонку для своих друзей. С технической точки зрения меня интересовал хронометраж, о том как я делаю собственную систему и провожу гонки читайте под катом.
В течение месяца вечерами написал первую версию судейской программы. Для реализации использовал C# и WPF, просто потому что их я лучше знаю и не нужно тратить время на изучение документации. В программе можно было записать участников со стартовыми номерами, разбить на классы и заезды. Во время гонки нужно было успевать руками вбивать номер участника, который едет через финишную черту. Всё работало хорошо, а учитывая небольшое количество участников в первой гонке (около 40 человек) посчитать всех руками было несложно.
Однако, как программисту мне хотелось большей автоматизации, не люблю ручную рутинную работу, к тому же записать руками заезд с сотней участников уже довольно трудно. В итоге в 2017 году провел ещё один этап, где было уже 3 отдельных класса и более ста участников, мероприятие прошло достаточно успешно и было принято решение к следующему сезону использовать электронную засечку.
На рисунке современная версия программы с поддержкой RFID и дистанционного управления со смартфона. В первой версии было гораздо меньше элементов.
Конечно эта тема не новая, есть много готовых вариантов, но большинство из них не очень устраивало по цене. Например, профессиональная система гоночного хронометража от итальянской фирмы AMB стоит примерно 13000€ и имеет в комплекте 20 прокатных транспондеров. Каждый дополнительный чип стоит 100€ и они одноразовые, то есть через 3–5 лет, когда в них умрет аккумулятор, его не заменить штатным способом. В остальном система отличная, используется на всех мировых гонках, имеет точность до тысячных долей секунды и так далее. Для хоббиста, который организует гонки для друзей в свободное время эта система не подходит. Также я нашел много готовых систем хронометража марафонов, триатлонов и других подобных соревнований. Системы использовали RFID метки. Но там смущала специфика — люди финишируют марафон в лучшем случае на скорости 20 км/ч, а в мотокроссе принято давать финиш по самому большому трамплину, на который заходят на скорости 70–80 км/ч. Зато цена RFID метки около 11 рублей за штуку позволяла раздавать их в любом количестве.
Вообще, RFID технология изначально не предназначена для засечки гонок, если почитать спецификации чипов и ридеров, можно найти ограничения по скорости движения чипа относительно антенны в несколько метров в секунду. Но я знал, что подобная система уже много лет успешно применяется в известной гоночной серии xsr-moto.ru, в которой я сам много раз участвовал и имел на шлеме их RFID метки. Сергей Миндин — организатор той серии любезно поделился информацией и указал мне на сайт motosponder.com, где он приобрел свою засечку.
Это помогло определиться с выбором первого ридера — Alien Technology F800, потому что я точно знал, что он будет работать в нужных мне условиях. Кроме Alien я рассматривал Imping Speedway Revolution R420 и глядя на качество SDK и документации собирался купить его. Но в итоге остановился на F800 как заведомо проверенном решении.
Ридер обошёлся мне примерно в 1600$, покупал в Москве, сразу докупил две антенны и 5 метровые ВЧ кабели к ним. Неприятным сюрпризом оказалась цена ВЧ кабелей. 10 метровый кабель будет стоить дороже самой антенны, а ещё его легко сломать, например перегнуть или раздавить ногой.
Решение: покупать готовый комплект оборудования и софта от motosponder за 3500$ дорого и не спортивно. Надо купить только оборудование, которое обошлось примерно в 2200$, а софт написать самому. Чего там сложного может быть? :)
Глядя на цены выше возникает закономерный вопрос:, а нельзя ли было сэкономить? Купить китайский ридер, цены на которые начинаются от 200$ Такие мысли были, но ещё была мысль, что у меня сильно ограничено время, и важна стабильность итоговой конструкции и простота разработки. До этого я не имел никакого практического опыта работы с RFID и не представлял с какими физическими ограничениями могу столкнуться. Поэтому мысль о китайских ридерах была отложена, но не позабыта.
RFID — это общее название целого семейства технологий различающихся по частоте и протоколу обмена данными.
- LF RFID — килогерцовый диапазон, низкая дальность и скорость чтения.
- HF 14 Мгц — обычно это «магнитные» пропуска в здание, домофонные ключи, бесконтактные платежные карты, NFC в телефонах. В общем, очень распространенная частота, но радиус связи до одного метра. Опять же не подходит для моего случая. Однако я знаю одну отлично работающую систему хронометража построенную на смартфонах и карточках от метро. Только для отметки гонщика он должен остановиться и судья должен приложить телефон к метке.
- UHF ~840 — 930 MHz — диапазон, на котором построены все системы хронометража массовых мероприятий. В оптимальных условиях метки читаются на расстоянии более 10 метров, скорости передачи данных достаточно, чтобы считывать метки по 50 и более раз в секунду, волны этих частот не настолько сильно поглощаются водой, как у следующего диапазона.
- UHF 2.4 GHz — возможно я плохо искал, но я сделал вывод, что эта частота является изобретением китайцев, потому что такие ридеры я не нашел у брендовых производителей. В любом случае, я решил не использовать эту частоту, потому что она слишком хорошо глушится водой, грязью, туманом и другими помехами.
Чуть более подробно описание частот и стандартов можно почитать по следующей ссылке rfidcenter.ru/page/frequencies-ranges
И так, я сделал вывод, что лучший вариант для моего применения — это диапазон UHF в зависимости от региональных ограничений это будут частоты примерно от 840 до 930 МГц и количество каналов от 2 до 30.
Мой F800 предназначен для европейского региона и настроен на работу в диапазоне 865–867 Мгц. Вместе с ридером я купил несколько разных меток, все они имели характеристики дальнобойных по описанию производителя, конкретная дальность и скорость чтения обычно нигде не пишется, т.к. сильно зависит от условий. Я провёл довольно много экспериментов чтения разных меток, в разном количестве и конфигурации антенн. Вот сжатые выводы:
- На открытой местности если точно сориентировать метку на антенну, вполне реально получить стабильное чтение на расстоянии 10 метров.
- Форма поля у антенны похожа на каплю, поэтому самое уверенное чтение получается на расстоянии 3–5 метров от антенны — в самой широкой части капли. Конечно форма диаграммы направленности зависит от модели антенны, я применял плоские панельные антенны с заявленным усилением 10dbi, 60/65° antenna31.ru/? product=rfid-panelnaya-antenna-pa868–10-rhcp
- Антенны бывают круговой и линейной поляризации. При линейной поляризации дальность чтения значительно выше, но ориентация метки должна совпадать с ориентацией антенны.
- Все «дальнобойные» метки работают примерно одинаково. Тут нужно уточнить, что я использовал метки одного бренда — Alien, возможно они все на одном чипе.
- Включить максимальную мощность передачи далеко не всегда оптимальное решение. Дома в небольшой комнате из-за переотражений скорость чтения очень сильно падала. Тоже самое может случиться на открытом пространстве, если две антенны смотрят друг на друга, они будут работать как зеркала.
- Вообще с RFID больше проблем случается от слишком большой мощности и дальности чтения, чем наоборот. Если «светить» в поле на максимальной мощности можно получить много случайных чтений с большой площади (десятки квадратных метров). Поэтому важно регулировать мощность и расположение антенн таким образом, чтобы чтение проводилось на наименьшей площади.
- Скорость чтения меток зависит от их количества в поле зрения ридера. Капитанское заявление, но я изменил конкретные цифры для оптимальных условий:
- Одна метка — 50–70/сек
- 5 и более меток — 250–280/сек
- Примерно 280 чтений в секунду — это предел для любого количества меток в поле, и конечно, если меток будет несколько десятков, скорость сильно упадёт из-за коллизий
- Метка на реальном мотоцикле движущемся со скоростью более 80 км/ч читается, но не в любом положении, желательно, чтобы метка и антенна были ориентированы таким образом, чтобы смотреть немного друг на друга. Например антенна слегка направлена в сторону гонщика, а метка наклеена где-то на передней части мотоцикла. При меньших скоростях метка и антенна могут быть строго перпендикулярно трассе.
На данном этапе всё выглядело неплохо, 50 чтений в секунду, означали, что среднее время между чтениями 20 миллисекунд, но это тоже нужно было проверить. Программа для сбора статистики была дополнена расчетом разницы времени между чтениями, она выводила худшее, лучшее время и восемь долей измеренных в миллисекундах. Тут выяснилось, что читает ридер далеко не равномерно. Это объясняется протоколом, по нему ридер обязан прекращать вещание хотя бы на 10 миллисекунд каждые несколько секунд. Вот так выглядел тест для двух меток в поле:
- 44 мс — худшее
- 20 мс — десятый дециль
- 1 мс — лучшее
- 3.2 мс — среднее время
- 104 чтения в секунду
То есть за 5 тестовых секунд большая часть чтений шло с разрывом в одну миллисекунду, а потом тишина в 44 миллисекунды. Это неприятная особенность для гонок, за 44 миллисекунды при скорости 20 метров в секунду гонщик проезжает 80 сантиметров и в случае помех может просто проехать мимо антенны. Примерно такая ситуация и воспроизвелась в реальном тесте описанном выше. И решение тоже есть — направлять антенны в сторону гонщиков, тогда пространство, а значит и время для чтения сильно увеличивается. И конечно нужно добавлять запасные способы отслеживания гонщиков, например: запись видео, человек с бумажкой и карандашом, человек, который вводит номера в программу руками.
Одно дело считывать метки с антенной на столе, а другое в реальном заезде с гонщиков. Я рассматривал два основных варианта конфигурации линии финиша.
Первый — антенны расположены на штативах по бокам от трассы. В идеальном варианте, антенны вообще стоят только с одной стороны и «светят» поперек трассы. Но при этом расположение меток на гонщиках становится несимметричным, нельзя, например запустить заезд в обратную сторону. К тому же чтение только с одной стороны не так надёжно. Тогда нужно ставить антенны с обеих сторон трассы, чтобы они «светили» друг на друга. Это уже требует сооружения рамки над трассой, по которой будут проложены ВЧ кабели и даже в такой конфигурации остаётся проблема ширины трассы. Бывает так, что трасса шириной 8–10 метров, а с учётом запаса на установку штативов может получиться и 12–13 метров. На таком расстоянии легко могут случаться сбои чтения.
Второй вариант, проверенный за много лет motosponder и xsr-moto — установка антенн на рамке над трассой и направление их вниз. Метки нужно клеить на шлемы гонщиков или верхнюю часть туловища. В итоге получается, что расстояние от антенны до метки всегда будет не больше 1.5 метра (высота рамки 3 метра, но гонщик редко проходит финишную черту со шлемом на уровне земли). А большую ширину трассы можно немного урезать самой рамкой.
На данный момент я использую рамку шириной 6 метров с тремя антеннами, ее ширину можно увеличить дополнительной секцией до 8–9 метров. После этого потребуется уже 4 антенны, расположенные немного шире. По опыту двух гонок в 2018 году ширины в 6 метров вполне достаточно, если установить рамку на медленном участке трассы. Это же повышает вероятность чтения меток — убиваем сразу двух зайцев.
После того как с железом всё стало более менее понятно, пришло время собственно считать круги. На первый взгляд всё просто: создаём таблицу, где каждому гонщику присвоен идентификатор метки и записываем, каждый сигнал от ридера.
Почти так, но сигналы от ридера нужно фильтровать, ведь когда метка находится в поле зрения ридера, она считывается до пятидесяти раз в секунду. Также нужно учесть, что в редких случаях метки всё таки не читаются, поэтому программа засечки должна уметь получать данные в реальном времени от ридера, от оператора, который вводит номера вручную и позволять редактировать отметки уже после окончания заезда.
Данные, которые даёт ридер и оператор проходят через фильтр для дедупликации и превращается в дорожку номеров. Это одномерный массив номеров гонщиков, в том порядке в каком они пересекали линию финиша. Например: [1, 2, 3, 2, 3, 1]. Из такой дорожки можно увидеть, что гонщики прошли два круга, на первом круге позиции гонщиков были 1, 2, 3. Но на втором круге у номера первого случилась проблема и он оказался в конце. В итоге победил номер два, за ним номер три и потом номер один. Для расчёта финишного протокола используется именно порядок, а не временные метки. Это сделано для совместимости с классическим ручным хронометражём, когда судьи записывают дорожку номеров в тетрадку. Хотя такой функции пока нет, но легко внедрить загрузку дорожки номеров от дополнительного судьи. В результате подсчёта получается следующая таблица:
Эта статья описывает только небольшой кусочек опыта, который я получил за последние 1.5 года. Дальше хотелось бы рассказать о создании сайта для регистрации гонщиков и публикации результатов в режиме Live, разработке второй версии аппаратного комплекса засечки на базе китайского RFID модуля и Orange Pi, процессе подготовки трассы, организации массового мероприятия и о многом другом. Если тема интересна, оставляйте комментарии.
Проект открытый, значительная часть кода опубликована на github.com/maxbl4 остальное тоже скоро будет, надо только подчистить пароли и ключи API из кода :-) Если Вам интересно помочь развитию проекта, узнать что-то новое, например научиться гонять на мотоциклах, писать на .Net Core и Angular, обращайтесь. Стэк технологий на данный момент .Net 4.7, .Net Core 2.2, Docker, Angular 7.1, MySql 10.3