ดิว.นินจา

ดิว.นินจา

Wednesday, July 12, 2017

การส่งข้อมูลจาก Freeboard Slider หลายตัวไปยัง ESP8266 microgear

NETPIE Series

จากตัวอย่าง ex5_3.ino ในหนังสือ “ตัวควบคุมป้อนกลับบนอินเทอร์เน็ตโดย ESP8266” ได้แสดงการควบคุมและแสดงผลผ่าน NETPIE เบื้องต้น โดยใช้ slider widget ส่งคำสั่งอ้างอิงให้กับตัวควบคุม และส่งข้อมูล 3 ค่ากลับไปแสดงผล จากตัวอย่างจะเห็นว่าการส่งข้อมูลหลายชุดไปยัง NETPIE สามารถทำได้โดยง่าย แต่การที่จะส่งข้อมูลจาก NETPIE ไปยังบอร์ดมากกว่าหนึ่งตัวยังคงเป็นปัญหาที่ยังไม่มีการแสดงวิธีการอย่างชัดเจน ซึ่งจากการบรรยายในชั้นก็มีคำถามนี้จากผู้เรียน

อ้างถึงตัวอย่างในหนังสือ เราได้ใช้คำสั่ง microgear.chat ใน Slider widget


microgear["myIoFCcontrol"].chat("myIoFCdevice",value)

ซึ่งทางด้านESP8266 จะมีฟังก์ชัน onMsghandler() เพื่อรับข้อความ


void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen) {
  char *m = (char *)msg;
  m[msglen] = '\0';
  float rc = atof(m);
  Serial.print("new r = ");
  if (rc>=0 && rc<=3)   {
    r = rc;
    Serial.println(rc);
    microgear.publish("/myIoFCdevice/rc",rc);
  }
}

และแปลงให้เป็นตัวแปรแบบ float ก่อนจะอัพเดทตัวแปรคำสั่งอ้างอิง r และ publish กลับไปเพื่ออัพเดทตำแหน่งของ slider

ปัญหาที่เป็นประเด็นหลักของบทความนี้คือ สมมุติว่านอกจากส่งคำสั่งอ้างอิงแล้ว ต้องการมี sliders อีก 3 ตัวเพื่อปรับค่าพารามิเตอร์ PID จะทำอย่างไรให้ฟังก์ชัน onMsghandler() สามารถแยกได้ว่าคำสั่งมาจาก slider ตัวใด? วันนี้เราจะมาศึกษาส่วนนี้กันครับ

ผู้เขียนยอมรับว่ายังไม่มีความรู้เกี่ยวกับ NETPIE มากกว่าการใช้งานพื้นฐาน จึงได้ตั้งคำถามใน NETPIE Public Group และได้รับคำแนะนำที่เป็นประโยชน์จาก Project Leader ของ NETPIE เองว่า “ต้องระบุ มาใน msg ด้วยว่าค่าที่ส่งมานี้สำหรับ parameter ไหน อย่าส่งแต่ตัวเลข”

Bingo! ฟังดูแล้วเหมือนกับว่าวิธีการนี้ก็ไม่แตกต่างจากการสร้างฟังก์ชันรับคำสั่งที่อธิบายในหนังสือ เพียงแต่เปลี่ยนจากสื่อสารผ่านพอร์ตอนุกรมเป็นจาก Slider widgets มายัง onMsghandler() นั้นเอง เช่นหากรับข้อความว่า “r=1” ก็ต้องแยกคำสั่งคือ r และค่าที่ต้องการตั้งให้กับตัวแปร r คือ 1 ถ้าได้รับ “kp=0.4” ก็ตั้งค่าตัวแปร kp เป็น 0.4 เป็นต้น

ซึ่งโค้ดตรงส่วนนี้เรารู้แล้วว่าจะทำอย่างไรหากท่านมีหนังสือ หรือเพียงแต่ดาวน์โหลดตัวอย่างโปรแกรมจากหน้าเพจของหนังสือ สิ่งที่ต้องเรียนรู้เพิ่มคือจะทำอย่างไรให้ slider widget ส่งข้อมูลเพิ่มเติมมาพร้อมตัวเลข

หลังจากอ่านตัวอย่างจากคู่มือของ NECTEC และทดลองดู พบว่าเพียงเพิ่มข้อความที่ต้องการเข้าไปก็ทำงานได้ ตัวอย่างเช่นหากต้องการส่งข้อความ “r=xx” แทนตัวเลข “xx” อย่างเดียว แก้คำสั่งใน slider เป็นดังนี้



microgear["myIoFCcontrol"].chat("myIoFCdevice","r="+value)

เพื่อแสดงให้เห็นเป็นรูปธรรม เราจะสร้างตัวอย่างง่ายๆ ขึ้นมาใหม่โดยสนใจเพียงการส่งค่าจาก slider 3 ตัวมายังบอร์ด ESPino โดยฮาร์ดแวร์ที่ใช้ประกอบคือบอร์ด LAG3 ที่ออกแบบมาสำหรับทดลองใน workshop ดังแสดงในรูปที่ 1

รูปที่ 1 บอร์ด LAG3 ที่ใช้ทดสอบร่วมกับบอร์ด ESPino

รายละเอียดของบอร์ดนี้สามารถอ่านได้จาก เพจประกอบหนังสือ ส่วนของวงจรอิเล็กทรอนิกส์ที่จะใช้ในบทความนี้คือ RGB LED ขนาดเล็กทางด้านซ้ายเท่านั้น โดยมีขาแอโนดของสี R=แดง, G=เขียว, B=น้ำเงิน ต่ออยู่กับขา GPIO 12, 2, 14 ของ ESP8266


โจทย์ของตัวอย่างนี้คือใช้ Slider 3 ตัว ส่งค่า R, G, B ในช่วง 0 – 1023 (PWM ของ ESP8266 มีขนาด 10 บิต) ให้กับบอร์ด ESPino ซึ่งจะทำหน้าที่ขับ RGB LED ให้มีเฉดสีตามค่าที่ตั้งโดย Sliders สำหรับตัวอย่างนี้จะไม่มีการส่งข้อมูลใดๆ ไปแสดงผลบน NETPIE


เริ่มต้นโดยล็อกอินเข้าไปที่ netpie.io และสร้างแอปปลิเคชันใหม่ ให้ชื่อว่า myRGB และสร้าง datasource บน freeboard ชื่อ myRGBboard รายละเอียดส่วนนี้จะเหมือนกับที่อธิบายในหนังสือจึงไม่ขอกล่าวถึงอีก

เพิ่ม Sliders 3 ตัวบน Freeboard ให้ชื่อว่า R, G, B ดังในรูปที่ 2

รูปที่ 2 Slider widgets สำหรับควบคุมสี R,G,B

สำหรับทางด้าน ESP8266 สามารถเริ่มต้นโดยใช้โปรแกรมตัวอย่างของ microgear แก้ไขส่วนของ APPID, KEY, SECRET และตั้งชื่อ ALIAS ในตัวอย่างนี้ให้ชื่อว่า myRGBdevice ตั้งค่าของ WiFi AP ให้ตรงกับที่มีอยู่ในพื้นที่ โหลดลงบนบอร์ดและเปิดดู Serial Monitor หากตั้งค่าทุกอย่างถูกต้องบอร์ดก็จะเชื่อมต่อกับแอปปลิเคชันบน NETPIE คือ myRGB เมื่อตรวจสอบจะเห็นว่ามีอุปกรณ์ชื่อ myRGBdevice มาต่อเชื่อมอยู่

คลิกที่แต่ละ Slider และพิมพ์คำสั่งในแต่ละฟิลด์ สำหรับตัวอย่างง่ายๆ นี้ฟิลด์ AUTO UPDATED VALUE ไม่จำเป็นต้องใช้ รูปที่ 3 แสดงการตั้งค่าสำหรับ R Slider

รูปที่ 3 การตั้งค่าสำหรับ Slider ควบคุมสีแดง

จะเห็นว่าคำสั่งที่ใช้ในทุกช่องก็คือ



microgear["myRGBboard"].chat("myRGBdevice","r="+value) 

ซึ่งก็คือการเพิ่มสตริง “r=” ก่อนหน้าค่าตัวเลขจาก slider นั่นเอง สมมุติว่า slider ถูกปรับไปที่ 275 สตริงที่ส่งให้กับ ESP8266 ก็คือ “r=275” ทำให้เราสามารถเขียนโปรแกรมเพื่อตรวจสอบได้ว่าค่านี้ถูกส่งมาจาก R slider

สำหรับ G และ B Sliders ตั้งค่าด้วยคำสั่งตามลำดับดังนี้



microgear["myRGBboard"].chat("myRGBdevice","g="+value)
microgear["myRGBboard"].chat("myRGBdevice","b="+value) 

ทดลองเลื่อนตัวปรับของ slider แต่ละอันแล้วดูที่ Serial Monitor รูปที่ 4 แสดงให้เห็นว่าฟังก์ชัน onMsghandler() สามารถรับค่าสตริงที่ถูกส่งมาได้อย่างถูกต้อง (ถึงแม้ว่าในการปรับแต่ละครั้งอาจเห็นข้อความซ้ำกันมากว่า 1 ครั้งก็ไม่เป็นปัญหาแต่อย่างใดสำหรับตัวอย่างนี้)

รูปที่ 4 แสดงค่าสตริงที่ถูกส่งมาจาก Slider แต่ละอัน

เมื่อได้ผลตามที่แสดงในรูปที่ 4 ทำให้เรามั่นใจว่าสามารถบรรลุตามวัตถุประสงค์ เพราะส่วนที่เหลือเป็นเพียงการเขียนโค้ดภาษา C ซึ่งส่วนใหญ่เป็นเพียงนำของเดิมมาใช้

เพื่อให้ง่ายต่อการตรวจสอบ เราจะให้ค่าของ R, G, B ที่ถูกส่งมาแสดงที่จอ OLED ด้วย คัดลอกฟังก์ชันของเดิมจากหนังสือมาใส่ได้เลยเพียงแค่ดัดแปลงเล็กน้อย

ในส่วน setup() เพิ่มการกำหนดขาเอาต์พุตให้ LED



pinMode(RLED, OUTPUT);
pinMode(GLED, OUTPUT);
pinMode(BLED, OUTPUT);  

โดยนิยาม RLED=12, GLED=2, BLED = 14 ไว้ส่วนบนของโปรแกรม สำหรับการส่งค่า PWM ให้กับขา R,G,B ของ LED เขียนเป็นฟังก์ชันเพื่อความเป็นระเบียบ



void lidRGBled(int rval, int gval, int bval)
{ 
  analogWrite(RLED, rval);
  analogWrite(GLED, gval);
  analogWrite(BLED, bval);  
} 

การแยกค่า R,G,B ทำได้หลายวิธีตามที่ท่านถนัด ในที่นี้เราใช้วิธีที่เคยทดลองแล้วว่าได้ผล เขียนเป็นฟังก์ชันได้ดังนี้



void cmdInt(void)
{
    rcvdstring.trim();  // remove leading&trailing whitespace, if any
    // find index of separator "="
    sepIndex = rcvdstring.indexOf('=');

    // extract command and parameter
    cmdstring = rcvdstring.substring(0, sepIndex);
    parmstring = rcvdstring.substring(sepIndex+1); 
    if (cmdstring.equalsIgnoreCase("r"))   {
      Rval=parmstring.toInt();
    }
    else if (cmdstring.equalsIgnoreCase("g"))   {
      Gval=parmstring.toInt();
    }
    else if (cmdstring.equalsIgnoreCase("b"))   {
      Bval=parmstring.toInt();
    }    
} 

อธิบายโดยสังเขปได้ว่าค่าสตริงที่ถูกเก็บในตัวแปร rcvdstring ถูกแยกเป็นส่วนของคำสั่ง (ก่อนหน้าเครื่องหมาย “=”) และพารามิเตอร์ (หลังเครื่องหมาย “=”) เก็บในตัวแปร cmdstring และ parmstring ที่เป็น String object มีข้อดีคือมี methods ให้ใช้ได้โดยสะดวก ตัวอย่างเช่นการเปลี่ยนค่าสตริงเป็นเลขจำนวนเต็มใช้ parmstring.toInt()

สำหรับฟังก์ชัน onMsghandler() เขียนใหม่ได้เป็นดังนี้



void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen) {
  char *m = (char *)msg;
  m[msglen] = '\0';
  rcvdstring = m;  // คัดลอกข้อความใส่ใน String object 
  cmdInt();  // แยกคำสั่งตามสี R,G,B
  lidRGBled(Rval,Gval,Bval); // ส่งเอาต์พุตไปยัง LED
  showOLED(Rval,Gval,Bval); // แสดงค่าบนจอ OLED
} 

หมายเหตุ: ตัวแปรบางส่วนนิยามไว้แบบ global ที่ส่วนบน ซึ่งโปรแกรมทั้งหมดรวมอยู่ใน rgb3sliders.ino สามารถดาวน์โหลดได้ด้านล่าง

คอมไพล์ rgb3sliders.ino (อย่าลืมใส่ข้อมูล NETPIE Application และ WiFi AP ของท่านก่อน) และโหลดลงบนบอร์ด (ที่ต่ออยู่กับ RGB LED) วีดีโอด้านล่างนี้แสดงให้เห็นว่า slider ทั้งสามสามารถส่งคำสั่งให้กับ RGB LED ได้อย่างถูกต้อง)

ดาวน์โหลด rgb3sliders.ino

ติดตามข่าวสารการฝึกอบรมเกี่ยวกับ Embedded Control ได้ที่เพจ https://www.facebook.com/dewninjathai/

4 comments:

  1. ขอบคุณมากๆครับ กำลังหาแนวทางใช้ slider พอดีเลยครับผม ^_^

    ReplyDelete
  2. ขอโคดแบบเต็มๆหน่อยได้ใหมครับ ผมพึ่งเริ่มเรียน

    ReplyDelete
  3. โค้ดเต็มๆ อยู่ในไฟล์ rgb3sliders.ino มีลิงก์ให้โหลดได้ครับที่ด้านล่างบทความ

    ReplyDelete

แนะนำหนังสือ “ตัวควบคุมป้อนกลับบนอินเทอร์เน็ตโดย ESP8266”

ปัจจุบันเมื่อกล่าวถึงอุปกรณ์ IoT (Internet of Things) คงมีน้อยคนที่จะไม่รู้จัก ในยุคที่การเข้าถึงอินเทอร์เน็ตเป็นกิจวัตรประจำวันของมนุษย์เ...