תקשורת אלחוטית עם ארדואינו ו-VirtualWire

תחום ה-RF (ראשי תיבות של Radio Frequency – תדר רדיו, כשהכוונה בדרך כלל לתקשורת אלחוטית באמצעות גלי רדיו) הוא תחום מסובך. לא שכל תחומי האלקטרוניקה האחרים הם טיול בשכונה, כמו שאומרים – ואף על פי כן, הסביבה הפיזית שלנו רוויה בכל כך הרבה הפרעות ומכשולים לגלי רדיו, שנדרש מאמץ רציני כדי לשלוח ולקלוט מידע בעזרתם ללא שגיאות ובקצב סביר.

מבחר התקני ה-RF שעומדים לרשותנו (חובבי הארדואינו) גדול, וגם הביקוש להם גדול: זו הדרך הפרקטית היחידה שלנו לשלוח מידע, למשל, מחדר לחדר בבית. עם זאת, היעילות והטווח של ההתקנים הללו תלויה בעוצמה ובתחכום של מעגלי העיבוד שלהם, וזה מתבטא במחיר. קחו לדוגמה את הקיטים הבסיסיים של RF, צמד משדר+מקלט שאפשר להשיג תמורת חמישה-שישה דולרים בלבד. לכאורה עסקה מצוינת, אבל מי שינסה לעבוד איתם בצורתם הגולמית (כפי שעשיתי במחסום הצעצוע) יגלה במהרה שאפילו משימה צנועה כמו זיהוי של אות פשוט ("יש/אין") היא קריעת ים סוף. האם נגזר עלינו לוותר על RF, או לחלופין להיפרד מעשרות רבות של דולרים עבור התקני Zigbee, בלוטות' ודומיהם?

הכירו את VirtualWire מאת מייק מק'קולי , ספריה לארדואינו לעבודה עם רכיבי RF פשוטים. הספריה הזו מהווה, למעשה, תחליף תוכנה לחומרה המתוחכמת של ההתקנים היקרים: היא גוזלת משאבים מהמיקרו-בקר, ובתמורה מעניקה פתרון נוח יחסית ומשתלם לתקשורת אלחוטית עבור מפתחים עם דרישות לא-גבוהות. בפוסט זה אדגים עבודה עם VirtualWire, ואערוך מספר בדיקות על האפקטיביות שלה בשטח.

משדר (משמאל) ומקלט מקיט RF
משדר (משמאל) ומקלט מקיט RF

הכנה והתקנות

הקישור שלמעלה הוא לקובץ PDF שמכיל מידע עדכני על הספריה ועל העבודה איתה. כאן אפרט רק את המינימום שבמינימום, ואני ממליץ לכל מי שרוצה לעבוד עם הספריה הזו ברצינות לעיין במסמך המקורי – הוא ברור וקריא מאד.

אנחנו מתחילים, אם כן, בהתקנה של הספריה. היא אינה מגיעה עם סביבת הפיתוח כמו ספריות אחרות (כגון SD), כך שצריך להתקינה לבד. הורידו את קובץ ה-ZIP מכאן (גרסה 1.9, העדכנית נכון לכתיבת הפוסט) והעתיקו את הספריה שבתוכו אל התיקיה libraries שתחת התקנת הארדואינו במחשב.

הספריות של ארדואינו
הספריות של ארדואינו

כעת, הפעילו (או הפעילו מחדש) את סביבת הפיתוח. הוסיפו בתחילת הקוד את השורה

#include <VirtualWire.h>

או, אם אתם מתעצלים, בחרו בתפריט Sketch->Import Library->VirtualWire והוא כבר יוסיף את השורה הזו לבד. זה מה שייתן לכם גישה לפקודות של הספריה.

כעת נעבור לארדואינואים. כן, אם זה לא היה ברור עד עכשיו, שידור וקליטה מחייבים שני לוחות ארדואינו, או לפחות שני מיקרו-בקרים מתוכנתים מראש, אחד למשדר ואחד למקלט. המקלט הוא בדרך כלל הרכיב המוארך מבין השניים בקיט RF מהסוג הזול. בידקו היטב את המפרט של הרכיב הספציפי שברשותכם כדי לגלות מה מתחבר לאן. בעיקרון, המקלט זקוק למתח של 5V שהארדואינו יכול לספק, ויש לו יציאה אחת של נתונים (לפעמים דרך שני פינים שונים, לבחירתכם). למשדר יש כניסה אחת לנתונים שמתחברת ישירות לארדואינו, וחיבורי מתח ו-Ground – אלא שלמשדר כדאי לתת מתח גבוה יותר, עד 12V. ככל שהמתח גבוה יותר, כך השידור אמור להיות חזק יותר. אפשר לגייס לשם כך סוללת 9V, או 12V של שלטי חניה עם תושבת מתאימה, ולחבר בין ה-Ground שלה/של המשדר ל-Ground של הארדואינו.

כדי לשפר את השידור ואת הקליטה, מומלץ להצמיד או להלחים לרכיבים אנטנות (חפשו פין או חור במעגל המודפס עם הכיתוב ANT). לא צריך משהו מושקע – חוט חשמל דק יספיק. אני חתכתי לצורך העניין קטעים מחוט אנטנה גמיש של רדיו-שעון ישן. האורך המתאים לאנטנה תלוי בתדר של המשדר/מקלט, ויש מחשבונים ברשת שיעשו את החשבון בשבילכם. במקרה שלי מדובר בתדר של 433 מגהרץ, והמחשבון נותן לי שתי אפשרויות – חצי אורך גל ורבע אורך גל. ה"חצי" ישדר קצת יותר טוב, אך הוא גם מסורבל יותר ולכן אימצתי את האופציה השניה: רבע אורך גל, 6.48 אינץ', כלומר בסביבות 16.5 סנטימטרים.

אתחול הספריה בתוכנה

לפני שניגש לתוכנה, בואו נכיר את הזוג TX ו-RX. יכול להיות שראיתם כיתוב כזה ליד פינים 1 ו-0 בלוח הארדואינו, אבל למעשה מדובר במושג הרבה יותר כללי. TX הוא פשוט חיבור, או "יציאת" השידור (Transmitter), ואילו RX הוא חיבור או "כניסת" הקליטה (Receiver). הם ממש לא חייבים להיות פינים 1 ו-0 דווקא: הספריה VirtualWire נותנת לנו לבחור לתפקידים הללו איזה פינים שנרצה.

אז בתוך הפונקציה setup שלנו, בואו נגדיר את הפינים. שתי הפקודות הבאות, אגב, אינן חובה: כברירת מחדל, TX של VirtualWire יושב על פין 12 ו-RX יושב על פין 11. שימו לב שכל הפקודות של הספריה מתחילות ב-vw_:

vw_set_tx_pin(12);
vw_set_rx_pin(11);

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

vw_setup(2400); // Transmitter & Receiver
vw_rx_start(); // For Receiver only

הפקודה הראשונה (vw_setup) מאתחלת את הספריה כולה וקובעת מהירות שידור (קצב הנתונים) בביטים לשניה. הספריה מסוגלת בעיקרון לעבוד במהירויות גדולות הרבה יותר מ-2400, אך רבים מהקיטים הזולים של RF מצהירים על 2400 כעל גבול המהירות של החומרה, ואנחנו לא ניקח סיכון. הפקודה השניה מיועדת לקוד של המקלט בלבד, והיא מתחילה את ההאזנה לשידורים בפועל.

שליחת נתונים

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

byte buff;
// ...whatever
vw_send(&buff, 1);

הסימן & פירושו, בשפת C, "הכתובת בזיכרון של…". נגיע לזה בעתיד, בפוסטים של שיעורי C למתחילים; בינתיים, קבלו את זה כתורה מסיני.

קליטת נתונים

כדי לקלוט מידע, אנחנו צריכים קודם כל לדעת מתי בכלל יש מה לקלוט. לשם כך ניעזר, בקוד הארדואינו הקולט, בפונקציה vw_have_message(). היא מחזירה לנו true אם התקבל מידע שמחכה שנקרא אותו, ו-false אם לא.

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

byte buff, buffLen;
// ...whatever
if (vw_get_message(&buff, &buffLen)) 
 Serial.println("Got it!");
 else Serial.println("Transmission failed!");

שימו לב ששמתי את הפונקציה הקוראת, vw_get_message, בתוך if, כי גם היא מחזירה ערך true או false בהתאם להצלחת הקליטה. כן, קליטה יכולה להיכשל, ואתם בטח שואלים את עצמכם עכשיו למה לכל הרוחות קיבלתם הודעה שיש מידע, אם המידע לא באמת עבר כמו שצריך. התשובה: כדי שתדעו שהיתה בעיה ותוכלו, למשל, להזעיק את המשתמש כמו שעשיתי בקוד למעלה, או (אם יש תקשורת דו-כיוונית) להודיע לארדואינו השולח שישלח שוב.

מבחן שטח

הפוסט מתארך ללא שליטה, אז נעזוב את הפרטים הקטנים ונעבור למבחן. עבור הארדואינו המשדר כתבתי קוד ששולח "פרצים" של נתונים. כל פרץ כזה מורכב ממאה ערכים עוקבים (לא כבאפר אחד ארוך אלא כל בייט בנפרד), ויש הפסקה של מספר שניות בין פרץ לפרץ.

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

זמן השידור אינו תלוי באיכותו או במרחק: המשדר אינו יודע איפה הוא ואם מה שהוא פולט נקלט או לא. הפרמטר היחיד שמשפיע הוא הביטים לשניה. במהירות 2400, שיכולה בתיאוריה להעביר 300 בייטים בשניה אחת, עברו רק כ-25 בייטים של נתונים מדי שניה. ההפרש הפרוע הזה מקורו במאמצים המרובים ש-VirtualWire עושה כדי להבטיח מינימום שגיאות: היא מוסיפה לכל באפר שמשודר סדרת ביטים לצורך איפוס המקלט, ביטים של בדיקת שגיאות ועוד כהנה וכהנה, וזה "מנפח" את המידע בלי חשבון. כמובן, אם הייתי שולח באפרים ארוכים יותר, החלק היחסי של התוספות הללו היה קטן בהרבה וקצב העברת הנתונים היה עולה בהתאם.

ומה בעניין הדיוק? האם כל הביטים הנוספים הללו עזרו במשהו? ובכן, בטווח של עד מטר בערך (ובקו ראייה) אחוז השגיאות וההשמטות היה אפסי – העברת נתונים כמעט מושלמת. בטווח של כחמישה מטרים, מעבר לקיר, בסביבות 5-7% מהנתונים הגיעו שגויים, ואחוז דומה לא הגיעו כלל. ייתכן שהמצב היה משתפר אם הייתי משתמש בסוללת 12V בשביל המשדר, ואם הייתי רוכש רכיבים איכותיים ולא את המוצר הסיני הכי זול.

מסקנות

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

היתה לכם התנסות חיובית יותר עם קיט RF ו/או VirtualWire? פספסתי משהו שיכול היה לשפר את התוצאות? אשמח לשמוע בתגובות!

להרשמה
הודע לי על
25 Comments
מהכי חדשה
מהכי ישנה לפי הצבעות
Inline Feedbacks
הראה את כל התגובות

עידו, אי אפשר שלא להעריך את הכשרון שלך לקחת דברים מסובכים ולפשט אותם, תוך שאתה מניח את כל המידע, בצורה מסודרת על השולחן. שאפו. קיימת ספרייה לניהול באפרים לארדואינו תחת השם המפתיע bytebuffer. קיים רכיב תקשורת נוסף ב5$ לזוג שכולל שימוש בפרוטוקול תקשורת וכל מה שצריך ונקרא: +nrf24l01, הנ״ל מגיע בשלל תצורות שהיקרה מבינהן מציעה טווח של עד 1000 מטר בשטח פתוח ועולה 20 דולר ליח׳ או 40$ לזוג. רכשתי את הסט הזול להתנסות ואוכל בעתיד לחלוק את רשמיי בנושא. בכל אופן, כדברי הפתגם: The right tool for the job יש לבחור ברכיב בהתאם לפרוייקט וכאשר קצב הנתונים לא קריטי,… לקרוא עוד »

לפי מה שקראתי ב PDF, הספריה מספקת רק קוד זיהוי שגיאות ולא מספקת קוד תיקון שגיאות. אתה יכול לקודד כל מידע שאתה רוצה לשלוח עם קוד תיקון שגיאות, ואז כאשר קוד זיהוי השגיאות (שכבר קיים בסיפריה) יגיד לך שיש כישלון* – תוכל לתקן את הבאפר שהתקבל. (זאת בתנאי שגם בזמן כישלון הפונקציה מחזירה את הבאפר שקיבלה) קודים לתיקון שגיאות (ECC) זה תחום רחב מאוד בתקשורת. אם רוצים משהו פשטני מאוד, אפשר פשוט לשלוח כל הודעה N פעמים בתקווה שאחד העותקים יגיע באופן תקין. אם אתה רוצה להתקדם למשהו פחות פרמיטיבי, אפשר להתחיל בקוד המינג (hamming) ומשם להמשיך לדברים יותר מורכבים… לקרוא עוד »

וואוו מעניין מאוד!
תודה

זה מעניין… אם כן, מדוע שלא תשלח באפרים יותר גדולים? בכדי שלא יפגמו?

🙂

תודה רבה על הפוסט לימד אותי המון!

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

היי עידו ומיקי יש אפשרות נוספת להשתמש ב WiFi ע"י הארדואינו. אם מחברים Module Ethernet עם ראוטר שיש לך בבית אז אתה יכול לקבל את רוב הפונקצוית כמו המודול שעידו המליץ. רק תבדוק איזה רכיב יש על הModule Ethernet יש את ENC28J60 שהוא היותר זול אך הסיפריה שלו אינה ברירת מחדל של הארדואינו ויש צורך לשנות אותה כדי שתתאים לך. מחיר 6$ + 25$ עבור ראוטר. אפשרות שניה היא היותר פופולרית היא Module Ethernet עם W5100 שיותר יקר והסיפריה היא יותר שלמה ואולי שם יותר פשוטה (לא ניסיתי) הסיפריה מגיעה עם הסביבת פיתוח של הארדואינו. מחיר 17$ + 25$ עבור… לקרוא עוד »

היי,
כל העניין הוא שאני רוצה שהארדואינו יהיה מרוחק מהראוטר ויקבל ממנו פקודות ב-WIFI ויעשה דברים בהתאם…

שווה אולי להסתכל כאן:
http://hackaday.com/2012/06/12/nah-you-dont-need-an-ethernet-module-for-your-arduino/
קצת פחות למתחילים (כולל קנות ראוטר זול באיביי, ולהחליף לו את הקושחה למשהו שידע לדבר עם ארדואינו) אבל פתרון בסופו של דבר מאוד אלגנטי.

אוריאל

הוא (מיקי שרייבר) חיפש WiFi עם ארדואינו, לא?
אתה יכול לשלוח לו את הלינק (אם לא סביר שהוא יקרא את זה כאן).

מוזר… קודם הייתי בטוח שהיה כתוב שזה WiFi.

היי עידו ,
אם הזמנתי משדר ומקלט ורק למקלט יש םין לאנטנה איך אני מחבר את המשדר לאנטנה ?

כרגיל, פוסט מאיר עיניים, כתוב מצויין ובמקרה שלי – בטיימינג נהדר 🙂
שתי שאלות ברשותך:
1. חששת מאורכו של הפוסט ואולי בשל כך לא הרחבת בחלק של "הספריה VirtualWire לא שולחת משתנים או ערכים ספציפיים, אלא באפרים" – מה זה למעשה אומר? אם בארדואינו המשדר יש לי זרימת ערכים מתמשכת מסנסור כלשהו, האם יש דרך שהיא "תזרום" לארדואינו הקולט באופן פשוט וברור?
2. האם הספריה הזו עובדת גם עבור התקני Zigbee שהזכרת?

תודה.
כמובן שאת סעיף 2 לא הבנתי אבל כשהרכיבים יגיעו לא תהיה לי ברירה ואז אבין…
🙂