איך תופסים שגיאות (גם באוויר!)

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

מכבל לאלחוט

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

#include "ZigduinoRadio.h"

// Channel = 11 to 26
#define RADIO_CHANNEL 11

void setup() {
  Serial.begin(9600);
  ZigduinoRadio.begin(RADIO_CHANNEL); 
}

void loop() {

  byte data; 

  if (ZigduinoRadio.available()) {
    data = ZigduinoRadio.read();
    Serial.write(data);
  }

  if (Serial.available()) {
    data = Serial.read();
    ZigduinoRadio.write(data);  
  }

}

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

עד כאן תחנת הממסר. ומה בעניין המודול שאשכרה עושה משהו, זה שהיה מחובר קודם ישירות למחשב ועכשיו נמצא בקצה השני של החדר? לקחתי את הקוד שלו, ובכל מקום בו הוא כתב או קרא מה-Serial, שיניתי לכתיבה או קריאה מ-ZigduinoRadio. זה הכל!

ומה עם השגיאות?

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

הטיפול בשגיאות מתחלק לשני תחומים: איתור ותיקון. שניהם תחומים מתמטיים רחבים מאד, וכמובן שלא ניכנס לפרטיהם כאן. בשלב זה נתמקד רק בבסיס ההתחלתי ביותר של איתור השגיאות.

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

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

האופציה הבאה היא לא לשלוח את כל המידע פעם שניה, אלא רק סיכום מקוצר כלשהו שלו. הסיכום הפשוט ביותר מכונה Checksum – "סכום בדיקה". אם אנחנו שולחים, נניח, עשרה בייטים שערכם 0-255, נסכום את כולם לתוך משתנה מסוג int (באורך 16 ביט), שמסוגל להחזיק את הסכום המלא (0-2550), ובסיום השידור הרגיל נשלח גם אותו. הצד המקבל יבצע סכימה נפרדת של הנתונים שמגיעים, ויוודא שהסכום המחושב שווה לסכום שהתקבל בסוף השידור. יש כאן סיכון מסוים, מכיוון שהסכום של 2 ו-3, למשל, שווה לסכום של 1 ו-4 אף על פי שהנתונים שונים לגמרי. למרות זאת, שיבוש שכזה אינו סביר במיוחד, וליישומים שאינם קריטיים (ולקווי תקשורת נקיים יחסית) הוא יכול להוות אופציה טובה וקלה ליישום – במיוחד אם אנחנו יודעים כמה בייטים אנחנו אמורים לקבל (נסו לנחש למה…).

כהערת אגב, אפשר גם ליצור Checksum בגודל בייט יחיד, בלי קשר לכמות הנתונים. זאת מכיוון שחיבור מעבר לגבולות הבייט לא נחשב טעות – הסכום פשוט "נגלל" להתחלה. 255 + 1 נותן 0, 255 + 2 נותן 1 וכן הלאה.

יישומים שמחייבים וודאות גדולה יותר ממה ש-Checksum מסוגל לתת יכולים להיעזר בחישוב מסוג שונה, שלוקח בחשבון כל ביט וביט. חישוב כזה מכונה CRC (ראשי תיבות של Cyclic Redundancy Check). גם הוא לא מבטיח זיהוי מושלם של כל שגיאה אפשרית – הוא פשוט מצמצם מאד את הסיכוי לטעות, וגובה על כך מחיר בזמן עיבוד וחישוב. כל אלה הם נושאים מעבר למה שאפשר לכסות בפוסט אחד, אז הסתכלו על הקישורים, ואם אתם רוצים שארחיב, תגידו בתגובות.

להרשמה
הודע לי על
0 תגובות
Inline Feedbacks
הראה את כל התגובות