3.27. טיימר watchdog

טיימר watchdog הוא חלק חומרה שמאפס את המיקרו-בקר אם הסקריפט הרץ אי-פעם מפסיק לדגדג אותו מעת לעת. הסקריפט ”מאכיל“ את ה-watchdog ממקום שהוא יודע שמריץ קוד תקין; אם באג, תקיעה, או חריגה לא צפויה אי-פעם מונעים מהמצלמה להאכיל את ה-watchdog בתוך timeout מוגדר, השבב מאפס את עצמו והסקריפט מתחיל מחדש.

במכשיר פרוס ללא אדם בקרבת מקום שיבצע לו מחזור חשמל, זהו ההבדל בין באג חולף שמתאושש תוך שניות לבין לבנה שדורשת קריאת שירות.

A graph of a watchdog counter over time. The counter starts at the timeout value, drops linearly toward zero, and is reloaded to the timeout each time the script calls feed(). After three successful feed() calls, a fourth interval has no feed() and the counter reaches zero, triggering an MCU reset.

מונה ה-watchdog מתקתק מטה מה-timeout שלו. כל feed() טוען אותו מחדש; אם הוא מגיע לאפס, השבב מתאפס.

3.27.1. המחלקה machine.WDT

machine.WDT מפעילה את ה-watchdog וחושפת מתודה יחידה, feed(). ברגע שהופעל, לא ניתן לעצור את ה-watchdog – הדרכים היחידות החוצה הן להאכיל אותו בזמן או לתת לו לאפס את השבב:

from machine import WDT

wdt = WDT(timeout=2000)    # reset if not fed within 2 seconds

while True:
    do_work()
    wdt.feed()

ה-timeout הוא במילי-שניות. הערך הנכון תלוי בכמה זמן לוקחת האיטרציה הלגיטימית הארוכה ביותר של הלולאה הראשית, עם מרווח נוח – לולאה של 100 מ“ש עם timeout של 2 שניות יש לה שוליים בשפע לאיטרציה איטית ללא resets מטרידים.

3.27.2. היכן לקרוא ל-feed()

היכן ש-feed() נמצא הוא החלטת התכנון הקריטית; ה-watchdog תופס רק באגים בחלקי הקוד שאינם רצים בין האכלות.

  • קראו מהלולאה הראשית, בראש או בתחתית. התבנית הנפוצה ביותר. ה-watchdog תופס כל דבר שתוקע את הלולאה הראשית – deadlock, while אינסופי, התקן היקפי שלעולם אינו חוזר – ומאפס את השבב חזרה אל הלולאה.

  • אל תקראו ממטפל פסיקות. מטרת ה-watchdog היא לתפוס תקיעות בנתיב הקוד הרגיל. ISR שמופעל ללא קשר לכך שהלולאה הראשית תקועה ימשיך להאכיל watchdog שאמור היה להיות מופעל.

  • אל תקראו מתוך פעולה חוסמת ארוכה. בקשת רשת או קריאת חיישן שלוקחת עשר שניות היא בדיוק סוג התקיעה שה-watchdog אמור לתפוס. הצבת feed() בתוכה מבטלת את ההגנה.

הנחיה שעובדת עבור רוב התוכניות: האכילו פעם אחת לכל איטרציה של הלולאה הראשית, כשה-timeout מוגדר לכמה פעמים משך הלולאה הצפוי. אם איטרציה יחידה אכן זקוקה ללגיטימיות ליותר מה-timeout – שלב כיול מכוון, נאמר – בנו את אותו שלב כסדרה של מקטעים קטנים יותר עם feed() ביניהם, או שנו את ה-timeout עם timeout_ms() (היכן שנתמך) לפני הכניסה אליו.

3.27.3. זמינות

ה-watchdog חשוף ברוב מצלמות OpenMV אך לא בכולן – החומרה קיימת בכל רכיב, אך ה-API של Python עדיין אינו מחווט בכל מקום. בדקו את לוחות OpenMV או נסו לבנות WDT ולתפוס את ה-AttributeError אם אינו נתמך.

אפילו במצלמות שבהן WDT אינו חשוף, מכשיר שנפרס בשטח יכול להשתמש בשווה-ערך תוכנתי – משימה נפרדת או צעד בלולאה הראשית שמנטר התקדמות ומפעיל machine.reset() אם משהו נראה תקוע. הוא פחות עמיד מ-watchdog חומרתי (מטפל פסיקות תקוע יכול להפיל גם את הניטור התוכנתי) אך הוא מכסה את אותם מקרים ברמת היישום.