שעון יד למייקרים, שמבוסס על מיקרו-בקר ESP32 וכולל בין השאר מסך TFT וחיישן תאוצה, מהווה פלטפורמה מצוינת לפרויקט כחול-לבן של הרגע האחרון.
יום העצמאות השנה תפס אותי בהפתעה. עוד לא הספקתי להתרגל לרעיון שפסח, ופתאום אני מגלה שנותרו פחות משבועיים להשלים את הפרוייקט המייקרי המסורתי (נניח), ואפילו עוד אין לי רעיון. אלא שבקושי יומיים לפני זה הגיע בדואר הרכש המייקרי החדש – שעון היד עם השם הקליט LILYGO TTGO T-Watch-2020 V1. האם הוא יוכל להציל אותי?
קצת פרטים על השעון: הדגם הזה עולה בסביבות 120 ש"ח (תלוי איפה ומתי קונים), והוא אחד מסדרה קטנה של דגמים שמתיימרים להיות חלומו של כל מייקר. יש בו סוללה נטענת, מסך מגע צבעוני 1.54 אינץ', מד תאוצה, רכיב שעון זמן-אמתי, מנוע רטט ועוד דברים טובים, וכולם נשלטים על ידי מיקרו-בקר ESP32 שאפשר לתכנת מסביבת הפיתוח של ארדואינו, למשל, דרך כבל USB. האינטרנט הבטיח גם ספריות מוכנות לכל הפונקציות האלה, שזה בכלל נהדר אם רק רוצים לעשות דברים בזריזות בלי להמציא את כל הגלגלים מחדש.
השעון שוקל כ-52 גרם, טיפ-טיפה מסורבל ביחס לפרק היד שלי (אבל זה אינדיבידואלי כמובן). את הרצועה תכנן וייצר מישהו שבחיים לא הלך עם שעון יד, והכיסוי הזעיר של יציאת ה-USB לא נראה כאילו ישרוד זמן רב. אבל חוץ מזה, השעון באמת חמוד. כדי לתכנת אותו דרך סביבת הפיתוח של ארדואינו, צריך קודם כל להוסיף תמיכה בלוחות ESP32: בוחרים בתפריט File->Preferences, ואיפה שכתוב "Additional Boards Manager URLs" מוסיפים את השורה "https://dl.espressif.com/dl/package_esp32_dev_index.json" (בלי המרכאות). מאשרים ועוברים לתפריט Tools->Board->Board Manager, מוצאים בחלון שנפתח את ESP32 ובוחרים Install. זה לוקח זמן. בסיום, אם לא היו תקלות, לתפריט הלוחות תתווסף הקטגוריה "ESP32 Arduino" ובתוכה, אם מחפשים טוב כי היא לא ממוינת, אפשר למצוא את "TTGO T-Watch".
אחרי זה, כדאי מאוד להתקין את הספריות שנכתבו עבור השעונים. מורידים אותן מהקישור הזה ב-GitHub. ההתקנה האוטומטית של ספריות בארדואינו לא הצליחה להתמודד עם הקובץ, אך אחרי העתקה ידנית של התיקיות ממנו לתיקיית הספריות הרגילה זה הסתדר (הנתיב לשם מופיע גם כן ב-File->Preferences בסביבת הפיתוח, תחת השם Sketchbook location, ומשם צריך להיכנס ל-libraries). מאותו רגע זה היה רק עניין של לחפש דוגמאות ברשת ולהסתכל בקוד המקור של הספריות האלה, כדי להבין איך גורמים לדברים לפעול. ואכן, תוך זמן קצר הצלחתי לקבץ את כל חלקי הקוד הדרושים כדי לבנות תוכנית שהתקמפלה ונצרבה בהצלחה – קוד שכותב Hello world בלבן על מסך שחור. אגב, הקימפול והצריבה איטיים מאוד ביחס לקוד ארדואינו. צריך סבלנות.
עכשיו, מה עם יום העצמאות? סתם לצייר דגל על המסך זה משעמם, רציתי משהו דינמי יותר – ואם כבר, אז שייעזר במד התאוצה ויגיב לאוריינטציה של השעון עצמו. כדי לראות איזה מין מידע אני יכול לקבל, חיטטתי שוב בקטעי קוד וכתבתי תוכנית חדשה שמציגה בזמן אמת את מדדי ההטייה בשלושת הצירים. לשמחתי, הספרייה טיפלה בכל העיבודים הדרושים ונתנה לי מידע סופי ברור בטווח ערכים הגיוני לציר X (מקביל לרוחב של המסך), Y (גובה המסך) ו-Z (ניצב למישור של המסך).
בשלב זה נזכרתי באפקט חביב מדמואים של פעם – שדה כוכבים (Starfield), משהו שאמור להיראות כמו הנוף מחלון של חללית שטסה ממש, אבל ממש מהר. בגרסאות הפשוטות כל הכוכבים נעים באותו כיוון, על ציר X או Y בלבד, רק במהירויות שונות ובדרגות בהירות שונות (מהיר = בהיר), מה שגורם לאשליה של כוכבים קרובים ורחוקים. בווריאציות משוכללות יותר הכוכבים יכולים גם לנוע "פנימה" ו"החוצה" וליצור תחושה של טיסה במרחב תלת-ממדי ממש. אז הנה רעיון לפרויקט – שדה כוכבים שכיוון ה"תנועה" בו תואם למנח השעון, וכדי לטעון שזה קשור ליום העצמאות אצבע את הכוכבים עצמם בכחול ובלבן.
שדה הכוכבים כמובן אינו אינסופי בזיכרון המיקרו-בקר (או המחשב): מספר הכוכבים מוגבל, וכאשר כוכב כלשהו יוצא מהאזור הניתן-לצפייה, צריך להחזיר אותו איכשהו פנימה מהכיוון השני. כל כוכב מוגדר קודם כל באמצעות שלושה מספרים (מיקום X, Y, Z), ואליהם אפשר להוסיף מידע כמו צבע בסיס. אני בחרתי לעבוד עם מרחב וירטואלי בצורת קוביה, שהגבולות שלו הם בדיוק הגבולות של טיפוס הנתונים int16_t (או uint16_t לציר Z). כך, כוכבים "תועים" יחזרו תמיד פנימה פשוט כי ככה עובדים משתני int.
למסך (ברזולוציה 240×240) אין שום buffer, אז כדי למנוע ריצודים, המחיקה והציור של הכוכבים נעשים לכל אחד לפי התור. אחרי אתחול של מיקומי הכוכבים באופן אקראי, הלולאה הראשית בפסודו-קוד נראית בערך כך:
- אסוף מידע ממד התאוצה
- לכל כוכב:
- מחק אותו (מהמיקום הקודם על המסך)
- שנה את המיקום הווירטואלי שלו לפי הערכים ממד התאוצה
- חשב את המיקום על המסך לפי המיקום הווירטואלי ושיקולי פרספקטיבה
- צייר את הכוכב, בגוון שנקבע לפי צבע הבסיס ולפי המרחק בציר Z
צריך לשים לב למגבלה מסוימת שנוצרת בשיטה הזו. בהיטל עם פרספקטיבה, כוכבים רחוקים יותר יצוירו קרוב יותר למרכז המסך ולהיפך. לכן, כשממפים קוביה ווירטואלית למסך, אז או שחלק מהכוכבים הקרובים יהיו מחוץ לגבולות המסך, או שהכוכבים הרחוקים לא יגיעו לשולי המסך אלא ייעלמו/יופיעו קרוב יותר לאמצע. כיוון שהכוכבים הרחוקים הם גם פחות בהירים ופחות מושכים תשומת לב, רוב הסיכויים שצופה תמים לא ישים לב איפה בדיוק הם צצים או נעלמים, ולכן בחרתי באופציה השנייה.
אחרי מספר סבבים של בדיקות וכוונונים, הגעתי לתוצאה שרציתי: כמאתיים כוכבים כחול-לבן בגודל פיקסל שנעו על פני המסך בהתאם למנח של השעון, כך שלמראית עין הם תמיד נופלים לכיוון האדמה. זה עבד, אבל הייתה בעיה שלא צפיתי מראש: עוצמת האור והניגודיות של המסך הם כאלה, שלמעשה לא כל כך קל להבחין בפיקסלים בודדים אם הם בתנועה ובבהירות לא-מקסימלית. הרבה מהאפקט הוויזואלי הלך לאיבוד.
הפתרון הוא פשוט: לצייר כוכבים גדולים יותר. כמובן שציור של כוכב גדול גוזל יותר זמן מאשר צביעה של פיקסל בודד, אז צריך להקטין את מספר הכוכבים, אבל זה בסדר כי הם גם ככה תופסים יותר מקום. מאה ועשרים כוכבים מרובעים בגודל 3×3 עדיין נראו כמו שדה כוכבים לגיטימי, ובעיית הניגודיות פחות מעיקה. במציאות זה נראה עוד יותר טוב מאשר בסרטון:
את הקוד אפשר לראות כאן. אין בו שום delay, אך גם לא אופטימיזציות מיוחדות. אם מתאמצים, מן הסתם אפשר להוסיף הרבה יותר כוכבים, או מגני דוד תלת-ממדיים מסתובבים. מבחינתי, הפרויקט המאולתר הזה הספיק כדי להציל את יום העצמאות 2021, והעבודה עם השעון כנראה תעבור לפסים יומיומיים יותר, כגון לכוון ולהראות את השעה…