จับ Node32s (EPS32) มาคุยกับ Raspberry Pi ผ่าน Wireless Network

ถ้าเปรียบกับดาราภาพยนต์ ก็ต้องบอกว่า ESP32 กำลังดังครับ มีหลายต่อหลายคนกำลังกล่าวถึงและเขียนเรื่องราวเกี่ยวกับ EPS32 ผมเองได้รับบอร์ดนี้มาเมื่อวันที่ 13 พ.ย. ที่ผ่านมานี้เอง เมื่อได้มาแล้วก็อยากจะเขียนถึงสักหน่อย





ผมจะไม่ review board นะครับ เพราะต้องให้ท่านอื่นที่มีความรู้แน่นอนกว่าผมเขียนจะดีกว่า หรือท่านอาจหาอ่านได้เองจากเว็บไซต์ของ Espressif เลยก็ดี ครับ ส่วนเรื่องที่จะเขียนคือการรับ-ส่งข้อมูลระหว่าง Node32s กับ Raspberry Pi ครับ ผ่าน TCP ครับ

ความจริงแล้วทาง Espressif เขามี SDK สำหรับการเขียนโปรแกรม แต่ด้วยความชอบ Arduino ผมเลยเลือกที่จะใช้ Arduino IDE เพื่อใช้การเขียนโปรแกรมทางฝั่ง Node32s  ซึ่งก็มีข้อจำกัดอยู่ เพราะในเวลาที่เขียนเรื่องนี้  Arduino - IDE ยังไม่สนับสนุน Esp32 เต็มที่ สามารถเรียกใช้งานได้เพียงบางส่วนเท่านั้นเอง แต่ก็มีสนับสนุน WiFi Client แล้ว ซึ่งเป็นจุดที่จะนำมาเขียนในครั้งนี้ ครับ

1. ปรับแต่ง Arduino-IDE

ก่อนอื่นเลยต้องมี Arduino-IDE ก่อน ครับ (https://www.arduino.cc/en/Main/OldSoftwareReleases)
ขั้นตอนการปรับแต่งในระบบปฏิบัติการ Windows อ่านได้จากhttp://www.ayarafun.com/2016/10/arduino-esp32-first-touch/ ครับ แต่ผมใช้ Ubuntu วิธีการจะต่างไปเล็กน้อย เพราะ Linux จะมี python 2.7 ติดตั้งมาแล้ว เหลือแต่ pyserial  (ถ้าเป็น raspbian ข้ามไปเลย ครับ เพราะมีมาครบหมดแล้ว) ติดตั้งด้วย

$ sudo pip install pyserial

หมายเหตุ : pyserial จะทำงานกับระบบ 32  bit ครับ

หลังต่อ PC เข้ากับ Node32s แล้ว เปิด Arduino - IDE ขึ้นมา ผมเลือก Board เป็น Nano32




2. สร้าง Code ฝั่ง Node32s

ตอนนี้ท่านหา สาย micro USB มาต่อระหว่าง Node32s กับคอมพิวเตอร์ เหมือนการต่อ Arduino ได้เลย เปิด Arduino IDE ขึ้นมาแล้วพิมพ์ code ข้างล่างตามลำดับ

ส่วนที่ 1 : Library 


#include <WiFi.h>



ส่วนที่ 2 : กำหนดตัวแปร


const char* _SSID  = "xxxxxxxxxx";
const char* _PWD  = "xxxxxxxxxx";
const char* _HOST = "xxxxxxxxxx";
const uint16_t _PORT = 9999;
boolean _ready;
String msgs[3] = {"Hello I am Node32s  ","I am from Thailand  ","Nice to meet you    "};
int c = 0;


_SSID คือชื่อของ router หรือ access point
_PWD คือ รหัสผ่านของ router หรือ access point
_HOST คือ address ของ server ในกรณีนี้หมายถึง ip address ของ raspberry pi
_PORT คือ หมายเลข port สื่อสารบน raspberry pi
_ready คือ ตัวแปรใช้บอกสถานะการทำงาน
msgs คือ ข้อความที่ใช้ส่งไปยัง Raspberry Pi

ส่วนที่ 3 : ต่อ WiFi

void wifi_connect(){
  if(WiFi.isConnected()) return;
  Serial.println("Connecting to "+String(_SSID));
  WiFi.begin(_SSID,_PWD);
  while(WiFi.status()  != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  _ready = true;
}

code ส่วนนี้ใช้ในการเชื่อมต่อไปยัง router หรือ access point  คำสั่งที่ควรรู้จักคือ

  • WiFi.begin(ssid,pwd) เป็นการเชื่อมไปยัง router เพื่อของ IP address
  • WiFi.status() แจ้งให้ทราบถึงสถานะการเชื่อมต่อกับ router 
  • WiFi.isConnected() จะให้ true หากว่า Esp32 ได้ทำการติดต่อกับ router แล้ว
  • WiFi.localIP() บอกให้ทราบว่าขณะนั้น Esp32 มี IP address เป็นอะไร

ส่วนที่ 4 : ส่งข้อความให้ Rasbperry Pi



void sendMsg(String msg){
  WiFiClient client;
  Serial.println("");
  Serial.print("Send : ");
  Serial.println(msg);
  if(!client.connect(_HOST,_PORT)){
     Serial.println("Connection faild.");
     return;
  }  
  byte buf[20];
  msg.getBytes(buf,20); 
  client.write(buf,20);
  
 unsigned long timeout = millis();
  while (client.available() == 0)   {
    if (millis() - timeout > 5000) 
    {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }

  while (client.available()) {
    String line = client.readStringUntil('\r');
    Serial.print("Recieve :");
    Serial.println(line);
    Serial.println("--------------------------");
  }
  
  client.stop();
  _ready = true;
}


  1.  เริ่มต้นด้วยการสร้างตัวแปร client ซึ่งเป็น instance ของ WiFiClient
  2.   ทำการเชื่อมต่อไปยังอุปกรณ์ปลายทาง (Raspberry Pi) ด้วยคำสั่ง client.connect(_HOST,_PORT)
  3.  เนื่องจาก Python3 ที่จะใช้งานทางฝั่ง Raspberry Pi นั้นจะรับ-ส่งข้อมูลด้วย data type เป็น byte  ไม่ใช่ String ดังนั้นเราต้องเปลี่ยนข้อความให้กลายเป็น byte ด้วยคำสั่ง getBytes(buf,length) โดย ข้อความที่เป็น byte จะถูกเก็บไว้ในตัวแปร buf ส่วน length นั้นคือความยาวหรือจำนวนตัวอักษรของข้อความ
  4.  การส่งข้อความออกไปใช้คำสั่ง client.write(buf,length)
  5.  ถัดลงมาเป็นการกำหนด timeout ในการรอข้อความตอบกลับจากอีกฝั่งหนึ่ง  ซึ่งในกรณีนี้กำหนดไว้ 5000 milliseconds  โดยการวนลูปจนกว่า client.available() จะไม่เท่ากับ 0
  6.  เมื่อมีข้อความเข้ามา ก็ให้พิมพ์ข้อความนั้นออกหน้าจอ


ส่วนที่ 5 : Code หลัก

void setup() {
  Serial.begin(115200);
  wifi_connect();
  _ready = false;
  delay(1000);  
}

void loop() {
 if(_ready && c < 3){
  sendMsg(msgs[c]);
  c+=1;
}

 delay(1000);
}

เป็นการทำงานแบบง่าย ๆ เพื่อให้เห็นขั้นตอนการทำงาน เริ่มต้นด้วยการเชื่อมต่อไปยัง router หรือ access point เพื่อขอ IP Address  แล้วก็วนลูปเพื่อส่งข้อความออกไป รอ echo กลับ

code ทั้งหมดของ Node32s


#include <WiFi.h>

const char* _SSID  = "xxxxxxxxxx";
const char* _PWD  = "xxxxxxxxxx";
const char* _HOST = "xxxxxxxxxx";
const uint16_t _PORT = 9999;
boolean _ready;
String msgs[3] = {"Hello I am Node32s  ","I am from Thailand  ","Nice to meet you    "};
int c = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  wifi_connect();
  _ready = true;
  delay(1000);  
}

void loop() {
 if(_ready && c < 3){
  sendMsg(msgs[c]);
  c+=1;
}
 delay(1000);
}

void wifi_connect(){
  if(WiFi.isConnected()) return;
  Serial.println("Connecting to "+String(_SSID));
  WiFi.begin(_SSID,_PWD);
  while(WiFi.status()  != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void sendMsg(String msg){
  WiFiClient client;
  Serial.println("");
  Serial.print("Send : ");
  Serial.println(msg);
  if(!client.connect(_HOST,_PORT)){
     Serial.println("Connection faild.");
     return;
  }  
 
  byte buf[20];
  msg.getBytes(buf,20); 
  client.write(buf,20);
  
 unsigned long timeout = millis();
  while (client.available() == 0)   {
    if (millis() - timeout > 5000) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }

  while (client.available()) {
    String line = client.readStringUntil('\r');
    Serial.print("Recieve :");
    Serial.println(line);
    Serial.println("--------------------------");
  }
  
  client.stop();
  _ready = true;
}


ทำการ Save และ Compile เช่นเดียวกับการใช้ Arduino  หาก compile เสร็จแล้วและไม่พบ error จะเห็นข้อความดังภาพ



ทำการ upload ไปยัง Node32s ก็จะเห็นข้อความปรากฏตามภาพ เป็นอันเสร็จงานทางฝั่ง Node32s


3. สร้าง Code ฝั่ง Raspberry Pi

ทางฝั่งของ Raspberry Pi จะทำหน้าที่เพียงอย่างเดียวคือการรับข้อความแล้วส่งข้อความนั้นกลับไปยังผู้ส่ง (EchoServer) โดยจะใช้ Python3.4 ที่มีอยู่แล้ว เหตุเพราะว่าต้องการแนะนำ asyncio library ใหม่ที่เพิ่งเริ่มมีการใช้งานใน Python3.4 หรือใหม่กว่าเท่านั้น ซึ่ง asyncio ช่วยให้การพัฒนาโปรแกรมสื่อสารด้วย Python ง่ายขึ้นมากเมื่อเทียบกับการใช้ socket โดยตรง


import asyncio
msgs = [b'Hello I am Raspi   ',b'I am from England    ',b'Nice to meet you too']
c = 0
class EchoServer(asyncio.Protocol):
     def connection_made(self,transport):
          self.transport = transport

     def data_recieved(self,data):
          im = data.decode('utf-8')
          if im[0] == 'H':
             self.transport.write(msgs[0])
          if im[0] == 'I':
             self.transport.write(msgs[1])
          else :
             self.transport.write(msgs[2])

loop = asyncio.get_event_loop()
coro = loop.create_server(EchoServer,'',10000)
server = loop.run_until_complete(coro)
try:
     loop.run_forever()
except :
     pass

server.close()
loop.run_until_complete(server.wait_closed())
loop.close()


ลำดับการทำงานของ code ในส่วนที่ทำงานบน Raspberry Pi อย่างคร่าว ๆ มีดังนี้

  1. กำหนดค่าของข้อความสำหรับตอบกลับไปยัง Node32s
  2. สร้าง class EchoServer  โดยทำงานอยู่สองอย่างคือ
    1. สร้าง transport ที่รับผิดชอบต่อ connection ที่มีเข้ามา
    2. ตอบข้อความไปยัง client ที่เชื่อมต่อเข้ามาผ่าน transport ที่ได้จากข้อ 1
  3. สร้าง loop ในการทำงาน

 และสุดท้ายก็นำผลการทำงานมาให้ดูในวิดีโอนี้แสดงผลที่เกิดขึ้นทางฝั่ง Node32s ครับ จะเห็นได้ว่า Node32s กับ Raspberry Pi มีการส่งข้อความ โต้ตอบไปมาระหว่างกัน เหมือนการเล่นปิงปอง ซึ่งก็พอที่จะทำให้เห็นภาพการสื่อสารระหว่างอุปกรณ์ทั้งสองผ่าน Wireless Network นะครับ





Previous
Next Post »