NETPIE Series
ในบทความนี้เราจะปรับปรุงส่วนติดต่อผู้ใช้บน freeboard ที่สร้างไว้ใน บทที่ 6 ของหนังสือ “ตัวควบคุมป้อนกลับบนอินเทอร์เน็ตโดย ESP8266” ให้เหมาะสมกับการใช้ในงานควบคุมอุตสาหกรรมจริง ตัวควบคุม IoFC ได้ถูกออกแบบให้มีความยืดหยุ่น คือสามารถปรับพารามิเตอร์ได้ทั้งที่หน้างานผ่านพอร์ตอนุกรม และจากระยะไกลโดย NETPIE แต่หน้าควบคุม freeboard จากตัวอย่างที่ 6.4 ในหนังสือยังไม่ได้ออกแบบให้รองรับกรณีมีผู้ปฏิบัติงานทั้ง 2 สถานที่ เพราะหากมีการเปลี่ยนค่าพารามิเตอร์ที่หน้างาน ส่วนควบคุมใน NETPIE จะไม่อัพเดตตาม เราจะมาศึกษาวิธีแก้ปัญหานี้โดยใช้ฟังก์ชัน microgear.publish() และเพิ่มการตั้งค่าใน freeboard widgets
ฮาร์ดแวร์ที่ใช้ทดสอบคือ WEMOS LOLIN32 และรันโปรแกรมจากบทความก่อนหน้านี้คือ
“การติดตั้งและแก้ปัญหาไลบรารีสำหรับ ESP32 เพื่อใช้งานกับ Arduino IDE และ NETPIE” ซึ่งจะใช้งานร่วมกับ NETPIE freeboard ในตัวอย่าง 6.4 ในหนังสือได้ เมื่อเข้าหน้า Freeboard จะมีหน้าตาดังแสดงในรูปที่ 1
รูปที่ 1 หน้าตา Freeboard จากตัวอย่าง 6.4 ในหนังสือ
ในบทความนี้จะไม่กล่าวถึงส่วน gauges และ feed ส่วนบน แต่มุ่งเน้นไปที่ control widgets คือตัว sliders และ toggle switches ในส่วนล่างของ Freeboard สังเกตค่าเริ่มต้นของแต่ละ widgets ซึ่งจะเป็นค่าที่ตั้งไว้ในแต่ละตัว ตัวอย่างเช่นเมื่อเราคลิกที่รูปประแจบน slider ของ Proportional Gain Kp จะเห็นการตั้งค่าในรูปที่ 2 สังเกตว่าค่าเริ่มต้นจะถูกกำหนดไว้ในฟิลด์ INITIAL VALUE ที่ใส่ค่าเท่ากับ 5 ดังนั้นเมื่อเปิดหน้าต่างมาครั้งแรก (หรือเมื่อกด refresh) ค่าจึงถูกตั้งไว้ที่ 5 sliders ตัวอื่นๆ ก็จะทำงานแบบเดียวกัน
รูปที่ 2 การตั้งค่า slider ในตัวอย่าง 6.4
ข้อสังเกตอีกจุดหนึ่งก็คือ ในขณะนี้ฟิลด์ AUTO UPDATED VALUE ถูกปล่อยว่างไว้ ซึ่งต่อไปเราจะใช้ฟิลด์นี้ในการปรับค่าของ sliders ให้ตรงกับความเป็นจริง
ดังนั้น เมื่อเปิดหน้าต่างมาครั้งแรก ไม่สามารถรับประกันได้ว่าค่าของ sliders และ toggle switches จะตรงกับค่าจริงในตัวควบคุมขณะนั้น ตรวจสอบง่ายๆ โดยเปิด serial monitor และถามค่าพารามิเตอร์ (โดยพิมพ์ชื่อพารามิเตอร์ที่ต้องการทราบ เช่น kp ในช่องบนสุด) พบว่าค่าจริงเป็นดังที่แสดงในรูปที่ 3 ที่แตกต่างจากค่าใน Freeboard นอกจากนั้นเมื่อตรวจสอบว่าใช้ตัวควบคุมแบบใหนอยู่ พบว่าเป็นแบบ CC (Custom Controller) แต่ปุ่ม toggle บน Freeboard ในรูปที่ 1 แสดง PID ซึ่งไม่ตรงกับความเป็นจริง
ทดลองตั้งค่าใหม่โดยพิมพ์ใน serial monitor เช่น kp=6 หรือ adma=on ค่าในตัวควบคุมจะถูกเปลี่ยน แต่ Freeboard จะไม่มีทางทราบเลย
รูปที่ 3 ค่าจริงของพารามิเตอร์และสถานะตัวควบคุม
วิธีง่ายที่สุดในการทำให้ค่าตรงกันตอนเริ่มต้นคือ ใส่คำสั่งในช่อง ON CREATED ACTION เพื่อส่งค่าไปอัพเดทค่าในตัวควบคุม แต่ไม่แนะนำวิธีนี้ด้วยเหตุผล 2 ประการคือ
เราจะแน่ใจได้อย่างไรว่าค่าใน Freeboard เหมาะสมกว่าค่าที่ใช้อยู่บนตัวควบคุมในขณะนั้น ซึ่งอาจจะถูกปรับแต่งละเอียดโดยวิศวกรที่หน้างานไว้แล้ว (ในงานควบคุมอุตสาหกรรมจริง การปรับพารามิเตอร์ตัวควบคุมจากระยะไกลเป็นวิธีที่ควรหลีกเลี่ยงเพราะอาจเกิดอันตราย นอกจากมีความจำเป็นหรือในสถานการณ์ฉุกเฉินเท่านั้น)
วิธีนี้ไม่สามารถแก้ปัญหาหากมีการเปลี่ยนแปลงผ่านพอร์ตอนุกรมหลังจากนั้นอีก
ดังนั้นทางแก้ที่ดีกว่าคือให้ตัวควบคุมอัพเดต freeboard widgets
การอัพเดทโดย publish ค่าอย่างต่อเนื่อง
เราจะเริ่มจากวิธีที่ง่ายที่สุดคือการ publish ค่าของสถานะและพารามิเตอร์ในฟังก์ชัน loop() เช่นเดียวกับการส่งค่าให้กับ gauges และ feed แต่จะตั้งชื่อ topics ให้ต่างกัน จากตัวอย่างเดิมได้ตั้งชื่อ topic สำหรับค่า r, y, u ที่แสดงบน gauge widgets ไว้คือ
#define RYUDATATOPIC "/ryu/" ALIAS // topic to publish; in this case, /ryu/{ALIAS}
เราจะเพิ่ม topic ใหม่โดยใช้ชื่อตัวย่อ CSP (Controller Status and Parameters)
#define CSPDATATOPIC "/csp/" ALIAS // Controller Status and Parameters /csp/{ALIAS}
ซึ่งตัว sliders และ toggle widgets จะ subscribe topic นี้เพื่อรับข้อมูลอัพเดท
ในขณะนี้เรามี widget สำหรับพารามิเตอร์และสถานะตัวควบคุมทั้งหมด 8 ตัว ประกอบด้วย sliders 6 ตัว (Kp, Ki, Kd, Kt, Wp, Wd) และ toggle 2 ตัว (Controller Select และ MA Filter) ในที่นี้จะเรียงลำดับตัวแปรที่เกี่ยวข้องดังนี้
controltype, adma, kp, ki, kd, kt, wp, wd
โดยส่งไปทั้งสตริงและให้ widget แต่ละตัวไปแยกข้อมูลเอาเอง ใช้วิธีเช่นเดียวกับการ publish ค่าของ r, y, u คือเพิ่มคำสั่งใน loop() เพื่อสร้างสตริงและส่งให้ microgear.publish()
String cspstring =(String)controltype+","+(String)adma+","+(String)kp+","
+(String)ki+","+(String)kd+","+(String)kt+","+(String)wp+","+(String)wd;
microgear.publish(CSPDATATOPIC, cspstring);
โดยตั้งค่าคาบเวลาในการ publish ให้เหมาะสม ในช่วงเริ่มต้นอาจจะให้พิมพ์ใน serial monitor ดูว่าค่าถูกต้องหรือไม่
Serial.print("Publishing /csp/ --> ");
Serial.println(cspstring);
ตัวอย่างโปรแกรมคือ
esp32_publishparms.ino (รวมอยู่ใน zip file ด้านล่าง) คอมไพล์และอัพโหลดลงบนบอร์ด เปิด serial monitor ดูจะเห็นสตริงที่ถูก publish ตามคาบเวลาที่ตั้งไว้ ดังในรูปที่ 4
รูปที่ 4 สตริง /csp/ ที่ส่งให้กับ microgear.publish()
งานที่เหลือก็คือในส่วนของ Freeboard widgets ซึ่งจะต้องไปตั้งค่าในฟิลด์ AUTOUPDATED VALUE ของแต่ละตัวเพื่อดึงค่าจากสตริงที่ถูก publish จะขอกล่าวถึง slider widget ก่อนโดยยกตัวอย่างตัว Kp คลิกรูปประแจเพื่อตั้งค่า และพิมพ์คำสั่งดังนี้ลงในช่อง AUTOUPDATED VALUE
datasources["myIoFCboard2"]["/myIoFC/csp/myIoFCdevice"].split(",")[2]
ดังแสดงในรูปที่ 5 (สำหรับส่วนต้นๆ ของคำสั่งจะมีตัวเลือกขึ้นมาให้เมื่อคลิกที่ +DATASOURCE แต่ในส่วนท้ายคือ .split(“,”)[2] ต้องพิมพ์เอง
รูปที่ 5 การตั้งค่าในฟิลด์ AUTO UPDATED VALUE ของ Kp slider
อธิบายคำสั่งนี้ได้คือ ในส่วนต้นจะเป็นการเลือก datasource และ topic ที่จะ subscribe ส่วนท้ายคือการแยกข้อมูลออกจากสตริงโดยตัวคั่นคือ "," และค่าของ kp อยู่อันดับที่ 3 ในสตริง (ตัวชี้ของคำสั่ง split จะเริ่มจาก 0 ดังนั้นค่าที่ 3 ในสตริงจะมีตัวชี้เท่ากับ 2)
สำหรับ sliders ตัวอื่นๆ ที่เหลือก็ตั้งค่าโดยใช้คำสั่งเดียวกันนี้ เพียงแต่เปลี่ยนตัวชี้ใน [ ] ท้ายคำสั่งให้ตรงกับตำแหน่งของข้อมูลที่ต้องการเท่านั้น ตัวอย่างเช่น slider สำหรับ Kt จะใส่ตัวชี้เป็น [5] เป็นต้น
ต่อมาสำหรับ toggle switches 2 ตัว จะต้องตั้งค่าใน AUTO UPDATED VALUE เช่นเดียวกันโดยคำสั่งที่คล้ายกัน แต่จะเพิ่มตรงส่วนท้ายอีกเล็กน้อย ตัวอย่างเช่นการตั้งค่าสำหรับ Controller Select จะใช้คำสั่งดังนี้
datasources["myIoFCboard2"]["/myIoFC/csp/myIoFCdevice"].split(",")[0]==1
ดังแสดงในรูปที่ 6 อธิบายคำสั่งคือ ตำแหน่งข้อมูลของชนิดตัวควบคุมจะอยู่อันดับแรกในสตริง (ตัวชี้เท่ากับศูนย์) แต่หลังจากดึงข้อมูลแล้วจะต้องเขียนตรรกะเพื่อบอกว่าให้ toggle เปลี่ยนสถานะเป็น ON เมื่อข้อมูลมีค่าเท่ากับ 1 และจะกลับเป็น OFF เมื่อข้อมูลมีค่า 0 ซึ่งสำหรับ Controller Select toggle นี้จะตั้งไว้ว่า ON คือการเลือกตัวควบคุมที่ออกแบบเฉพาะ (Custom) และ OFF คือเลือกตัวควบคุม PID
รูปที่ 6 การตั้งค่า AUTO UPDATED VALUE ของ Controller Select Toggle
หมายเหตุ: ในการทดลองครั้งแรกผู้เขียนไม่ได้ใส่ == 1 ท้ายคำสั่ง ผลคือ toggle เปลี่ยนค่าเป็น ON (Custom) เพียงครั้งแรกและไม่สามารถเปลี่ยนกลับเป็น OFF หลังจากนั้น ไม่ว่าจะคลิกด้วยเม้าส์หรือเปลี่ยนค่าใน serial monitor ก็ตาม
อย่าลืมตั้งค่าใน toggle อีกตัวหนึ่งคือ MA Filter โดยใช้คำสั่งเดียวกันเพียงเปลี่ยนแค่ตัวชี้เป็น [1] เท่านั้น
เมื่อแก้ไข widgets ครบทั้งหมดแล้ว ท่านจะเห็นว่าค่าพารามิเตอร์และสถานะของตัวควบคุมใน Freeboard จะถูกปรับให้ตรงกับค่าจริง ดังในรูปที่ 7 ทดลองเปลี่ยนค่าใน serial monitor จะเห็นว่า Freeboard widget ถูกอัพเดต โดยอัตราการอัพเดตจะสัมพันธ์กับคาบเวลาที่เรา publish ในโปรแกรม
รูปที่ 7 ค่าของสถานะและพารามิเตอร์ควบคุมที่ถูกอัพเดตให้ตรงกับค่าจริง
การควบคุมโดย Freeboard จะเป็นไปตามปกติ คือเมื่อคลิกเลื่อนตัว sliders ค่าพารามิเตอร์ในตัวควบคุมจะถูกเปลี่ยน ทดลองคลิกที่ toggle switches ถ้าสถานะไม่เปลี่ยน ตรวจสอบคำสั่งใน AUTO UPDATED VALUE ว่าลืมใส่ ==1 ต่อท้ายหรือไม่
การ publish เฉพาะเมื่อสถานะหรือพารามิเตอร์ถูกเปลี่ยน
วิธีการ publish ค่าอย่างต่อเนื่องแบบที่กล่าวมามีข้อเสียที่ชัดเจนคือ โดยปกติหลังจากได้ค่าที่เหมาะสมแล้วผู้ใช้งานจะไม่ได้ปรับค่าสถานะและพารามิเตอร์ตัวควบคุมบ่อยครั้ง หรืออาจจะไม่ได้เปลี่ยนอีกเลยก็ได้ ดังนั้นการ publish ค่าอย่างต่อเนื่องเป็นการเปลืองแบนด์วิดธ์โดยเปล่าประโยชน์ หรือถ้าหาก publish นานๆ ครั้งก็จะมีปัญหาต้องรอนานกว่าค่าจะเปลี่ยน ดังนั้นวิธีที่ดีกว่าคือ publish เฉพาะเมื่อมีการเปลี่ยนแปลงสถานะหรือพารามิเตอร์ตัวใดตัวหนึ่งเท่านั้น ถ้าไม่มีการเปลี่ยนแปลงก็ไม่ต้องส่งข้อมูลใด
การเขียนโค้ดสำหรับวิธีนี้จะสะดวกกว่าหากรวมไว้เป็นฟังก์ชัน ที่สามารถเรียกใช้ในส่วนอื่นของโปรแกรม ตัวอย่างเช่น
// publish all parameters to update freeboard widgets
// whenever a parameter is changed
void update_freeboard(void)
{
// format is controller, adma, kp , ki, kd, kt, wp, wd
String cspstring = (String)controltype+","+(String)adma+","
+(String)kp+","+(String)ki+","+(String)kd+","+(String)kt
+","+(String)wp+","+(String)wd;
Serial.print("Publishing /csp/ --> ");
Serial.println(cspstring);
microgear.publish(CSPDATATOPIC, cspstring);
}
จากนั้นก็พิจารณาส่วนของคำสั่งหรือฟังก์ชันตรงจุดที่มีการเปลี่ยนค่าพารามิเตอร์ สำหรับตัวควบคุม IoFC การเปลี่ยนค่าอัตราขยาย PID แต่ละตัวจะเริ่มที่ฟังก์ชันแปลคำสั่ง CmdInt() หลังจากนั้นจะต้องเรียกพังก์ชัน PID_update() เพื่อคำนวณสัมประสิทธิ์ตัวควบคุมใหม่เสมอ ดังนั้นจุดที่เหมาะสมที่สุดที่จะเรียกฟังก์ชัน update_freeboard() คือในฟังก์ชัน PID_update() นั่นเอง
ส่วนสำหรับการเลือกตัวควบคุม และการเลือกใช้ MA Filter จะอยู่ใน CmdInt() ดังนั้นจึงใส่ update_freeboard() ไว้หลังจากที่เปลี่ยนค่าตัวแปรแล้ว
ตัวอย่างโปรแกรมคือ
ESP32_publishparmsfn.ino ทดลองรันโปรแกรมนี้เพื่อตรวจสอบการอัพเดทค่าในตัวควบคุมกับบน Freeboard เมื่อเปิด serial monitor มาจะไม่เห็นการ publish ใดๆ เพราะยังไม่มีการเปลี่ยนค่า
ทดลองพิมพ์คำสั่งเปลี่ยนค่าพารามิเตอร์และสถานะตัวควบคุมดังในรูปที่ 8 จะเห็นว่าสตริงจะถูก publish ทันทีหลังจากที่แต่ละค่าถูกเปลี่ยน
รูปที่ 8 พิมพ์คำสั่งเปลี่ยนค่าสถานะและพารามิเตอร์ใน serial monitor
และเมื่อตรวจสอบค่าบน Freeboard widgets ในรูปที่ 9 จะเห็นค่าถูกเปลี่ยนไปเป็นค่าใหม่โดยทันที เวลาในการตอบสนองต่อการเปลี่ยนแปลงจะดีกว่าการส่งค่าแบบเป็นคาบเวลา และไม่เปลืองแบนด์วิดธ์ด้วย
รูปที่ 9 การอัพเดทค่าของ sliders และ toggle switches เฉพาะเมื่อมีคำสั่งเปลี่ยนค่า
ไฟล์ตัวอย่างในบทความนี้รวมอยู่ใน
ESP32_csp.zip
อ่านบทความนี้แล้วยังไม่หนำใจ มาร่วม ฝึกอบรมกับเราใน
Workshop ตัวควบคุมป้อนกลับบนอินเทอร์เน็ต ครั้งที่ 1 โดยจะแจก printout หนังสือ “ตัวควบคุมป้อนกลับบนอินเทอร์เน็ตโดย ESP8266” ที่เพิ่มเติมเนื้อหาที่เพิ่งเขียนใหม่อย่างเช่นในบทความนี้ หรือการพัฒนาบน ESP32 เบื้องต้น สำหรับผู้เข้าร่วมอบรมเท่านั้นครับ พร้อมของแถมอื่นๆ อีก
ลิงก์อ้างอิง
https://netpie.io
No comments:
Post a Comment