אחרי שדיברתי על הפוטנציאל והסטטוס של שפת התכנות MicroPython למיקרו-בקרים, הגיע הזמן להדגים עבודה איתה בפועל. הנה פרויקט קטן לדוגמה, עם לוח הפיתוח הלימודי BBC Micro:bit, בשילוב ההתרשמות והמסקנות שלי מהתהליך ומהתוצאה.
הרעיון
בתור פרויקט הדגמה רציתי ליצור משהו שיהיה מורכב ומעניין יותר מסתם "בלינק", אבל עדיין כזה שאפשר להסביר ולהדגים בקלות, וגם לשחזר אצלכם אם במקרה יש לכם לוח כזה. מטרה נוספת הייתה להשתמש לא רק במיקרו-בקר אלא גם ברכיבים היקפיים שמובנים בלוח, וזאת כדי לנצל את היתרון העיקרי של מיקרו-פייתון – הספריות המוכנות-מראש שמקנות גישה נוחה לרכיבים כאלה.
בחרתי ליצור, על תצוגת 5×5 הלדים המובנית, משהו שמזכיר קצת גחלים לוחשות שנושפים עליהן (מה שמביא, כידוע, יותר חמצן לסביבת הבעירה ומגביר זמנית את עוצמתה). ל-Micro:bit אין חיישן לתנועת אוויר, אז במקום נשיפה הפרויקט יסתפק בזיהוי של נפנוף הלוח עצמו, בעזרת חיישן התאוצה (Accelerometer) המובנה.
חומרה וסביבת פיתוח
את הלוח BBC Micro:bit אפשר להשיג בכמה חנויות רשת (בדרך כלל אלה שמוכרות גם רספברי פיי), כולל ישראליות. מחיר הלוח בחו"ל הוא בסביבות $16 לפני משלוח, ויש גם כל מיני קיטים וציוד היקפי למי שרוצה. החיבור של הלוח למחשב נעשה באמצעות כבל USB רגיל (חיבור Micro USB).
לכתיבת הקוד בחרתי במה שהוא, למיטב ידיעתי, הכלי הלא-מקוון הפשוט והידידותי ביותר למתחילים: Mu Editor. עורך הקוד שלו מינימליסטי ביותר – בגרסה הנוכחית אין אפילו פונקציית חיפוש/החלפה – אבל יש לחצנים גדולים וברורים לניהול בסיסי ולטעינת הקוד ללוח, יש הדגשת תחביר ראשונית, ומה שהכי חשוב, השלמה אוטומטית: הן של מילות מפתח בשפת מיקרו-פייתון והן של שמות משתנים ופונקציות מקומיים. כפי שאפשר לראות בצילום המסך למטה, סביבת הפיתוח אפילו מספקת בזמן הכתיבה "טיפים" לגבי פונקציות מובנות והפרמטרים שלהן.
אם עובדים ב-Windows, דבר אחד נוסף שכדאי להתקין הוא הדרייבר של Mbed לתקשורת סריאלית עם הלוח. פשוט מורידים את הקובץ ומריצים. דרייבר זה מאפשר לנו לעבוד עם REPL, עליה אדבר בהמשך.
התוכנה
שפת MicroPython היא גרסה חלקית ומוחלשת של פייתון, אבל התחביר הבסיסי זהה, ויש בערך מיליון אתרים, ספרים וקורסים על שפת פייתון כך שלא תהיה לכם בעיה להתחיל ללמוד אותו. משאב מצוין נוסף ספציפי ל-Micro:bit הוא האתר הזה, שמפרט ומדגים את השימוש בכל ספריות הקוד שפותחו במיוחד עבור הלוח. בקוד שלי השתמשתי באובייקט Accelerometer לקריאת התנועה ובאובייקט Display והמחלקה Image לניהול התצוגה.
הקוד שלי יוצר רשימה של 25 אובייקטים, אחד לכל "פיקסל" בתצוגה. כל אובייקט כזה מחכה פרק זמן קצר שנקבע אקראית, מדליק את הפיקסל שמקושר אליו בבהירות מתגברת ונחלשת, ואז מתאפס ומתחיל מהתחלה. הלולאה הראשית דואגת לעדכן את הערכים באובייקטים האלה, לרענן את כל התצוגה בהתאם, וגם לקרוא את הנתונים שמגיעים מחיישן התאוצה ולהשוות אותם לנתונים שהתקבלו בקריאה קודמת. ככל שנתוני התאוצה שונים יותר (מה שמעיד על תנועה כמובן), כך הקוד מגדיל משתנה שמציין את כמות ה"אנרגיה" במערכת. הערך של המשתנה הזה קובע את הבהירות המקסימלית שפיקסלים יכולים לקבל באיפוס הבא שלהם, ואת משך ההמתנה עד להדלקתם. כלומר, ככל שמטלטלים את הלוח בעוצמה גדולה יותר, כך בממוצע הפיקסלים נדלקים מהר יותר ומגיעים לבהירות רבה יותר, וזה יוצר משהו שוויזואלית מזכיר קצת גחלים לוחשות. הקוד דואג גם להפחית את ה"אנרגיה" עם הזמן, כך שאם הלוח נמצא במנוחה היא חוזרת לערכים נמוכים.
המחלקה Image בנויה כך שכל פיקסל יכול להיות באחת מעשר רמות בהירות (0-9), אז הקוד שלי בנוי כך ש-9 תהיה רמת האנרגיה המרבית, והפונקציה getDisplayImage שכתבתי אחראית להמיר את הערכים שבאובייקטים למחרוזת בפורמט המתאים להעברה לתצוגה. את הקוד המלא אתם מוזמנים לקרוא כאן.
הביצועים
כפי שהזהרתי בפוסט על MicroPython, יעילוּת ומהירוּת הן לא הצדדים החזקים של השפה הזו, והמצב גרוע במיוחד ב-Micro:bit כיוון שתדר השעון שלו הוא 16MHz בלבד (לעומת למשל 168Mhz בלוח pyboard) וגם כמות ה-RAM שבו מצומצמת יחסית. בלולאה הראשית שלי יש אמנם השהייה של 10ms, אך אתם מוזמנים לנסות ולהיווכח שההשפעה שלה זניחה: הקוד עצמו פשוט זוחל, עד כדי כך שוויתרתי על אפקט נוסף שרציתי לשלב במערכת כדי שהיא תוכל לפעול במהירות סבירה.
לא ביצעתי מדידות מדויקות כדי לקבוע איפה העיכובים הגדולים ביותר, וזה גם לא ממש משנה. אם זה בלוגיקה שאני כתבתי, אתם יכולים לראות לבד שהיא פשוטה מאוד ולא אמורה להיות איטית כל כך – ואם זה במודולים המוכנים-מראש, אז הדרך היחידה לזרז אותם היא לכתוב לבד קוד חלופי בשפה אחרת, מה שמייתר את MicroPython מלכתחילה. זה מה שקורה בקוד של שמונים שורות ברוטו; רק תארו לעצמכם מה יקרה לתוכנה כבדה.
קלות התכנות והדיבוג
כאמור, לא בוחרים ב-MicroPython כדי שהתוכנה תרוץ מהר, אלא כדי שיהיה קל לכתוב אותה (מתאים אולי למתחילים, למערכות שבהן המהירות היא לא שיקול, למפתחים בלחץ זמן וכדומה). מהבחינה הזו, בתור מתכנת עם ניסיון מינימלי בלבד בפייתון, דווקא התרשמתי לטובה. השילוב של השלמת הטקסט האוטומטית והטיפים עם טיפוסי הנתונים הסלחניים של פייתון הופך את כתיבת הקוד לקלילה ממש. עדיין לא משהו שכל ילד יכול לעשות (לדעתי לעולם לא יהיה פתרון כזה), אבל קל לפחות כמו ארדואינו, אם לא יותר.
ויש את REPL, ראשי תיבות של "Read Evaluate Print Loop" ("לולאת קריאה-עיבוד-הדפסה", וכן, בכוונה לא תרגמתי "הערכה"). זוהי טכניקה כללית שהותאמה גם ל-MicroPython: לחיצה על אייקון REPL בסביבת הפיתוח גורמת לתוכנה שרצה על הלוח לקפוא, ופותחת חלונית שבה אפשר להקליד פקודות שירוצו בזמן אמת. לדוגמה, אני יכול להפעיל את REPL תוך כדי ריצה של תוכנית הגחלים שלי, ואז לכתוב energy ולראות מיד על מסך המחשב את הערך של המשתנה הזה ברגע העצירה (כמובן, בתנאי שהלוח מחובר למחשב ב-USB), או לשנות ערכים ולקרוא לפונקציות, כפי שמראה צילום המסך הזה:
ה-REPL היא לא פתרון אידאלי לדיבוג כי אין שליטה טובה בתזמון העצירה (אלא אם מוסיפים קוד עזר), ואי אפשר לצאת ממנה ולחזור לריצה רגילה אלא רק לאתחל את התוכנית לגמרי (בלחיצה על Ctrl+D). מצד שני, אם משתמשים בה נכון היא מספקת גמישות שאי אפשר למצוא בשום שפת תכנות מקומפלת, והיא נוחה מאוד גם לשלב הלמידה, לצורך הדגמה, מעקב ותפעול בזמן אמת של החומרה.
אפרופו, בחלונית ה-REPL אפשר לראות את הפלט הסריאלי שנשלח מהלוח באמצעות פקודות write של מודול uart, אם לא שיניתם את הפינים או את קצב השידור שמוגדרים כברירת מחדל.
מסקנות
שפת MicroPython לא מתאימה למיקרו-בקרים. לפחות בכלים ובאופן שאני בדקתי היא התגלתה כבזבזנית בטירוף, ברמה כזו שרק קוד קצר וטריוויאלי יכול לרוץ במהירות מתקבלת על הדעת. אבל למייקר החובבן הטיפוסי, שהקוד שלו ממילא כזה והבזבוז לא מעניין אותו, קלות השימוש בשפה הזו ובכלי הפיתוח שלה הופכת אותה לפתרון לא רע בכלל. היא יכולה להתאים גם לאילתור זריז של פתרונות "מלוכלכים". ככלי לימוד לא הייתי מסתמך עליה, כי היא מסתירה יותר מדי דברים חשובים. מי שרוצה ללמוד פייתון שייגש ישר למחשב, ומי שרוצה לעבוד עם מיקרו-בקרים, שילמד שפה נורמלית.
יחד עם זאת, גם למייקרים מתקדמים יותר כדאי להכיר את השפה, כי היא צצה בעוד ועוד מקומות. יכול להיות שזו פשוט האופנה כרגע, ואולי יש יתרון מסוים בסטנדרטיזציה – בכל אופן, יש מודולים שימושיים שמגיעים עם גרסה כזו או אחרת של MicroPython (למשל מודם סלולרי מסוים ששמעתי עליו במקרה רק לפני יומיים), ואם נרצה או לא, ייתכן שיגיע שלב שבו נהיה חייבים להכיר את כלי העבודה הזה.
מסכים עם האבחנות שלך לגבי השימוש בלוח עם micro-python.
זה באמת פתרון מצוין ללימוד השפה ולפרויקטים שאין בהם דרישה לזמן ריצה מהיר.
סתם מתוך סקרנות ניסיתי לבדוק כמה אפשר לשפר את הביצועים ע"י אופטימיזציה לתוכנית.
אז השתמשתי במערכים סטטיים במקום ב-class-ים וכן מעבר אחד על מערך הפיקסלים ושימוש בפונקציות קריאה/כתיבה של פיקסלים בודדים:
https://pastebin.com/4c4k6P0f
במדידה גסה, זמן הלולאה הראשית (בקיזוז זמן השינה) התקצר מ-80 ל-15 מילי.
יפה, וכמובן הפואנטה היא שאם צריך לעשות אופטימיזציות בשביל תוכנית כל כך בסיסית ולוותר על האלמנטים ה"טבעיים" ביותר בפייתון, אז בשביל מה לעבוד בכלל בפייתון 🙂
אכן.
ועדיין עבור פרויקטים פשוטים, למי שאוהב ורגיל לכתוב בפייתון זה פתרון טוב.
תיקון קטן לקוד שפרסמתי למעלה – בשורה 37 הפרמטר השלישי לפונקציה צ"ל 1 במקום te.
(כדי שעוצמת הלדים תתחזק בהדרגה)