תחום ה-RF (ראשי תיבות של Radio Frequency – תדר רדיו, כשהכוונה בדרך כלל לתקשורת אלחוטית באמצעות גלי רדיו) הוא תחום מסובך. לא שכל תחומי האלקטרוניקה האחרים הם טיול בשכונה, כמו שאומרים – ואף על פי כן, הסביבה הפיזית שלנו רוויה בכל כך הרבה הפרעות ומכשולים לגלי רדיו, שנדרש מאמץ רציני כדי לשלוח ולקלוט מידע בעזרתם ללא שגיאות ובקצב סביר.
מבחר התקני ה-RF שעומדים לרשותנו (חובבי הארדואינו) גדול, וגם הביקוש להם גדול: זו הדרך הפרקטית היחידה שלנו לשלוח מידע, למשל, מחדר לחדר בבית. עם זאת, היעילות והטווח של ההתקנים הללו תלויה בעוצמה ובתחכום של מעגלי העיבוד שלהם, וזה מתבטא במחיר. קחו לדוגמה את הקיטים הבסיסיים של RF, צמד משדר+מקלט שאפשר להשיג תמורת חמישה-שישה דולרים בלבד. לכאורה עסקה מצוינת, אבל מי שינסה לעבוד איתם בצורתם הגולמית (כפי שעשיתי במחסום הצעצוע) יגלה במהרה שאפילו משימה צנועה כמו זיהוי של אות פשוט ("יש/אין") היא קריעת ים סוף. האם נגזר עלינו לוותר על RF, או לחלופין להיפרד מעשרות רבות של דולרים עבור התקני Zigbee, בלוטות' ודומיהם?
הכירו את VirtualWire מאת מייק מק'קולי , ספריה לארדואינו לעבודה עם רכיבי RF פשוטים. הספריה הזו מהווה, למעשה, תחליף תוכנה לחומרה המתוחכמת של ההתקנים היקרים: היא גוזלת משאבים מהמיקרו-בקר, ובתמורה מעניקה פתרון נוח יחסית ומשתלם לתקשורת אלחוטית עבור מפתחים עם דרישות לא-גבוהות. בפוסט זה אדגים עבודה עם VirtualWire, ואערוך מספר בדיקות על האפקטיביות שלה בשטח.
הכנה והתקנות
הקישור שלמעלה הוא לקובץ 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? פספסתי משהו שיכול היה לשפר את התוצאות? אשמח לשמוע בתגובות!
עידו, אי אפשר שלא להעריך את הכשרון שלך לקחת דברים מסובכים ולפשט אותם, תוך שאתה מניח את כל המידע, בצורה מסודרת על השולחן. שאפו. קיימת ספרייה לניהול באפרים לארדואינו תחת השם המפתיע bytebuffer. קיים רכיב תקשורת נוסף ב5$ לזוג שכולל שימוש בפרוטוקול תקשורת וכל מה שצריך ונקרא: +nrf24l01, הנ״ל מגיע בשלל תצורות שהיקרה מבינהן מציעה טווח של עד 1000 מטר בשטח פתוח ועולה 20 דולר ליח׳ או 40$ לזוג. רכשתי את הסט הזול להתנסות ואוכל בעתיד לחלוק את רשמיי בנושא. בכל אופן, כדברי הפתגם: The right tool for the job יש לבחור ברכיב בהתאם לפרוייקט וכאשר קצב הנתונים לא קריטי,… לקרוא עוד »
יש ספריה לכל דבר בארדואינו… 🙂
על ה-NRF שמעתי ואפילו יש לי זוג זול שמחכה לניסויים – לא רציתי לדבר על זה לפני שאני בודק ומבין איך זה עובד.
תודה לך!
לפי מה שקראתי ב PDF, הספריה מספקת רק קוד זיהוי שגיאות ולא מספקת קוד תיקון שגיאות. אתה יכול לקודד כל מידע שאתה רוצה לשלוח עם קוד תיקון שגיאות, ואז כאשר קוד זיהוי השגיאות (שכבר קיים בסיפריה) יגיד לך שיש כישלון* – תוכל לתקן את הבאפר שהתקבל. (זאת בתנאי שגם בזמן כישלון הפונקציה מחזירה את הבאפר שקיבלה) קודים לתיקון שגיאות (ECC) זה תחום רחב מאוד בתקשורת. אם רוצים משהו פשטני מאוד, אפשר פשוט לשלוח כל הודעה N פעמים בתקווה שאחד העותקים יגיע באופן תקין. אם אתה רוצה להתקדם למשהו פחות פרמיטיבי, אפשר להתחיל בקוד המינג (hamming) ומשם להמשיך לדברים יותר מורכבים… לקרוא עוד »
אפרופו שליחת כל הודעה N פעמים – זה בדיוק מה שעושים השלטים של החניות, שמשתמשים במשדרים ומקלטים דומים לאלה שבפוסט.
תודה על המידע והרעיונות. מההיכרות השטחית שלי עם ECC, נדמה לי שערוץ "רועש" כל כך יזדקק לתיקון שגיאות מאסיבי במידה כזו, שעדיף כבר למצוא פתרון אחר… אבל מי יודע, אולי אשחק גם עם זה ביום מן הימים.
וואוו מעניין מאוד!
תודה
זה מעניין… אם כן, מדוע שלא תשלח באפרים יותר גדולים? בכדי שלא יפגמו?
ספציפית לפוסט הזה, העדפתי לדבר על הספריה נטו ולא להציף את הקוראים המתחילים במידע נוסף כמו פוינטרים, מערכים וכאלה. כל דבר בשעתו… 🙂 ככלל, באפר גדול יותר פירושו סיכוי גדול יותר לשגיאה בקליטה (אם יש, סתם לצורך הדוגמה, שגיאה אחת בכל 1000 ביטים שנשלחים, אז כל באפר בן 1000 ביטים ומעלה ייכשל בהכרח). מצד שני, כל באפר נשלח כשהוא מוקף בהמון ביטים לבקרה ולאיתור שגיאות, והפרופורציה של הביטים הנוספים הולכת וקטנה ככל שהבאפר גדול יותר. כך שאינטואיטיבית, אם אין סיבה מיוחדת לשלוח באפרים מינימליים או ארוכים במיוחד, אני מניח שבאפרים בני 4-8 בייטים בערך יתנו את התוצאות האופטימליות מבחינת כמות… לקרוא עוד »
🙂
תודה רבה על הפוסט לימד אותי המון!
היי עידו,
כפי שכתבתי לך בעבר – תענוג לקרוא כל מילה שלך.
אני במקרה מתעניין בקליטת WIFI ע"י ארדואינו. האם זה קיים? אם כן – הפוטנציאל של זה פשוט אינסופי. אם אתה מכיר את הנושא אשמח אם תכתוב עליו.
תודה
אני לא מכיר את הנושא אישית ולא נראה לי שאגיע אליו בקרוב – עם זאת אני יודע שיש תוספים לארדואינו שמספקים חיבור ל-WiFi. חפש Arduino WiFi Shield וקח בחשבון שתוספים כאלה עשויים להיות יקרים, בסביבות מאה דולר.
היי עידו ומיקי יש אפשרות נוספת להשתמש ב 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/
קצת פחות למתחילים (כולל קנות ראוטר זול באיביי, ולהחליף לו את הקושחה למשהו שידע לדבר עם ארדואינו) אבל פתרון בסופו של דבר מאוד אלגנטי.
אוריאל
זה יכול לעניין אותך (אבל הזדרז אם כן):
http://www.kickstarter.com/projects/1608192864/open-source-wireless-inventors-shield-for-arduino?ref=category
מה יש לי לעשות עם טווח של 117 מטר? 🙂
הוא (מיקי שרייבר) חיפש WiFi עם ארדואינו, לא?
אתה יכול לשלוח לו את הלינק (אם לא סביר שהוא יקרא את זה כאן).
כן, ההיררכיה של ההודעות חמקה מעיניי לרגע…
עדיין, הדבר הזה זה לא WiFi.
מוזר… קודם הייתי בטוח שהיה כתוב שזה WiFi.
היי עידו ,
אם הזמנתי משדר ומקלט ורק למקלט יש םין לאנטנה איך אני מחבר את המשדר לאנטנה ?
בקיטים שאני ראיתי, דווקא המשדר הוא זה עם הפין הייעודי לאנטנה. נסה למצוא שרטוט של הרכיב שיש לך – החיבור יכול להיות חור להלחמה, כמו בלוח PCB ריק, או פין לא מזוהה. כמובן שאם אתה לא בטוח, אפשר לעשות ניסויים זהירים לפני שמלחימים משהו קבוע…
כרגיל, פוסט מאיר עיניים, כתוב מצויין ובמקרה שלי – בטיימינג נהדר 🙂
שתי שאלות ברשותך:
1. חששת מאורכו של הפוסט ואולי בשל כך לא הרחבת בחלק של "הספריה VirtualWire לא שולחת משתנים או ערכים ספציפיים, אלא באפרים" – מה זה למעשה אומר? אם בארדואינו המשדר יש לי זרימת ערכים מתמשכת מסנסור כלשהו, האם יש דרך שהיא "תזרום" לארדואינו הקולט באופן פשוט וברור?
2. האם הספריה הזו עובדת גם עבור התקני Zigbee שהזכרת?
1. ה"באפר" הוא רק אופן ההתייחסות של הפונקציה המשדרת למידע שבזכרון – בכל מקרה אתה צריך משהו שיכניס את המידע הזה לזכרון מלכתחילה. במילים אחרות, אין מצב ל-Streaming בזמן אמת.
2. לא, הספריה מיועדת לרכיבי RX/TX בסיסיים. מודולים מתקדמים יותר, כולל Zigbee ו-Xbee, הם לא סתם "צינורות" – הם מקבלים מקוד הארדואינו פקודות ממש דרך פרוטוקול תקשורת, וזה דבר ש-VirtualWire לא בנויה לעשות.
תודה.
כמובן שאת סעיף 2 לא הבנתי אבל כשהרכיבים יגיעו לא תהיה לי ברירה ואז אבין…
🙂
נגיד ככה – VirtualWire עובדת עם רכיבים פרימיטיביים: מעבירים להם 1 הם משדרים, מעבירים להם 0 הם לא משדרים, וזהו. בלי קונצים.
לעומתם, מודולים כמו Zigbee הם חכמים, יש להם מיקרו-בקר משל עצמם שקובע מה לעשות עם הקלט ומתי. עם מודולים כאלה צריך לדבר בגובה העיניים, וזה אומר להשתמש בפרוטוקול תקשורת (לדוגמה SPI או I2C, שיש ספריות מוכנות עבורם).