การทดลอง: วัดความเร็วการส่งข้อมูลผ่าน ESPNow
วัดความเร็วของ โพรโตคอล ESPNow และอ่านข้อมูลจาก Serial Port ด้วย NodeJS
หลังจากที่เราทดลองใช้ ESPNow กันมาสักระยะนึง ก็ได้ฤกษ์มาวัดความสามารถสูงสุดของตัวโพรโตคอลว่า… จะส่งได้ถี่สุดได้เท่าไหร่ ใช้พลังงานขนาดไหน… แต่บทความนี้จะทดสอบคร่าวๆ เกี่ยวกับความเร็วในการส่งข้อมูลก่อนนะครับ
บทความนี้คงจะเป็นบทความที่น่าเบื่อในสามโลก… มันจะออกแนวโพสไว้เตือนใจ ๕๕๕ ข้อมูลเชิงสถิติ หรือการทดลองที่ละเอียดกว่านี้คงเขียนถึงอีกทีครับ…
ESP-Now คืออะไร?
ESP-Now เป็นโพรโตคอลที่พัฒนาโดย Espressif system ครับ การติดต่อสื่อสารนั้นไม่จำเป็นต้องมีตัวกลางอย่างเช่น Access Point หรือ Router เลยครับ สามารถเชื่อมต่อกันตรงๆได้เลย การเชื่อมต่อกัน สามารถทำได้ทั้งระบุ และไม่ระบุ key ครับ เหมาะสำหรับทำ remote controll สั่งเปิด — ปิด หรี่ไฟเป็นต้น ตัวโพรโตคอลใช้ความถี่ที่ 2.4GHz ครับ การส่งข้อมูลทำได้รวดเร็ว
ความสามารถ
- Encrypted and unencrypted unicast communication.
- สื่อสารได้ทั้งอุปกรณ์ที่เข้ารหัส และไม่ได้เข้ารหัส
- ส่งข้อมูลได้ครั้งละ 250 byte ต่อครั้ง (payload)
- มี callback function ที่แจ้งเตือนเมื่อส่งข้อมูลออกไปว่า สำเร็จหรือไม่
ข้อจำกัด
- ยังไม่รองรับการสื่อสารแบบ broadcast
- จำกัด encrypted peers ได้แค่ 10 เท่านั้น ถ้า unencrypted ได้ถึง 20 ตัวครับ
- Payload หิ้วไปได้ครั้งละ 250byte
ผู้ที่สนใจสามารถหาข้อมูลเพิ่มเติมได้ที่ “Introduction to the ESP-Now” นะครับ
ทดลอง รับ — ส่ง — อ่านค่า
บทความนี้จะพูดถึงการทดลองเลยครับ.. ไม่อธิบายโค๊ดแล้วเนอะ พูดกันที่โค๊ดอย่างเดียวเลย… แล้วก็สรุปผลกันเลยครับ ซึ่งการทดลองนี้ Hardware จะใช้ ESPresso Lite 2.0 และ NodeWiFi เป็นตัวทดสอบครับ
Code ฝั่งส่ง (Slave)
โค๊ดไม่มีอะไรมากครับ ให้ delay 2ms นั่นแปลว่า
ใน 1 วินาที จะทำงาน 1000ms/2ms = 500 ครั้งนั่นเองครับ และจะใช้ฟังก์ชั่น esp_now_send
ส่งข้อมูลไปยัง master node ครับ
while(1) {
digitalWrite(LED_BUILTIN, ledState);
esp_now_send(master_mac, pkt, sizeof(pkt));
ledState = !ledState;
delay(2);
}
การจับเวลา
ผมใช้ Ticker
เข้ามาเป็น Timer คอยนับค่าทุกๆ 1 วินาที นับค่าจาก Callback ของ ESPNow โดยที่ไม่สนใจว่าจะ สำเร็จ หรือล้มเหลวครับ…
esp_now_register_send_cb([](uint8_t* macaddr, uint8_t status) {
recv_counter++;
});ticker.attach_ms(1000, []() {
Serial.printf("%d/s\r\n", recv_counter);
recv_counter = 0;
});
โค๊ดฝั่งรับ (Controller)
โค๊ดฝั่งรับทำเช่นเดียวกันครับ มี Timer ที่ทำงานทุกๆ 1 วินาที.. แล้วก็คอยเคลียร์ค่าที่รับมาได้.. แต่จะพิเศษนิดนึงคือ ถ้ากด GPIO 0 ค้างไว้ตอนโปรแกรมรันอยู่ จะส่งออกไปทาง Serial Port ด้วยครับ
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include "datatypes.h"
extern "C" {
#include <espnow.h>
#include <user_interface.h>
}
bool ledState = LOW;
Ticker ticker;#define BUTTON_PIN 0uint32_t freqCounter = 0;;void setup() {
Serial.begin(230400);
delay(10);
Serial.flush();
WiFi.disconnect();
pinMode(LED_BUILTIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP); Serial.print("Initializing... Controller..");
WiFi.mode(WIFI_STA);ticker.attach_ms(1000, []() {
Serial.printf("%d/s\r\n", freqCounter);
freqCounter = 0;
});if (esp_now_init() == 0) {
Serial.print("direct link init ok");
} else {
Serial.print("dl init failed");
ESP.restart();
return;
} esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); esp_now_register_recv_cb([](uint8_t *macaddr, uint8_t *data, uint8_t len) {
freqCounter++;
if (digitalRead(BUTTON_PIN) == LOW) {
Serial.write(data, len);
}
digitalWrite(LED_BUILTIN, ledState);
ledState = !ledState;
});
}void loop() {
yield();
}
Code ฝั่ง Bridge ข้อมูลจาก Serial Port
ส่วนนี้ผมเขียนด้วย NodeJS ครับ… และหลังการทดลองพบว่าเราส่ง packet ขนาด ~41bytes ฝั่ง ESP8266 ทำความเร็วได้ประมาณ 480Hz แบบนิ่งๆเลย แต่ถ้าเขียนออก Serial Port ที่ baudrate 115200
จะส่งข้อมูลไม่ทัน และ WDT Reset เลยครับ จึงต้องปรับขึ้นไปเป็น baudrate 230400
ครับ
var SerialPort = require('serialport');
var Parser = require('binary-parser').Parser;
const Delimiter = SerialPort.parsers.Delimiter;
var port = new SerialPort('/dev/tty.usbserial-A703X2U3', {
baudRate: 230400
});
const parser = port.pipe(new Delimiter({delimiter: Buffer.from('0d0a', 'hex')}));var packetCounter = 0;
var bytesCounter = 0;
setInterval(function () {
console.log(packetCounter + ' packet/s data = ' +
bytesCounter + ' bytes/s');
packetCounter = 0;
bytesCounter = 0;
}, 1000);
parser.on('data', function (data) {
bytesCounter += data.length;
if (data[0] === 0xff && data[1] === 0xfa) {
packetCounter++;
} else {
console.log(data.toString());
}
});
ผลการรันโปรแกรม
ถ้าไม่กด GPIO0 นั่นคือ ไม่ให้ทำ I/O Serial.write ความถี่ที่ทำได้คือ ~480Hz ค่อนข้างนิ่งเลย
480/s480/s480/s481/s479/s480/s481/s
แต่พอกด GPIO0 แล้วก็พบว่า ความเร็วในการรับข้อมูลจาก ESPNow ยังคงได้ 480packets/s
นั่นคือ 19680 bytes/s
แต่ข้อมูลจาก Serial Port มีความไม่สม่ำเสมออยู่บ้าง.. ตามข้อมูลข้างล่าง…
369 packet/s data = 15134 bytes/s461 packet/s data = 18906 bytes/s553 packet/s data = 22678 bytes/s395 packet/s data = 16200 bytes/s558 packet/s data = 22883 bytes/s461 packet/s data = 18906 bytes/s431 packet/s data = 17676 bytes/s553 packet/s data = 22678 bytes/s439 packet/s data = 18004 bytes/s
บทสรุป
วันนี้เราทดสอบโพรโตคอล ESPNow รับส่งข้อมูลด้วยความเร็วสูง ขนาด packet ประมาณ 41bytes พยายามส่งข้อมูล ทุกๆ 2ms (500Hz)
พบว่าส่งได้ประมาณ 480Hz แล้วก็ส่งผ่าน SerialPort ที่ Baudrate 230400 ได้ความเร็วประมาณ 19229.444 B/s
(เฉลี่ยนิดเดียวนะครับ)
ก็ประมาณนี้ก่อนครับ…