TL-WR703N OpenWrt

TL-WR703N

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

ישנו צורך במודול שישמש שער לאינטרנט עבור כל אותם מודולים.

אחד המוצרים השימושיים ביותר עבור הנגשה של WIFI ורשת קווית לבקרים דוגמת הארדואינו זה TL-WR703N שזה בעצם ראוטר קטן בגודל של כרטיס אשראי הכולל כניסת USB ששם אמורים לתקוע מתאם סלולארי ולהפוך בעצם את המודם לנייד. להלן המאפיינים:

Atheros AR7240 CPU (400Mhz)
Atheros AR9331 Chipset (integrated wireless)
802.11 b/g/n 150Mbps (130Mbps real)
wireless power output 20dBm – 100mW
4 MB flash memory
32 MB RAM
USB 2.0 port (High-Speed only, use an external High-Speed hub for Full/Low-Speed devices)
Powered via micro-USB socket
5.7cm x 5.7cm x 1.8cm

 TL-WR703N TL-WR703N

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

במדריך זה אראה איך אני התקנתי OpenWrt וקינפגתי את הראוטר כ WIFI client .

במדריכים העוקבים אראה כיצד "לדבר" עם ארדואינו ולשדר ממצלמת ווב שידור חי…

מצרכים:

  1. כבל רשת .
  2. ראוטר TL-WR703N כ – 20-25$ באתרים הסינים הרגילים.

ישנו אתר נחמד המציע להורדה חבילה של OpenWrt המתאימה לצ'יפ של הראוטר וכוללת את כל החבילות תוכנה שצריך ע"מ לעשות את מה שמניתי (שידור ממצלמה דיבור עם ארדואינו וכו')  להורדת החבילה.

לאחר ההורדה יש לפתוח את הכיווץ לתוך תיקיה מתאימה.

יש לחבר את הראוטר לחשמל ולכבל רשת שמחובר למחשב ולגשת לכתובת http://192.168.1.1 .

הראוטר הנ"ל מיועד לשוק הסיני וכל ה UI שלו הוא סיני ולכן אצרף פה תמונות ע"מ להמשיך את ההסבר.

נתחבר כדי לגשת לממשק האינטרנט, ברירת המחדל – משתמש:admin  הסיסמה היא: admin.

יש ללחוץ על "系统工具" (כלי מערכת):

chin1

 

לאחר מכן יש ללחוץ על "软件升级" (עדכון קושחה) :

chin2

ולבחור את הקובץ שחילצנו מהתיקיה המתאימה:

chin3

יש ללחוץ על הכפתור "浏览…" שזה BROWSE… לאחר מכן יש ללחוץ על "升 级" (שידרוג) ולאשר:

chin4

ניתן לתוכנה להטען…………….

הנתב צריך אתחול מחדש לתוך OpenWRT, ויש לבצע כניסה לממשק החדש ללא סיסמא (כרגע לא הגדרנו סיסמא).
נעבור להגדרת סיסמא:

openwrt1

זהו התקנו OpenWRT ! עכשיו צריך לשדרג את המערכת שתכלול את כל ההפתעות שיש בחבילה שהוכנה מראש.

שדרוג OpenWRT
שדרוג שכבר קיימת מערכת OpenWRT זה פשוט יותר יחסית.

כניסה רגילה כדי לגשת לממשק האינטרנט ( ששמו Luci)
בחירה בטאב "system"
לאחר מכן בחר "Backup / Flash Firmware"

Upgrade

נלחץ על "Choose File"  ונבחר את הקובץ "openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-sysupgrade.bin" מהחבילה שפרסנו ונלחץ "Flash image".

זהו המערכת מוכנה.

קינפוג הראוטר כ WIFI client

כדי שנוכל לגשת לראוטר ולכל הדברים שהוא מציע אלחוטית ללא כבל רשת ,על הראוטר לשמש כ CLIENT ולהתחבר לראוטר הביתי שנו ע"מ לקבל כתובת רשת ושנוכל לגשת אליו ושגם לו תהיה גישה לרשת.

הגדרת הנתב יש לבחור בכרטיסייה "network" בחלק העליון , ולאחר מכן בחר באפשרות " Wifi " וללחוץ על "scan":

wifi1

נמצא את הראוטר שלנו ונלחץ על "Join Network":

wifi2

נזין את הסיסמה של WPA (בהנחה שיש WPA/WPA2 ) , ותחת " Create / Assign firewall-zone " – בחר " LAN" לאחר מכן לחץ על "Submit":
wifi3

יש ללחוץ לאחר מכן על "Save & Apply" ונמתין עד שההגדרות יתפסו:

wifi5

תחת הלשונית " network" בחלק העליון , נבחר " interfaces"  שימו לב לכתובת ה-IP של החיבור שכרגע יצרנו .

wifi6

דבר אחרון חשוב שגרם לי להרבה כאב ראש – כאשר הראוטר מחובר קווית הוא מקבל כתובת מטווח כתובות IP מסויים. במקרה שלנו 192.168.1.1. ולכן כל עוד הייתי מחובר אליו לא יכולתי לגשת לאינטרנט במחשב.

הרבה ראוטרים בייתים טווח הכתובות שלהם הוא *.192.168.1 שהראוטר עצמו הוא 192.168.1.1.

חשוב להגדיר את את הכתובת של ה – TL-WR703N כאשר הוא בחיבור קווי כחלק מטווח כתובות שונה מהטווח של הראוטר הבייתי שגם נתן כתובת לחיבור החדש שיצרנו ע"מ לחבר את ה TL-WR703N אלחוטית כ CLIENT לראוטר הביתי.

אני שיניתי ידנית את הכתובת של ה TL-WR703N כאשר הוא מחובר קווית מ 192.168.1.1 ל 192.168.0.1 והכתובת שלו כאשר הוא מחובר אלחוטית לראוטר הביתי נשארה 192.168.1.124.

זהו נכון לעכשיו הראוטר מוכן ומחובר אלחוטית לראוטר הביתי.

בפוסטים הבאים אראה איך ל"דבר" עם ארדואינו ולשדר ממצלמת ווב רגילה.

המדריך הזה נכתב בעיקר ע"פ האתר הזה :

madox.net

electric imp

לאחרונה קיבלתי מחבר ערכה של  – electric imp להלן – השדון.

הערכה כללה את המודול עצמו ה – imp ולוח מתאים (breakout).

החלק הכי בעייתי שחוויתי ע"מ להתחיל להשתמש בשדון זה ה – BlinkUp . אפרט את כל התהליך ואסביר:

ראשית יש ליצור חשבון בענן .

BlinkUp TM  –  הטכנולוגיה שתשמש להעביר את כל פרטי ההתקשרות בWIFI לשדון ע"מ לחברו לרשת.

יש להוריד אפליקציה לסמרטפון ,שם יש להזין את פרטי חשבון, SSID של הרשת, והססמה של ה- WIFI ולשלוח אותם לשדון באמצעות הבהובי מסך.

חיפוש בסטור של גוגל או אפל עם המילים electric imp ימצא בקלות את האפליקציה.

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

כשמחוברים לאפליקציה, בחרו את הרשת האלחוטית שדרכה נרצה להתחבר לאינטרנט.

יש להזין את הססמה של ה-WiFi . אם אתם מתחברים לרשת לא מאובטחת, פשוט השארו את השדה ריק.

חברו את הקצה הקטן של כבל USB Mini לשקע ה-USB במתאם, ואת הקצה השני ליציאת USB במחשב.

יש למקם ג'מפר כך שהמכשיר יקבל מתח דרך USB ולא דרך בטרייה:

IMAG2234

הכנסו את כרטיס השדון לחריץ SD . אם הכל כשורה, ה-LED בתוך השדון צריך להתחיל להבהב בכתום.

אם אתם משתמשים באפליקציה לאנדרואיד, יכול להיות שיש לבחור מצב Legacy לתוצאות הטובות ביותר.

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

  • החזק את המסך של הטלפון קרוב ככל האפשר לחיישן האופטי (כמעט נוגע במידת האפשר)
  • האגודל שלך מכסה את החלק החשוף, חלקו העליון של שדון (היכן שכתוב – "developer edition").
  • נסה לחסום את כל האורות הבוהקים / או עשה את התהליך במקום חשוך.

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

אני ניסיתי את התהליך עם מכשיר HTC ONE S הכולל מגן מסך וזה לא הצליח , ניסיון נוסף עם אייפון 4 ללא מגן מסך צלח.

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

 

בית חכם חלק שני – מודול העלה

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

הבקר של המודול יהיה חיקוי של ארדואינו פרו והרכיב האלחוטי שבו יהיה nrf24l01 .

IMAG1866

את המעגל יצרתי באמצעות תוכנה מאוד שימושית ופופולרית בשם – fritzing שלא ארחיב עליה כאן רק אצרף את הקובץ לצורך הדפסת המעגל.

יש 2 ספריות נפוצות לארדואינו לצורך עבודה עם המודול הזה – rf24 ו mirf.

אני מצאתי את הספרייה rf24  מתאימה יותר לצורך של רשת מודולים אל אף שהיא יותר מורכבת  מאשר ספריית ה mirf כמו כן ישנה ספרייה מעולה (אם כי קצת מורכבת) לצורך רשת מודולים שמבוססת על ספריית ה rf24  בשם – rf24network .

אני אדלג על הסבר לספריית rf24 ואקפוץ ישר לעניינים – rf24network.

להלן סכימת החיבור בין הארדואינו לבין רכיב ה nrf24l01 :

24L01

סכמת חיבור ארדואינו ל NRF24L01

סיגנלארדואינוNRF24L01
GNDGND1
VCC3.3V2
CE93
CSN104
SCK135
MOSI116
MISO127
סכמת חיבור ארדואינו ל NRF24L01

כלומר אם יש בארדואינו פרו 13 יציאות דיגיטליות ו7 יציאות אנלוגיות אחרי חיבור למודול האלחוטי נשארנו עם 8 יציאות דיגיטליות ו7 אנלוגיות.(שזה דיי מספיק למודול אחד – יכולת שליטה על עד 8 אלמנטים וחיבור של עד 7 חיישנים ).

כלומר אני צריך לתכנן מעגל לחיבור מודול האלחוט לארדואינו וחשיפה של 8 פינים דיגיטליים ו 7 אנלוגיים כמו כן עלי להמיר את 5V שמגיע מהארדואינו למודול האלחוט (VCC) מ5V ל 3.3V.

כמו כן עלי לחשוף גם את הפין ה RST לצורך העברת הקוד לארדואינו ואת פין ה RAW לצורך חיבור למקור מתח חיצוני לדוגמה סוללה.

sketch-iotv1

 

את המעגל יצרתי באמצעות שיטת ה – tuner transfer שלא כאן המקום להרחיב.

השתמשתי בארדואינו פרו 5V ולא ב-3.3V בגלל שההבדל בעלות זה כמעט דולר אך הדבר הצריך ממני להוסיף למעגל ממיר מתח ל3.3 בגלל שזה מה שמקבל מודול ה- nrf24l01 (כמעט 10 ממירי מתח וקבלים עלו לי קצת מעל 2 דולר כך שעדיין יוצא יותר זול).

המעגלים (לוח הארדואינו המודפס שבתמונות לא קשור לפרויקט):

אפרט קצת על מבנה רשת העלים.

היישום הרשת היה קצת שונה מהיישום של מחבר הספרייה rf24network אך עדיין מבוסס על טופולוגית עץ.

ישנו בסיס ראשי בכתובת 00 (כתובות העלים הם בפורמט uint16_t unsigned 16-bit integer) והיות ויש אפשרות ל6 צינורות (PIPES) תקשורת לכל מודול nrf24l01 לפי ה – DATASHEET,  אז כל עלה בסיס יכול לתקשר עם 5 בנים (sibling)  ועם האבא שלו, הבסיס הראשי היות והוא אב לכולם ואין לו אב משלו יש לו אפשרות להתחבר ל 6 בנים אך כדי לשמור על הקוד פשוט ושכל עלה ראשי יהיה עם אותם המאפיינים אז גם העלה הראשי ביותר יכול לתקשר רק עם 5 בנים.

כל עלה יכול לתקשר עם בסיס האב שלו או עם אחד הבנים שלו אך לא עם אחד מהאחים שלו או עם הסבא או הנכד וכו'…

הקוד שלי הוא עד הרמה השלישית, כלומר 5 בחזקת 3  כלומר 1+25+125+5 עלים = עד 151 נקודות מודולים ברשת ! יכולתי להוסיף עוד 'דור' לרשת ואז היה אפשרות ליותר מפי חמש אך 151 מודולים זה דיי והותר לרשת ביתית.

להלן סכמה של המודולים והכתובות שלהם – נשים לב שהספרות הכי ימניות במספר uint16_t הם בעצם כתובת האב:

topologu

בסיס האב הראשי – 00 יהיה בעל קישוריות לאינטרנט (wired / wifi) והוא יהיה אחראי על חשיפת כל רשת החיישנים ומודולי השליטה לרשת האינטרנט.

לבסיס האב הראשי 5 ילדים – 01,02,03,04,05 הוא יכול לתקשר רק איתם והם איתו. האחים לא מדברים בינהם – 01 לא יכול לתקשר עם 02, אלא רק עם האב שלו (00) ועם חמשת ילדיו – 011,021,031,041,051 ,כלומר אם בסיס 00 מעוניין להעביר פקודה לעלה 011 או לקרוא מידע מעלה 011 התעבורה צריכה להיות דרך עלה 01 שהוא האב של 011 והבן של 00 וכן על זה הדרך…

ואם נתרגם למספרים רגילים אז מודול 0 מדבר עם מודולים 1-5 ומודול 1 מדבר עם אביו(0) ועם מודולים 9,17,25,33,41(כפולות של 8).

מודול 2 מדבר עם אביו(0) ועם ילדיו שהם 10,18,26,34,42 (גם כן כפולות של 8) וכן הלאה.

חשבתי בהתחלה לשמור את כתובת העלים ב EEPROM אך לשם הפשטות הכנסתי לכל עלה את הכתובת שלו בתוך קוד המקור (hard coded).

אני מצרף כאן קוד מקור למודול הבסיס וקוד מקור לכל מודולי העלים כרגע הכל זה רישומים ל serial consule אין עדיין חיישנים או relays:

קוד הבסיס:

/*
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

/**
 * https://iot.org.il
 * Internet Of Things Implement by Arduino Pro and nrf24l01 
 * using RF24Network 
 *
 * Base NODE - main node with eventually internet gateway always with address 00
 * By Vardi Michael.
 * Adapt from Maniacbug - http://maniacbug.wordpress.com
 */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI>

// nRF24L01(+) radio attached using Getting Started board 
RF24 radio(9,10);
// Network uses that radio
RF24Network network(radio);
// Address of our node
const uint16_t this_node = 00;
// Address of the other node
uint16_t other_node;
// Structure of message
char bits[8];
struct a_message//structure of message(need to be less than 32 bytes)
{
  uint16_t addressTo; //where the message destination
  char digital1To8; // char with take 2 bytes - 8 bits so we can put inside one char 8 digital pins status...
  int A1;//sensor number 1
  int A2;//sensor number 2
  int A3;//sensor number 3
  int A4;//sensor number 4
  int A5;//sensor number 5
  char typeOfMsg;//is it sensor reading or digital command
  uint16_t addressFrom;//original origin of the message.
};

String getValue(String data, char separator, int index)
 {
 int found = 0;
 int strIndex[] = {0, -1};
 int maxIndex = data.length()-1;
 for(int i=0; i<=maxIndex && found<=index; i++)  {  if(data.charAt(i)==separator || i==maxIndex)  {  found++;  strIndex[0] = strIndex[1]+1;  strIndex[1] = (i == maxIndex) ? i+1 : i;  }  }  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
 }

void getBits(char c){
    for (int i = 7; i >= 0; --i)
    {
        bits[i]=(c & (1 << i)) ? '1' : '0';     } } void setup(void) {   Serial.begin(57600);   Serial.println("Base Node Started");   SPI.begin();   radio.begin();   network.begin(/*channel*/ 90, /*node address*/ this_node); } void loop(void) { 		// Pump the network regularly 		network.update(); 		String content = ""; 		char character;                 // Is there anything ready for us?                 while ( network.available() )                          {                                   // If so, grab it and print it out                                   RF24NetworkHeader header;                                   a_message message;                                   network.read(header,&message,sizeof(message));                                   Serial.print(message.addressFrom);                                   Serial.print(";"+message.A1);                                   Serial.print(";"+message.A2);                                   Serial.print(";"+message.A3);                                   Serial.print(";"+message.A4);                                   Serial.print(";"+message.A5);                                   Serial.println(";"+message.typeOfMsg);//+";"+message.A2+";");//+message.A3+";"+message.A4+";"+message.A5+";");//+";"+message.A2+";"+message.A3+";"+message.A4+";"+message.A5+";"+message.typeOfMsg);                        } 		while(Serial.available()) 			{ 				character = Serial.read(); 				content.concat(character); 				delay (1); 			}                  		if (content != "") 			{                             if(content !="ack")                             { 				a_message message = { getValue(content,';',0).toInt(), getValue(content,';',1).charAt(0),getValue(content,';',2).toInt(),getValue(content,';',3).toInt(),getValue(content,';',4).toInt(),getValue(content,';',5).toInt(),getValue(content,';',6).toInt(), getValue(content,';',7).charAt(0),getValue(content,';',8).toInt()}; 				 				if(message.addressTo>5)
                                    {
                                      if(message.addressTo>45)
                                           other_node = message.addressTo % 64;
                                      else
                                           other_node = message.addressTo % 8;
                                    }
                                 else  
                                     other_node = message.addressTo;

				RF24NetworkHeader header(/*to node*/ other_node);
                                Serial.print("Sending to node ");
                                Serial.println(other_node);
				bool ok = network.write(header,&message,sizeof(message));
				if (ok)
					Serial.println("ok");
				else
					Serial.println("failed");
                            }
                            else{
                                a_message message = { getValue(content,';',0).toInt(),'a',0,0,0,0,0,getValue(content,';',7).charAt(0),getValue(content,';',7).toInt()};

				if(message.addressTo>5)
                                    {
                                      if(message.addressTo>45)
                                           other_node = message.addressTo % 64;
                                      else
                                           other_node = message.addressTo % 8;
                                    }
                                 else  
                                     other_node = message.addressTo;

				RF24NetworkHeader header(/*to node*/ other_node);
                                Serial.print("Sending to node ");
                                Serial.println(other_node);
				bool ok = network.write(header,&message,sizeof(message));
				if (ok)
					Serial.println("ok");
				else
					Serial.println("failed");
                            }
			}
}

להלן קוד המקור של העלים(כאן זה דוגמה לעלה מספר 01 כלומר 1):

/*
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

/**
 * https://iot.org.il
 * Internet Of Things Implement by Arduino Pro and nrf24l01 
 * using RF24Network 
 *
 * Leaf NODE - Leaf node  with hardcoded address.
 * By Vardi Michael.
 * Adapt from Maniacbug - http://maniacbug.wordpress.com
 */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI>
// nRF24L01(+) radio attached using Getting Started board RF24 radio(9,10); // Network uses that radio RF24Network network(radio); // Address of our node const uint16_t this_node = 021; // Address of the other node const uint16_t base_node =00; uint16_t other_node; boolean is_queue=false; // Structure of message char bits[8]; struct a_message { uint16_t addressTo; char digital1To8; int A1; int A2; int A3; int A4; int A5; char typeOfMsg; uint16_t addressFrom; }; void getBits(char c){ for (int i = 7; i >= 0; --i) { bits[i]=(c & (1 << i)) ? '1' : '0'; } } void setup() { Serial.begin(57600); Serial.print(this_node); Serial.println(" Node Started"); SPI.begin(); radio.begin(); network.begin(/*channel*/ 90, /*node address*/ this_node); } void loop(void) { // Pump the network regularly network.update(); a_message message; // Is there anything ready for us? while ( network.available() ) { // If so, grab it and print it out delay(200); RF24NetworkHeader header; network.peek(header); network.read(header,&message,sizeof(message)); is_queue=true; } network.update(); if(is_queue) { if(message.addressTo==this_node&&message.addressFrom==base_node) { Serial.print("Received packet from "); Serial.print(message.addressFrom); Serial.print(";"); Serial.print(message.digital1To8); Serial.print(";"); Serial.print(message.A1); Serial.print(";"); Serial.print(message.A2); Serial.print(";"); Serial.print(message.A3); Serial.print(";"); Serial.print(message.A4); Serial.print(";"); Serial.print(message.A5); Serial.print(";"); Serial.print(message.typeOfMsg+";"); Serial.println(message.addressTo); } else { if(message.addressTo>45) { int tmpAddress; tmpAddress = message.addressTo / 64; other_node=tmpAddress*64+this_node%64; } else{ int tmpAddress; tmpAddress = message.addressTo / 8; other_node=tmpAddress*8+this_node%8; } RF24NetworkHeader header2(/*to node*/ other_node); a_message nextMsg = message; Serial.print("Sending to node "); Serial.println(other_node); bool ok = network.write(header2,&nextMsg,sizeof(nextMsg)); if (ok) Serial.println("ok"); else Serial.println("failed"); } is_queue=false; } } 

לצורך ניסוי ניקח 3 מודולים.

מודול ראשון יהיה מודול הבסיס ונעביר אליו את הסקיצה של קוד הבסיס.

מודול שני יהיה עלה שהוא בן ל 00 עם הכתובת 01.(יש לשנות את הכתובת של המודול בקוד מקור המצורף ל 01 במקום 021).

מודול שלישי הוא בן ל מודול שני 01 הוא יהיה 021 שזה המספר 17.

נפתח 3 מופעים של ה ARDUINO IDE לכל מודול נזהה באיזה פורט הוא מאזין (כמובן שיש לחבר לPRO MINI כבל תקשורת ע"מ שיוכל לתקשר טורית דרך ה USB עם המחשב וזה לא יכוסה פה) ונפתח בכל מופע את הSERIAL MONITOR ונאזין על הפורט הרלוונטי.

נקבל במודול הבסיס את ההודעה הבאה:

Base Node Started

ובמודולי העלה נקבל :

17 Node Started

או

1 Node Started

בהתאמה.

במוניטור הסיריאלי של נקודת הבסיס נזין את השדר הבא:

17;a;2;2;2;2;2;s;00

השדר:

17 – כתובת היעד

a – תו שמורכב משני בייטים כלומר 8 סיביות שיכולות לייצג מצב של 8 יציאות דיגיטליות וכך לבזבז פחות מקום בשדר.

2 – איזשהו קריאה של חיישן לדגמה

s – הודעה שהשדר הוא מסוג קריאת חיישן ולא פקודה כשלהיא ליציאה דיגיטלית

00 – כתובת מקור השדר.

ונראה שבעלה 01 התקבל השדר אך היות וזה לא מיועד אליו אלא הוא משמש כאן רק כ"תיבת ממסר" הוא מעביר את המסר לעלה המתאים שזה 021(17).

היות וטווח השידור והקליטה של  nrf24l01  מוגבלים היכולת לשרשר מודולים מאפשרת להרחיב את טווח השידור והקליטה של הרשת ולהתגבר על המגבלה הזאת.

קובץ פריטזינג וPDF מצורפים:

node

בית חכם – מבוא

רעיון "האינטרנט של דברים" מאוד מרתק – להפוך את הכל (!) לזמין ברשת .

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

מה צריך כדי ליצור את "האינטרנט של הדברים" הפרטי  שלי ובנוסף "להחכים" את הבית שלי ? מה העלות והמורכבות של הדברים?

הייתי רוצה פתרון קטן , זול וקל ליישום.

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

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

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

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

התצורות היותר פופולריות היום של ארדואינו:

ard2

ישנם הרבה מודולים עם אפשרויות תקשורת בהם שקלתי להשתמש :

IMAG1736

  • מיני מחשב X86 עם מערכת הפעלה XP/linux .
  • Raspberry PI.
  • ראוטר נייד או כל ראוטר שאפשר להתקין עליו קושחה כמו OPENWRT.
  • כרטיסי הרחבה של ארדואינו לרשת .
  • Bluetooth.

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

+nRF24L01 הוא  שבב  בעל צריכת חשמל נמוכה שמשדר בצורה אלחוטית בתדר 2.4GHz מחברת Nordic Semiconductor הוא משתמש בפרוטוקול SPI, ויש לו טווח תיאורי של כ -50 מטר פחות או יותר, תלוי אם הסביבה בין המשדרים נקייה ממכשולים/קירות ורוחב הפס הוא מספיק לצורך שידור נתוני חיישן וכו'.

כמובן שהעלה הראשי במערכת (base node) יכלול גם רכיב שיאפשר קישוריות לרשת כמו WIFI.

היום חיקוי של ארדואינו מיני פרו 5V ניתן לרכישה בEBAY בפחות מ-3$ והרכיב תקשורת כ- 1.2$ – בעצם מודול שישמש כבסיס ל- NODE ב 4$ כולל משלוח(!) אני לא חושב שכרגע ניתן לנצח את המחיר הזה(אפילו קניה רק של הצ'יפ עצמו – ATMEGA328P-PU בלבד יותר יקרה מהחיקוי לפרו) .

לצורך פיתוח השתמשתי בלוחות הארדואינו היותר נפוצים שיש להם גם יכולת התחברות בUSB למחשב.

IMAG1744 IMAG1742 IMAG1738

המודול הסופי יהיה כמובן מבוסס על ארדואינו ערום יותר כמו הפרו.

ההמשך בפוסט הבא…

 

זרוע רובוטית

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

לפני זמן מה מצאתי שקיימת זרוע צעצוע מאוד זולה וזמינה ברשת של חברה בשם – OWI.

זוהי זרוע מאוד פשוטה ללא כל בקר עם 5 מנועי DC פשוטים ושלט חוטי ללא כל אמצעי בקרה על מיקום כל מפרק של הזרוע.

היה לי מכר שביקר בארצות הברית לכן כל הזרוע עלתה לי 29$ כולל משלוח.

למי שאין מכר בחו"ל הזרועה כולל משלוח זמינה ב EBAY באזור ה 350 שקל כולל משלוח, ישנם כמה חנויות אינטרנטיות שמוכרות את הזרוע בארץ אך המחיר משמעותית יקר יותר.

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

רכיבים לפרויקט:

  1. ערכת זרוע .
  2. לוח ארדואינו (אני השתמשתי ב dumiliannov כי זה מה שהיה לי זמין).
  3. לוח הרחבה(מגן) (ציוד הקפי משלים לארדואינו) בקר מנועים של adafruit (קיימים העתקים לא מקוריים בחניות סיניות בעלות נמוכה יותר שם אני קניתי).
  4. בקר זוג מנועים רגיל כמו זה (היה לי בקר כזה שאחת היציאות שלו תקולה ולכן הוא יכול לשלוט רק על מנוע אחד אך זה הספיק – הסבר בהמשך ).
  5. מצלמת רשת שפורקה ממחשב נייד.
  6. פוטנציומטרים – נגדים משתנים 10K אני בחרתי ב 3 כאלה, אחד כזה, ואחד כזה.
  7. מזהה טווח אולטרה סוני כמו זה.

כל פוטנציומטר מחובר לפין אנלוגי שעל גבי הלוח הרחבה:

בנוסף ישנה מצלמה שפרקתי ממחשב נייד וחיברתי לה מחבר USB והיא ממוקמת ע"ג החלק העליון.

הארדואינו והמצלמה מחוברים למחשב המריץ וינדוס XP ע"ג מחשב קטן שמחובר לחלק התחתון של השולחן ושמשמש כשרת.

על המחשב הזה יש 2 תוכנות שרצות כ- service :

1. YAWCAM – תוכנה לשידור תזרים של פריימים ממצלמת הרשת שמחוברת למחשב .

2. node.js יחד עם socket.io express ו- serial . כל הקונפיגורציה הזאת כדי שיהיה ניתן לשלוט על הראדואינו בזמן אמת דרך אפליקציית javascript.

ישנם סליידרים לכל מפרק שמזיזים את הזרוע בהתאם לקריאה מהפוטנציומטרים ובנוסף ישנם כפתורים לכל מפרק שמזיזים את הזרוע ללא קשר לקריאה מהפוטנציומטרים.

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

מתחת לסטרים של המצלמה ישנו אלמנט של serial output terminal שלשם מוזרמת כל תכולת המסרים שמגיעים מהSERIAL של הארדואינו.

כל הקבצים הסטטיים (קבצי JS CSS HTML IMAGES) יושבים על שרת WEB חיצוני  והקישור למצלמה ולnodejs נעשה ישירות למחשב שמשמש כשרת כשהפורטים אליו פתוחים בפיירוול הביתי.

קוד הארדואינו:

//*************************************************************
//OWI Arm controller
//Include potenciometers for position.
//By Vardi Michael
//iot.org.il
//*************************************************************

#include
#include

#define PING_PIN A5 // Arduino pin tied to both trigger and echo pins on the ultrasonic sensor.
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(PING_PIN, PING_PIN, MAX_DISTANCE); // NewPing setup of pin and maximum distance.
int tempPing=0;
AF_DCMotor motor1(1); // Instantiate all the motors
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

int LED=2; //pin for LED
int gripperA=9; //pin for gripper close
int gripperB=10; //pin for gripper open

AF_DCMotor motorArray[]={motor1,motor2,motor3,motor4}; //put all motors in an array.

//function to drive all motors take 3 params - motor number,motor speed and motor direction( 1 or 2 to represent forward/backward).
void motorDrive (int motor,int motorSpeed,int motorDirection,int motorDuration)
{
digitalWrite(gripperA, LOW);//turn off gripper motor
digitalWrite(gripperB, LOW);
if(motor-1&gt;3)//motor-1 &gt;3 in the motors array mean its only gripper motor(ordenarry motor controller and not arduino motor shield).
{
if(motorDirection&gt;1) //1 mean forward and &gt;1 mean backwards
digitalWrite(gripperA, HIGH);
else
digitalWrite(gripperB, HIGH);
delay(motorDuration);
digitalWrite(gripperA, LOW);
digitalWrite(gripperB, LOW);
}
else
{
if(motorDirection&gt;1)
{
motorArray[motor-1].setSpeed(motorSpeed); // set the speed up to 255
motorArray[motor-1].run(BACKWARD);
}
else
{
motorArray[motor-1].setSpeed(motorSpeed); // set the speed to 100/255
motorArray[motor-1].run(FORWARD);
}
delay(motorDuration);
motorArray[motor-1].setSpeed(0);
motorArray[motor-1].run(RELEASE);
motorArray[motor-1].setSpeed(0);
}
}
//function to drive all motors to potentiometer position reading value;
int motorDrivePosition (int posit,int motor)
{
digitalWrite(gripperA, LOW);//turn off gripper motor
digitalWrite(gripperB, LOW);
int tempPositionVal = analogRead(motor-1);
int delta=tempPositionVal-posit;
while(abs(delta)&gt;40)
{
if((motor-1)&gt;3)//motor-1 &gt;3 in the motors array mean its only gripper motor(ordenarry motor controller and not arduino motor shield).
{
if(tempPositionVal&lt;posit) //1 mean forward and &gt;1 mean backwards
{
digitalWrite(gripperA, HIGH);
delay(10);
digitalWrite(gripperA, LOW);

}
else if(tempPositionVal&gt;posit)
{
digitalWrite(gripperB, HIGH);
delay(10);
digitalWrite(gripperB, LOW);

}
}

else if(motor==1)
{
if(tempPositionVal&gt;posit)
{
motorArray[motor-1].setSpeed(255); // set the speed up to 255
motorArray[motor-1].run(BACKWARD);
delay(10);
motorArray[motor-1].setSpeed(0);
motorArray[motor-1].run(RELEASE);
motorArray[motor-1].setSpeed(0);

}
else if(tempPositionVal&lt;posit) { motorArray[motor-1].setSpeed(255); // set the speed to 100/255 motorArray[motor-1].run(FORWARD); delay(10); motorArray[motor-1].setSpeed(0); motorArray[motor-1].run(RELEASE); motorArray[motor-1].setSpeed(0); } } else if(motor&gt;1&amp;&amp;motor&lt;5)
{
if(tempPositionVal&lt;posit) { motorArray[motor-1].setSpeed(255); // set the speed up to 255 motorArray[motor-1].run(BACKWARD); delay(10); motorArray[motor-1].setSpeed(0); motorArray[motor-1].run(RELEASE); motorArray[motor-1].setSpeed(0); } else if(tempPositionVal&gt;posit)
{
motorArray[motor-1].setSpeed(255); // set the speed to 100/255
motorArray[motor-1].run(FORWARD);
delay(10);
motorArray[motor-1].setSpeed(0);
motorArray[motor-1].run(RELEASE);
motorArray[motor-1].setSpeed(0);

}
}
tempPositionVal = analogRead(motor-1);
delta=tempPositionVal-posit;
}
Serial.println(tempPositionVal);
if(motor-1&gt;3)
{
digitalWrite(gripperA, LOW);
digitalWrite(gripperB, LOW);
}
else
{
motorArray[motor-1].setSpeed(0);
motorArray[motor-1].run(RELEASE);
motorArray[motor-1].setSpeed(0);
}
}
//function to "expload" string from serial with delimiting and return desired value
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i&lt;=maxIndex &amp;&amp; found&lt;=index; i++) { if(data.charAt(i)==separator || i==maxIndex) { found++; strIndex[0] = strIndex[1]+1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found&gt;index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void setup()
{
Serial.begin(9600); // set up Serial library at 9600 bps
motor1.setSpeed(100); // set the speed to 100/255
motor2.setSpeed(100); // do the same for the others...
motor3.setSpeed(100);
motor4.setSpeed(100);
//Setup gripper
pinMode(gripperA, OUTPUT); //Initiates Motor gripper Channel A pin
pinMode(gripperB, OUTPUT); //Initiates Motor gripper Channel B pin
pinMode(LED, OUTPUT); //Initiates lED pin
}

void loop()
{
//handel the serial communication...reading a string from serial
delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
if(abs(tempPing-(uS / US_ROUNDTRIP_CM))&gt;5)
{
Serial.print("ping;");
Serial.println(uS / US_ROUNDTRIP_CM); // Convert ping time to distance and print result (0 = outside set distance range, no ping echo)
}
tempPing=uS / US_ROUNDTRIP_CM;
String content = "";
char character;
while(Serial.available())
{
character = Serial.read();
content.concat(character);
delay (1);
}
if (content != "")
{
if(content =="ping")
{
Serial.print("ping;");
Serial.println(uS / US_ROUNDTRIP_CM); // Convert ping time to distance and print result (0 = outside set distance range, no ping echo)
}
else if(content =="ledon")
{
digitalWrite(LED, HIGH);
}
else if(content =="ledoff")
{
digitalWrite(LED, LOW);
}
else if(getValue(content,';',0) =="cp")//get current motors position report
{
int valtemp = analogRead(getValue(content,';',1).toInt()-1) ; // read the input pin 0
Serial.println(valtemp); // report the new readings
delay(10);
}
else if(getValue(content,';',0) =="pos")//drive motor to position of potentiometer
{
motorDrivePosition(getValue(content,';',1).toInt(),getValue(content,';',2).toInt());
}
else//call for motorDrive function according to string from serial
motorDrive(getValue(content,';',0).toInt(),getValue(content,';',1).toInt(),getValue(content,';',2).toInt(),getValue(content,';',3).toInt());
}
}