3.27. Сторожовий таймер¶
Сторожовий таймер – це апаратний елемент, який скидає мікроконтролер, якщо запущений скрипт перестає його регулярно «годувати». Скрипт «годує» сторожовий таймер з місця, де він знає, що виконується справний код; якщо помилка, зависання або несподіваний виняток не дозволяє камері нагодувати сторожовий таймер у межах налаштованого тайм-ауту, чіп скидає себе і скрипт починається заново.
На розгорнутому пристрої без людини поруч, щоб увімкнути його повторно, це різниця між минущою помилкою, яка відновлюється за секунди, та «цеглою», яка потребує виклику служби.
Лічильник сторожового таймера відраховує від свого тайм-ауту. Кожен feed() перезавантажує його; якщо він досягає нуля, чіп скидається.¶
3.27.1. Клас machine.WDT¶
machine.WDT вмикає сторожовий таймер і надає єдиний метод feed(). Після запуску сторожовий таймер неможливо зупинити – єдиний вихід – годувати його за розкладом або дати йому скинути чіп:
from machine import WDT
wdt = WDT(timeout=2000) # reset if not fed within 2 seconds
while True:
do_work()
wdt.feed()
timeout вказується в мілісекундах. Правильне значення залежить від того, скільки часу займає найтриваліша легітимна ітерація основного циклу, з хорошим запасом – цикл 100 мс з тайм-аутом 2 с має достатній запас для повільної ітерації без зайвих скидань.
3.27.2. Де викликати feed()¶
Місце виклику feed() – це критичне проектне рішення; сторожовий таймер відстежує лише помилки в тих частинах коду, які не виконуються між годуваннями.
Викликати з основного циклу, на початку або наприкінці. Найпоширеніший шаблон. Сторожовий таймер відловлює все, що блокує основний цикл – взаємоблокування, нескінченний
while, периферійний пристрій, що ніколи не повертається – та скидає чіп назад до циклу.Не викликати з обробника переривань. Мета сторожового таймера – відловлювати зависання у нормальному шляху коду. ISR, що спрацьовує незалежно від того, завис основний цикл чи ні, продовжував би годувати сторожовий таймер, який повинен спрацювати.
Не викликати всередині тривалої блокуючої операції. Мережевий запит або зчитування датчика, що займає десять секунд, – це саме той тип зависання, який повинен відловлювати сторожовий таймер. Розміщення
feed()всередині нього нівелює захист.
Правило, що підходить для більшості програм: годувати один раз за ітерацію основного циклу, встановивши тайм-аут у кілька разів більший за очікувану тривалість циклу. Якщо одна ітерація законно потребує більше часу, ніж тайм-аут – наприклад, навмисна фаза калібрування – структуруйте цю фазу як серію менших фрагментів з feed() між ними, або змініть тайм-аут за допомогою timeout_ms() (де підтримується) перед входом у неї.
3.27.3. Доступність¶
Сторожовий таймер доступний на більшості камер OpenMV, але не на всіх – апаратне забезпечення присутнє на кожній мікросхемі, але Python API ще не підключено всюди. Перевірте Плати OpenMV або спробуйте створити WDT та перехопіть AttributeError, якщо він не підтримується.
Навіть на камерах, де WDT недоступний, пристрій, розгорнутий у полі, може використовувати програмний еквівалент – окрему задачу або крок основного циклу, яка відстежує прогрес і запускає machine.reset(), якщо щось виглядає завислим. Це менш надійно, ніж апаратний сторожовий таймер (завислий обробник переривань може вивести з ладу і програмний монітор), але покриває ті ж випадки на рівні застосунку.