В этой заметке оставлю наработки по логике хронометража на основе радиоконструктора для взрослых Ардуино. Хронометраж нам нужен для тренировок. Самодельная омега Льва Иванова держит на трассе одного участника. На тренировках это приводило к очереди на старте, поэтому мы ставили хронометраж не всегда. В постановке задачи было сформулировано: одновременно (максимум) три участника на трассе и три индикатора времени. Пришлось повозиться с логикой.
Три индикатора показывают время только что финишировавшего участника (сверху) и двух предыдущих (с прокруткой вниз при каждом финише). Когда на трассе участник(и), на верхнем индикаторе мигает двоеточие, но время «не бежит», показывается результат предыдущего участника.
На трассе максимум один участник
Если на трассе программно разрешен только один участник, то логика обработки сигналов «Старт» и «Финиш» простая и надежная. А именно: кнопка «Старт» отключена пока участник не финишировал, а кнопка «Финиш» отключена пока участник не стартовал.
Конечно нужно еще предусмотреть «отсечку по превышению максимального времени прохождения трассы» на тот случай, если участник не финишировал. Так реализовано в омеге Льва Иванова. Если участник сошел и не пересек Финиш, то следующему нужно подождать до старта 40 секунд.
Такая логика удобно реализуется в Ардуино. Дело в том, что при нажатии кнопок в Ардуино не генерируется запускающий импульс. Плата просто все время опрашивает соответствующий цифровой вход. Когда кнопка нажата, Ардуино фиксирует, что состояние входа изменилось. И пока кнопка не отжата, то так и продолжает фиксировать. А так как опрос происходит гораздо чаще, чем время нажатия кнопки, то фиксируется как бы сразу серия стартов. Поэтому логический запрет на следующий старт, пока не нажата кнопка финиша сразу оставляет в программе только факт первого считывания нажатой кнопки. Конечно можно разобраться с кнопками разными способами, но логика «только один участник на трассе» делает все автоматически.
Кстати, три индикатора с прокруткой вниз (как табло в Аэропорте), это удобно и при логике «один участник» 🙂
На трассе максимум три участника
Переходим к трем участникам на трассе. Со стороны Финиша запрет может прийти только после старта трех участников, действующий на четвертого, желающего стартовать. Кроме этого, этому желающему нужно сосчитать число участников, которые уже едут, а это гораздо сложнее, чем как описано в предыдущем разделе, дождаться финиша одного участника. Помимо этого первые три участника «имеют право» стартовать один за другим, поэтому логический запрет на необходимую паузу придется «брать с потолка». Без такого запрета Ардуино может сосчитать все три сигнала «Старт» за время первого нажатия кнопки.
Таким образом, сразу приходится идти на неудобные ограничения. Первое — это пауза между стартами участников, второе — обслуживание этой паузы. Нужно как минимум предусмотреть «лампочку — Можно дать Старт», а лучше еще и звуковой сигнал. При этом, к сожалению, все равно найдутся участники, которые не поймут, что это за лампочка 🙁
Есть и другие сложности, в общем, приведу описание алгоритма «как есть».
Описание алгоритма
Константы и переменные
Задается необходимая пауза между стартами и светодиод «можно дать старт». Если участник все равно «рванет» через стартовую калитку, то его время измеряться не будет.
Управление логикой идет через кучу «флажков» — логических переменных. Это «Можно дать старт» для каждого из трех участников (участники пронумерованы как А, В, С) и «Участник на трассе» (для каждого из трех участников).
Для хранения времен, считываемых из внутреннего таймера Ардуино заведены ячейки: Время старта (для каждого из трех участников) и одно время финиша (поскольку финиширует всегда участник номер «А», об этом ниже).
При запуске программы все флажки сброшены (на трассе никого нет), кроме «Можно дать старт» участнику А.
Сброс DNF-Reset
Такой же сброс (как и при запуске программы) осуществляется в любое время при нажатии на кнопку DNF-Reset (Do Not Finished). То есть, если участник с трассы сошел, то нужно нажать на эту кнопку, желательно когда на трассе нет других участников. После этого программа снова будет ждать участника А (первого). Нужно отметить, что это гораздо более важная кнопка, чем аналог «времени отсечки» для случая с одним участником на трассе. При нескольких участниках, если один не финишировал, то программа припишет этот финиш следующему участнику и далее все «поплывет», поскольку старт будет браться от одного участника, а финиш от другого. Такую «чудо-кнопку» планирую разместить и на старте и в базовом блоке (про конфигурацию «железа» здесь: Хронометраж для горных лыж на Ардуино. Постановка задачи).
добавлено позже
По замечанию Александра Мистрюкова переделал логику. Теперь нажатие кнопки DNF обрабатывается в точности как Финиш, только без показа результата. Если на трассе уже находится несколько участников, то тогда можно сохранить результаты тех, которые едут за нефинишировавшим. То есть нажатие на кнопку DNF сбрасывает не всех участников, а только того, который должен был финишировать, но не финишировал. На всякий случай оставил и «Reset» (как и раньше сброс всех едущих участников) по длинному нажатию кнопки.
В основном цикле программа все время опрашивает, не нажаты ли кнопки. Про кнопку DNF-Reset уже написал. Далее про кнопку «Старт».
Обработка Стартов
Со стартовой кнопкой все более запутано, поскольку нажатие кнопки нужно разнести по участникам А, В, С, причем участников В или С может и не оказаться 🙂 При этом для организации обязательной паузы между стартами программе нужно проводить действия и без нажатия кнопок, а именно вычислять, не прошла ли эта пауза, если перед этим был дан старт.
Начнем с участника А, никаких пауз ему соблюдать не нужно, он стартует самый первый. Разрешение на старт ему дано при запуске программы. При нажатии кнопки старт идет обработка логики: сбросить ему флажок «Можно дать старт», считать из таймера Ардуино время старта, поставить флажок «Участник А на трассе» и выключить светодиод «Можно дать старт».
Участник А уехал на трассу, на кнопку старт пока никто не нажимает, хоть она и продолжает опрашиваться, светодиод не горит, стартовать участнику В нельзя. Если он стартанет, то есть нажмет на кнопку «Старт» (откроет стартовую калитку), то ничего не произойдет, поскольку не взведен флажок «Можно дать старт участнику В».
В основном цикле, в котором программа опрашивает, не нажаты ли кнопки, постоянно считывается текущее время из внутреннего таймера Ардуино. Это время сравнивается с временем старта участника А (который уже ушел на трассу) плюс необходимая пауза. Перед сравнением проверяется условие: участник А на трассе, а участник В не на трассе.
Как только считываемое время станет больше, то есть пауза выдержана, происходят действия: взводится флажок «Можно дать старт участнику В» и зажигается светодиод «Можно дать старт».
После этого участник В может стартовать, кнопка сработает. При нажатии кнопки Старт происходят действия: сбрасывается флажок «Можно дать старт участнику В», считывается время старта участника В, взводится флажок «Участник В на трассе» и гасится светодиод «Можно дать старт».
Далее в основном цикле идет подготовка к разрешению старта участнику С, при помощи проверки условия: едет участник В, но пока не едет участник С, текущее время больше, чем время старта участника В плюс необходимая пауза. Как только условие выполняется, взводится флажок «Можно дать старт участнику С» и зажигается светодиод «Можно дать старт».
Участник С может стартовать в удобное для него время, только чтобы на трассе пока еще находились участники А и В. Иначе он перестанет быть участником С (об этом ниже). После старта, флажок «Можно дать старт участнику С» сбрасывается, считывается время старта участника С, взводится флажок «Участник С на трассе» и гасится светодиод «Можно дать старт. Теперь уже гасится не на необходимую паузу, а пока не финиширует участник А, потому что на трассе не разрешено более трех участников.
На этом самая муторная для аккуратного прописывания часть закончена.
Финиш
Итак, участник А пересекает финиш, первым из трех. По другому и быть не может 🙂 Для срабатывания кнопки Финиш необходимо условие, чтобы хотя бы кто-нибудь ехал по трассе (осталось от подхода с одним участником на трассе, на всякий случай). Далее происходит простая обработка. Считывается время из внутреннего таймера Ардуино. Из него вычитается время старта участника А. Это разница (результат прохождения трассы) после необходимой обработки выводится на верхний индикатор. А то время которое (если) до этого было на верхнем индикаторе перемещается на средний, а время со среднего индикатора на нижний.
По данным участников В и С происходит сдвиг: данные В переписываются в А, С в В, а ячейки С обнуляются. То есть, с этого момента математически к финишу приближается снова участник А (только другой по-человечески 🙂 ). Точнее, переписываются такие данные: времена стартов, состояние флажков «Участник на трассе» и «Можно дать старт».
Приведенный алгоритм обслуживает, конечно и одного участника на трассе, и двух. И, если вдруг дойдет до этого на московских холмах, и трех участников одновременно. А четырех уже нет. Честно говоря, это и невозможно, не поместятся они на трассе 🙂
Здесь собраны все заметки по теме «Хронометраж для горных лыж на Ардуино».
Вадим Никитин
Приветствую. Очень внимательно слежу за данной темой, для меня она очень актуальна. У нас в Самаре тоже есть горнолыжка, периодически проводятся соревнования среди любителей. Кроме того, самим горнолыжным комплексом организованы так называемые тренировки — во время вечернего катания ставится трасса, по которой за небольшую плату можно ходить. Но на указанных тренировках отсутствует хронометраж. Хотелось бы тоже сделать подобную систему хронометража.
Хочу изложить свои мысли по поводу индикатора «Можно дать старт», который как Вы справедливо отметили могут понять не все. Предлагаю сделать его не в виде одного светодиода, а двух: красного и зеленого. Как цветовая система светофора, горит красный — нельзя стартовать, зеленый — вперед. Это будет более интуитивно понятно.
Второй момент, касающийся кнопки старт, выполненной в виде стартовой калитки. Дело в том, что после старта калитка «залипнет» и будет открыта (т.е. кнопка все время нажата) и не определено, когда она будет взведена в стартовое положение – во время выдержки паузы или после нее. При втором варианте после стартовой паузы отрытая калитка тут же запустит время очередного участника.
Может попробовать следующий алгоритм действий при старте. Добавить еще один флаг «Калитка» (0 – закрыта, 1 – открыта) который устанавливается по результатам опроса кнопки старт (калитки). Перед стартом участника флаг «Можно дать старт» устанавливается только при условии что флаг «Калитка» = 0 (т.е. калитка закрыта). Далее постоянно считывается кнопка старт, и если она нажата, то идет проверка:
— если в этот момент флаг «Калитка» = 0, то запускаем таймер, ставим флажок «Участник А на трассе», выключаем светодиод «Можно дать старт» и устанавливаем флаг «Калитка» = 1
— если же «Калитка» = 1, то ничего не делаем.
Таким образом ловим момент открытия калитки, игнорируя ее последующее положение в открытом виде.
Далее постоянно считывая кнопку старт, дожидаемся когда она становится не нажата (калитку закрыли), здесь опять:
— если в этот момент флаг «Калитка» = 1 (т.е. до этого момента была открыта) — устанавливаем флаг «Калитка» = 0, включаем светодиод «Можно дать старт»
— если же в этот момент флаг «Калитка» = 0, то ничего не делаем.
Опять поймали момент закрытия калитки.
И при такой логике не надо выдерживать паузу, её время заменяет время необходимое для взведения калитки в стартовое положение.
Надеюсь я не слишком сумбурно объяснил. ))
Роман, спасибо за мысли, очень вовремя и к месту 🙂 Насчет «светофора» на старте тоже думал, наверное так и сделаю. Решил дополнить светодиод «можно дать старт» пьезопищалкой, запрещающей старт. Но красный светодиод — классная идея. Поставлю и его. Насчет логики калитки предварительно считал примерно так же, обязательное прохождение через «отлипание» от крайнего положения. Но это позже. Основная логика, разобранная в этой заметке относится к базовому блоку. Стартовый модуль с калиткой по результатам логики, как Вы разобрали передаст на базовый блок готовую информацию по радиомодулю: участник стартовал.
Вадим, добрый день!
Удалось победить радиомодули? Я, пока железо не пришло, читаю теорию 🙂 Как я понял при получении инфы от передатчика, приемник отправляет пакет подтверждения, в который можно запихнуть и доп. инфу…
С уважением, Дмитрий.