בפוסט זה אציג את הטכניקות בהן השתמשתי ליצירת חיישן התראה אחורי למשאית צעצוע. מערכת זו מבוססת על חיישן אולטרה-סוני פשוט מדגם HC-SR04 ומיקרו-בקר ATtiny85, וכמו המערכות האמתיות לרכב, היא מציגה התראה ויזואלית על גבי שורה של נוריות LED צבעוניות. ראשית, הנה וידאו של המערכת בפעולה:
המערכת שבסרטון נבנתה בלחץ זמן, ולכן הקוד שלה מאולתר למדי (שלא לומר חפיף). זו הסיבה שאני מקדיש לה פוסט נפרד ולא כולל אותה בסדרת "הלו טייני", אף על פי שהחומרה וסביבת הפיתוח בהן השתמשתי מתאימות לשם.
תצוגת הלדים
כדי שהמערכת תהיה קומפקטית מספיק להתקנה על המשאית בלי להפריע לתפקוד התקין של הצעצוע, לא השתמשתי בארדואינו אלא ב-ATtiny85, שיש לו רק חמישה פינים נוחים לקלט/פלט. השאלה הראשונה היתה, אם כך, איך לנהל את שמונת הלדים (3 ירוקים + 3 כתומים + 2 אדומים) של תצוגת המרחק.
האפשרות הראשונה שעולה לראש היא כמובן ג'וק Serial-to-Parallel כלשהו, למשל מדגמי 74HC595. בעזרת שני קווי קלט בלבד – קו שעון וקו נתונים – אפשר "לדחוף" לתוכו שמונה ביטים, והוא יציג אותם בו-זמנית בקווי הפלט שלו. אבל לי היה רעיון אחר: לנצל ג'וק מונה עשרוני (מהסוג שחשבתי שאין הרבה מה לעשות איתו!)
הג'וק הזה אמנם מוציא בכל פעם פלט בקו אחד בלבד מתוך עשרה, אך אם אעשה זאת מספיק מהר, העין לא תבחין בהבהוב – ועל הדרך, אחסוך גם הרבה חשמל, כי בכל רגע נתון ידלוק רק לד יחיד, ולא שמונה במקרה הקיצוני. גם כאן צריך שני קווי קלט בלבד: קו למונה עצמו וקו איפוס, שיאפשר לי לאתחל את הספירה מתי שארצה וכך להפעיל את כמות הלדים הרצויה.
על התזמון של חיישן המרחק
הוויתור על הארדואינו, והבחירה להשתמש בסביבת הפיתוח Atmel Studio, הכריחו אותי לוותר גם על הפונקציה pulseIn, שבה משתמשים בכל הדוגמאות למתחילים של חיישנים אולטרה-סוניים. פונקציה נוחה זו מאזינה לפין קלט, ממתינה שיעבור למצב שבחרנו (HIGH או LOW), ואז מודדת במיליוניות השניה את הזמן שעובר עד שהפין חוזר למצב ההפוך. מכאן, חישוב המרחק בסנטימטרים על סמך מהירות הקול הוא פשוט מאד – מחלקים את התוצאה ב-59.
פין Echo של חיישן המרחק HC-SR04 נותן לנו בדיוק את הסיגנלים הדרושים. הוא עולה ל-5V מיד אחרי שליחת הצליל, ויורד בחזרה ל-0V כשהצליל החוזר נקלט, או כעבור 38 אלפיות השניה אם לא הגיע שום הד.
בדיקה "ידנית" של מצב פין קלט ב-ATtiny פשוטה למדי, באמצעות מניפולציית פורטים בסיסית. אבל איך לבצע את המדידה במיליוניות השניה? גם כאן, המחשבה הראשונה היא על טיימרים ופסיקות – נושאים שעוד נגיע אליהם בהמשך – אבל במחשבה שניה, מה זה משנה בכלל אם האור האדום יידלק כשמשאית הצעצוע במרחק שני סנטימטרים מהקיר, או שלושה? בשביל מה לטרוח עם מיליוניות שניה וחישובי סנטימטרים כשאפשר פשוט להסתמך, בהערכה גסה, על מהירות הפעולה של המיקרו-בקר עצמו?
הגדרתי את ה-ATtiny85 כך שיפעל עם שעון פנימי בתדר 8MHz. אם אני מריץ בקוד לולאה שמאזינה לפין הקלט, ובתוכה מגדיל מונה מטיפוס int (בן 16 ביטים), אפשר לשער, בגסות, שכל "סיבוב" של הלולאה לוקח בסביבות 8 מחזורי שעון, כלומר מיליונית השניה בקירוב. לכן, 59 "סיבובים" מקבילים לסנטימטר אחד. יש דרכים לבדוק זאת בדיוק, אבל שוב, אין צורך בדיוק רב מכיוון שהתוצאה הסופית עצמה אינה כפופה לאילוצים כאלה.
ההערכות הראשוניות שלי הסתברו בדיעבד כטובות, אבל במקום לספור סיבובים בלולאה, לחלק ואז לתרגם את התוצאה למספר הלדים שצריך להדליק, בחרתי בדרך ישירה יותר: ספירה לאחור.
הספירה לאחור
הרעיון של הספירה לאחור מתחיל מכך שיש גבול למרחקים שמעניינים אותי. כל מה שמעבר למרחק מסוים, נניח 24 ס"מ, חסר משמעות מבחינתי ואין שום טעם לחכות להד שמגיע ממכשולים רחוקים יותר. אז אני מתחיל את הספירה ב-1400 (שזה בערך 24 * 59) ויורד עד שהחיישן מודיע על הד חוזר או עד שהספירה מגיעה לאפס, המוקדם מביניהם. מכאן נובע שהמספר שאליו אגיע יהיה גדול יותר ככל שהמכשול קרוב יותר. כמו כן, שימו לב שככל שהמכשול קרוב יותר, אצטרך להדליק יותר לדים. רואים את הקשר?
אחרי מדידת המרחק, אני מאפס את הג'וק שאחראי על הלדים, ואז לוקח את המספר שהתקבל בתום המדידה, מקטין אותו בקפיצות של 200 (כי יש לי 1400-חלקי-200 לדים, לא כולל לד ה"אפס" הירוק שתמיד דולק) ושולח פולס לג'וק עם כל קפיצה, עד שהמספר קטן או שווה לאפס. בתזמון נכון, כל העסק נראה לעין רציף לגמרי.
הפרעות
אם הייתי משאיר את הקוד ככה, הייתי נתקל בבעיה. נניח שהמשאית נמצאת במרחק 25 ס"מ מהקיר. מכיוון שההד לא חזר תוך 1400 סיבובים (שהם כאמור 24 ס"מ), אני מדליק את לד האפס בלבד ומתחיל מדידה חדשה – אבל תוך 59 סיבובים לערך יגיע לחיישן ההד מהמדידה הקודמת! המערכת תחשוב שהיא במרחק סנטימטר אחד בלבד מהקיר, ואני אקבל התראה בהתאם.
הפתרון הוא לבצע מדידה אחת, לחזור על לולאת הדלקת הלדים שוב ושוב עד שעובר מספיק זמן כך שאדע בוודאות ששום הד לא יחזור, ורק אז למדוד שוב. כמה זה "מספיק זמן"? הזכרתי שהחיישן עצמו מפסיק את המדידה אחרי 38 אלפיות השניה, אז זה סדר הגודל.
למרות זאת, עדיין הציקה לי הפרעה קטנה שהופיעה רק בתנאים מסוימים מאד, ושלא הצלחתי להעלים בשום פנים. הסתבר שמקורה בהחזר מסתורי של צליל מהרצפה. החיישן כנראה מוקם נמוך מדי: כאשר המשאית מוחזקת באוויר, או שאני שם פיסת נייר בולטת קצת מתחת לחיישן, ההפרעה נעלמת. ככה זה כשעובדים עם העולם האמתי 🙂
מקור כוח
המערכת כולה מופעלת במתח של 5V, אך מקור החשמל הוא סוללת AA פשוטה של 1.5V. בין לבין נמצא ממיר מתח חמוד וזול שמצאתי באיביי (חפשו "1-5V USB charger boost converter"), שיועד במקור לטעינה של מוצרי USB. הוא מקבל מתח של 1 עד 5 וולט ומוציא 5V בחיבור USB נקבה סטנדרטי. בשביל ההתקנה הנוחה הלחמתי החוצה את חיבור ה-USB (זהירות, מדובר בחיבור עקשן). עם סוללה כזו, הזרם המרבי שהמודול מסוגל לספק מוגבל למשהו כמו 200 מיליאמפר או פחות, אך למערכת שלי זה די והותר.
הטעות הגדולה באמת שעשיתי היא שמרוב שמיהרתי, שכחתי להתקין מפסק הפעלה על הלוח, אז צריך להוציא את הסוללה עצמה בכל פעם שהילדים גומרים לשחק עם זה, אחרת היא תיגמר במשך הלילה…
לא קצת נמאס לך מהמונה הבינארי? אתה מנסה להיפתר ממנו בכל מחיר 🙂
בכללי פוסט ממש אהבתי את צורת החשיבה של הזמנים שבאמת יעילה ומתאימה בדיוק למקרה
להיפך, בכל פעם אני מגלה כמה הג'וק הזה עוד יותר גאוני… כבר התחלתי לחשוב על להזמין עוד חבילה 😉