เวลาทำกับข้าวเนี่ย ทุกคนคงเคยเจอสถานการณ์ที่ตั้งหม้อทิ้งไว้ แล้วน้ำหรือนมเดือดจนล้นออกจากหม้อใช่ไหมล่ะ?
วิธีป้องกันก็ง่ายๆ หรอก แค่ลดไฟลง แต่แบบนั้นมันไม่มันส์! วันนี้พี่จะพาน้องไปรู้จักกับวิธีแบบ Overengineered กัน:
- เอา Arduino board กับ accelerometer มาสักชุด
- ใช้ Embedded AI ตรวจจับตอนที่น้ำเดือดผ่านการสั่นสะเทือน
- สั่งให้พัดลมเป่าไปที่หม้อเพื่อป้องกันไม่ให้น้ำล้น
ง่ายมั้ยล่ะ :)

ภาพรวมโปรเจค
"Boil-Guard" เนี่ยคือการนำ Thermal-Anomaly Forensics และ Asynchronous Edge-AI Vibration Orchestration มาลงมือทำจริงจังเลย โดยใช้พลังการประมวลผลของ Arduino Uno R4 WiFi ในการจำแนกสภาพของไหลแบบเรียลไทม์ ผ่านการเฝ้าสังเกตการสั่นสะเทือนระดับไมโครที่เกิดจากฟองน้ำเดือด โปรเจคนี้จะพาไปเจาะลึกการใช้งาน Pre-Trained N-Class Classifier ที่สร้างจาก NanoEdge AI Studio เพื่อระบุฮาร์มอนิกความถี่เฉพาะของน้ำเดือด โดยไม่ต้องสัมผัสความร้อนโดยตรง สิ่งที่เน้นในงานสร้างนี้คือการตรวจจับด้วย accelerometer ความเร็วสูง, การวินิจฉัยการทำงานของ actuator ที่ขับด้วย TIP120, และการประยุกต์ใช้หลักการความปลอดภัยในครัวระดับอุตสาหกรรม
ขั้นตอนที่ 1: เตรียมการตั้งค่า




สิ่งที่ต้องเตรียม: หม้อ, พัดลม และเตาไฟฟ้าหรือเตาอินดักชัน
ต่อมา เราต้องเชื่อมต่อ accelerometer เข้ากับบอร์ด Arduino ใช้สายจัมเปอร์ต่อดังนี้:
- VIN (จาก accelerometer) ไปที่ 3.3V (บนบอร์ด)
- GND ไปที่ขา GND ข้างใดข้างหนึ่งบนบอร์ด
- SDA ไปที่ SDA
- SCL ไปที่ SCL
จากนั้นก็ทำวงจรตามตัวอย่างนี้ (ลิงก์ไปยังบทความสอน) จุดประสงค์ของทรานซิสเตอร์ TIP120 คือให้ทำงานเป็นสวิตช์ที่ควบคุมได้ ขา Arduino ที่ส่งสัญญาณเป็น Logical 1 ควรจะเปิดพัดลม และ Logical 0 ควรจะปิดพัดลม ในที่นี้เราใช้ขา A0 ร่วมกับตัวต้านทาน (ดูสายสีส้มในรูป)
เสร็จแล้วก็ติดตั้งชุดอุปกรณ์ทั้งหมดบนหม้อด้วยกาวร้อน และหาวิธีติดพัดลมให้อยู่กับที่ พี่ใช้ที่หนีบพลาสติก (serflex) เอง
ใน Arduino IDE: ตรวจสอบให้แน่ใจว่าเลือกพอร์ต COM ถูกต้อง: Tools > Port แล้วเลือกพอร์ตที่ถูกต้อง เลือกบอร์ดให้ถูกต้อง:
- Tools > Boards > Arduino Renesas UNO R4 boards > Arduino UNO R4 WIFI
- ถ้าไม่เจอ ให้คลิก Tools > Boards > Boards Manager..., ค้นหา UNO R4 แล้วติดตั้งแพ็คเกจ
ลงลึกกันแบบช่างๆ
- การแยกประเภทการสั่นสะเทือน & การวิเคราะห์เชิงนิติวิทยาศาสตร์ (Forensics):
- The LIS3DH Acquisition-Hub: ทำงานที่อัตราการสุ่มตัวอย่าง $1.6\text{kHz}$ เพื่อจับฮาร์มอนิกความถี่สูงจากการแตกตัวของแรงตึงผิว การวิเคราะห์จะเกี่ยวข้องกับการวัด "ความหนาแน่นของกำลังในสเปกตรัม (Spectral-Power Density)" โดยประมวลผลข้อมูล 512 ตัวอย่างต่อแกนเพื่อสร้างลายเซ็นการสั่นสะเทือนที่มีความเที่ยงตรงสูง การวินิจฉัยจะเน้นที่ "การแยกสัญญาณจากสัญญาณรบกวน (Signal-Noise Separation)" เพื่อให้แน่ใจว่าเอไอจะไม่สนใจการสั่นสะเทือนจากคอมเพรสเซอร์โดยรอบและการวินิจฉัยกิจกรรมอื่นๆ ในครัว
- NanoEdge AI Inference Engine: ระบบใช้ไลบรารีภาษาซีที่คอมไพล์และปรับแต่งให้เหมาะกับคอร์ Renesas RA4M1 การวิเคราะห์รวมถึงการคำนวณที่แน่นอนของ "บัฟเฟอร์ความน่าจะเป็นในการจำแนกประเภท (Classification-Probability Buffers)" เพื่อประเมินว่าสถานะปัจจุบันตรงกับเมทริกซ์ความรู้ของสถานะ "น้ำเดือด" หรือ "ปกติ" หรือไม่ การวินิจฉัยนี้ทำให้แน่ใจว่าการอนุมานจะเกิดขึ้นภายในเวลาน้อยกว่า 10ms เพื่อป้องกันไม่ให้เกิดฮาร์มอนิกจากความร้อนล้นเกิน
- การจัดการบรรเทา & การวินิจฉัยเมทริกซ์ HMI:
- The TIP120 Switch-Probe: ใช้คู่ดาร์ลิงตันเพื่อเชื่อมต่อเอาต์พุตลอจิก $(A0)$ เข้ากับโหลดพัดลมกระแสสูง การวิเคราะห์รวมถึงการวัด "ความหน่วงเวลาตอบสนองต่อความร้อน (Thermal-Response Latency)" เมื่อเอไอตรวจจับเหตุการณ์น้ำเดือด พัดลมจะเริ่มทำงานแบบบังคับพาความร้อนเพื่อป้องกันไม่ให้เกิดเหตุการณ์น้ำล้น
- LED-Matrix Feedback Harmonics: ใช้เมทริกซ์ 12x8 ของ Uno R4 เพื่อให้ข้อมูลเทเลเมทรีภาพแบบเรียลไทม์ของสถานะเอไอ $(เช่น แสดงข้อความเลื่อน "Boiling")$
ขั้นตอนที่ 2: เก็บข้อมูลจาก Accelerometer
จะให้เอไอตรวจจับว่าน้ำเดือดได้ยังไงถ้ายังไม่เคยเห็นข้อมูลน้ำเดือดเลยเนอะ? งั้นขั้นแรกเราต้องเก็บข้อมูลของทั้งสองสถานะก่อน: สถานะน้ำเดือด กับ สถานะปกติ เราจะเขียนโค้ดเก็บข้อมูลจากตัววัดความเร่งเองก็ได้ แต่ NanoEdge เขามีเครื่องมือสร้างโค้ดให้อัตโนมัติอยู่แล้ว ใช้ของเขาดีกว่า ประหยัดเวลาไปเป็นชั่วโมง!
- เปิดโปรแกรม NanoEdge AI Studio
- เข้าไปที่แท็บ Data Logger
- เลือกบอร์ด Arduino
- เลือกเซ็นเซอร์ LIS3DH

เพราะการสั่นสะเทือนจากน้ำเดือดมันค่อนข้างเบา และเราไม่ต้องการข้อมูลมหาศาลเกินไป ให้ตั้งค่าตามนี้เลย:
- Data rate (Hz): 1600Hz
- Range: 2g
- Sample per axis: 512
(จะลองตั้งค่าอื่นดูก็ได้นะ แต่ระวังเรื่อง Sample per axis ให้ดี เพราะมันจะกิน RAM ไปเก็บบัฟเฟอร์มากขึ้นเรื่อยๆ)
กด Generate Data Logger แล้วจะได้ไฟล์ .zip มา ซึ่งข้างในมีไฟล์ .ino พร้อมโค้ดที่พร้อมอัปโหลดลงบอร์ดแล้ว โค้ดนี้จะพิมพ์ข้อมูลบัฟเฟอร์ออกมาทาง Serial ในกรณีของเรา มันจะส่งบัฟเฟอร์ขนาด 3*512 ตัวอย่าง ด้วยความถี่ 1.6kHz ในขั้นตอนต่อไป เราจะอ่านบัฟเฟอร์ที่พิมพ์ออกมานี้และบันทึกเป็นชุดข้อมูลเพื่อเอาไปเทรนโมเดลเอไอ
คำเตือนเล็กน้อย: อาจต้องลงไลบรารีสำหรับตัววัดความเร่งถ้ายังไม่เคยใช้มาก่อน:
- ใน Arduino IDE ไปที่ Sketch > Include Library > Manage libraries... > แล้วค้นหา "Adafruit LIS3DH"
ในโค้ดบันทึกข้อมูลจาก NanoEdge จะมีบางส่วนที่เกี่ยวข้องกับ NanoEdge ถูกคอมเมนต์ไว้ เราจะมาใช้ส่วนนั้นทีหลัง หลังจากที่เราได้ไลบรารีเอไอจาก NanoEdge AI Studio แล้ว
โค้ดบันทึกข้อมูลจาก NanoEdge ถูกแนบไว้ท้ายบทความแล้ว
วิศวกรรมและการลงมือทำ
- การจับคู่การสั่นสะเทือนและนิติเวชโครงสร้าง:
- การวิเคราะห์การยึดติดด้วยกาว: ติดตั้ง LIS3DH ด้วยอินเทอร์เฟซที่ทนความร้อนสูง นิติเวชนี้ทำให้มั่นใจว่า "ฟังก์ชันถ่ายโอนเชิงกล" ระหว่างภาชนะและเซ็นเซอร์ยังคงเป็นเชิงเส้นตลอดช่วงอุณหภูมิ $25^\circ\text{C}$ ถึง $100^\circ\text{C}$
- การวินิจฉัยความสมบูรณ์ของบัสบน PCB: ใช้สุนทรียภาพการเดินสายระดับการบินเพื่อเชื่อมต่อ IMU เข้ากับบัส I2C นิติเวชเน้นที่ "การวิเคราะห์การกดทับสัญญาณรบกวนแม่เหล็กไฟฟ้า" เพื่อป้องกันไม่ให้ฮาร์มอนิกจากเตาเหนี่ยวนำทำให้เกิดการวินิจฉัยการกะพริบของลอจิกบนสาย SDA/SCL
- การรวบรวมชุดข้อมูลและฮิวริสติกมาตรฐาน:
- การนำไปใช้เกี่ยวข้องกับการบันทึกสัญญาณมากกว่า 200 สัญญาณที่มีความเข้มข้นของการเดือดที่แตกต่างกัน นิติเวชรวมถึง "การวิเคราะห์เอนโทรปีข้ามของชุดตรวจสอบความถูกต้อง" เพื่อยืนยันว่าโมเดลยังคงมีความแม่นยำ 90% ในปริมาณน้ำและรูปทรงภาชนะที่ต่างกัน
ขั้นตอนที่ 3: NanoEdge AI Studio
ตอนนี้เราสามารถเก็บข้อมูลโดยใช้ตัววัดความเร่งได้แล้ว ขั้นตอนต่อไปคือการใช้ NanoEdge AI Studio เพื่อบันทึกสัญญาณและใช้สัญญาณเหล่านี้สร้าง AI ที่สามารถแยกแยะสัญญาณน้ำเดือดออกจากสัญญาณอื่นๆ ได้
- เปิด NanoEdge AI Studio
- สร้างโปรเจกต์ Classification แบบ N class
ในการตั้งค่าโปรเจกต์:
- เลือก Arduino R4 WiFi เป็นเป้าหมาย
- เลือก Accelerometer 3 แกนเป็นเซ็นเซอร์
- ส่วนอื่นๆ เป็นตัวเลือกเพิ่มเติม
- คลิก Next
ในส่วน Signals: ที่นี่เราจะเพิ่มข้อมูลทั้งน้ำไม่เดือดและน้ำเดือด และทำซ้ำหลายครั้งด้วยระดับน้ำที่ต่างกัน เราเริ่มจากแบบง่ายๆ ก่อน พี่เลือกที่จะใช้หม้อที่เติมน้ำครึ่งหนึ่งและทำดังนี้:
- วางหม้อบนเตาไฟฟ้าหรือเตาเหนี่ยวนำ (ที่กำลังสูงสุด)
- บันทึกข้อมูลน้ำไม่เดือดขณะที่น้ำกำลังร้อนขึ้น
- หยุดบันทึกข้อมูลน้ำไม่เดือดเมื่อคิดว่ามันใกล้จะหรือเริ่มเดือดแล้ว
- รอสักหน่อยเพื่อให้แน่ใจว่าน้ำเดือดจริงๆ
- เริ่มบันทึกข้อมูลน้ำเดือด
ทุกๆ 10 สัญญาณที่บันทึก พี่จะหยุดบันทึกชั่วคราวและขยับหม้อบนเตาไฟนิดหน่อยเพื่อเพิ่มความหลากหลายให้ข้อมูล พี่บันทึกสัญญาณน้ำไม่เดือดประมาณ 150 สัญญาณ (เป็นเวลาที่ใช้ในการเริ่มเดือด) และสัญญาณน้ำเดือดประมาณ 50 ถึง 100 สัญญาณ
หลังจากนั้นพี่ก็เปลี่ยนระดับน้ำและทำขั้นตอนเดิมซ้ำหลายรอบ
สำหรับการบันทึกข้อมูลใน NanoEdge ให้ทำดังนี้:
- คลิกที่ Add Signal
- เลือก From Serial (USB)
- เลือกพอร์ต COM ที่ถูกต้อง
- คลิก Start/Stop ใน NanoEdge เพื่อเก็บสัญญาณ
- หยุดเมื่อพอใจ
พี่เก็บข้อมูลหลายคลาสของน้ำเดือดและหลายคลาสของน้ำไม่เดือด แต่เพื่อจะรันเบนช์มาร์ก คุณต้องรวมไฟล์ทั้งหมดให้เหลือแค่ 2 ไฟล์: เดือด กับ ไม่เดือด
วิธีทำคือ:
- ดาวน์โหลดไฟล์ทั้งหมดที่บันทึกไว้
- กลับไปที่หน้าแรกของ NanoEdge AI Studio
- ไปที่ Data Manipulation
- นำเข้าไฟล์น้ำไม่เดือดทั้งหมด
- คลิก concatenate ด้านบน
- คลิก extract line แล้วคลิก run
- จากนั้นบันทึกไฟล์ที่รวมสัญญาณทั้งหมดไว้
- ทำแบบเดียวกันสำหรับข้อมูลน้ำเดือด
- กลับไปที่โปรเจกต์และนำเข้า 2 ชุดข้อมูลของเราที่รวมทุกอย่างไว้

ในส่วน Benchmark: เบนช์มาร์กคือหัวใจของ NanoEdge AI Studio ตรงนี้เราจะใช้สัญญาณทั้งสองประเภทเพื่อพยายามหาคอมบิเนชันที่ดีที่สุดของการประมวลผลข้อมูลล่วงหน้าและโมเดลที่ดีที่สุดที่สามารถแยกแยะข้อมูลได้
- คลิกที่ New Benchmark
- เลือกชุดข้อมูลทั้งหมด
- คลิก start
เบนช์มาร์กจะลองคอมบิเนชันของการประมวลผลล่วงหน้าและโมเดลบนข้อมูลซ้ำๆ และประเมินประสิทธิภาพ มันจะแบ่งข้อมูลออกเป็นชุดฝึกและชุดทดสอบหลายครั้งเพื่อให้ได้ผลลัพธ์ที่แข็งแกร่ง เบนช์มาร์กอาจใช้เวลาหลายชั่วโมงกว่าจะเสร็จสิ้น ขึ้นอยู่กับปริมาณข้อมูลที่ใช้ ถ้าคะแนนถึง 90% ขึ้นไป คุณสามารถหยุดชั่วคราว/หยุดและดำเนินการต่อได้ เบนช์มาร์กจะพยายามปรับให้โมเดลดีที่สุดเท่าที่จะเป็นไปได้ แต่คุณหยุดมันได้เมื่อพอใจแล้ว

ในขั้นตอนการตรวจสอบ (Validation): ขั้นตอนนี้เอาไว้ทดสอบโมเดลกับข้อมูลใหม่ๆ ไงน้อง การเทรนโมเดลแมชชีนเลิร์นนิงหรือ AI นี่มันมีเรื่องให้ปวดหัวอยู่นะ อย่างนึงคือโมเดลมันอาจจะ "overfit" ได้! มันคืออะไรเหรอ? ก็คือโมเดลมันทำคะแนนดีเลิศตอนเทรนนิง แต่พอเจอข้อมูลใหม่ที่มันไม่เคยเห็นมาก่อนเนี่ย ทำงานได้ห่วยแตกเลย เพราะมันท่องจำข้อมูลฝึกไปหมดเลย ไม่ได้เรียนรู้หลักการ classify จริงๆ จังๆ... ถ้าอยากใช้ validation ละก็ ต้องมีชุดข้อมูลใหม่ๆ ทั้งเสียงน้ำเดือดและไม่เดือด กลับไปขั้นตอนก่อนหน้าเพื่อเก็บข้อมูลเพิ่ม แล้วดาวน์โหลดไฟล์ csv มาใช้ในขั้นตอนนี้ได้เลย
วิธีใช้ Validation:
- เลือกโมเดลที่อยากทดสอบได้สูงสุด 10 ตัว (ตัวแรกๆ ที่คะแนนดีสุดแนะนำเลย)
- กดปุ่ม "New Experiment"
- เลือกชุดข้อมูลใหม่ของน้ำไม่เดือดและน้ำเดือด
- กด Start ได้เลย
เสร็จแล้วก็จะได้ผล performance ของโมเดลทั้งหมดบนข้อมูลใหม่มาดูกัน
พี่ใช้เวลาในส่วนนี้พอสมควรเลยนะ เพื่อหาโมเดลที่ทำงานได้ดีจริงๆ นั่นหมายความว่าพี่ลบข้อมูลบางส่วนออก บันทึกข้อมูลใหม่ ทำ benchmark และ validation ซ้ำๆ จนเจอโมเดลที่ดูเหมือนจะทำงานได้ตามที่คาดหวัง เริ่มจากแบบง่ายๆ ก่อนนะน้อง ค่อยๆ เพิ่มความหลากหลายของข้อมูลไปเรื่อยๆ พร้อมกับตรวจสอบไปด้วยว่าโมเดลยังทำงานได้ดีอยู่
ในขั้นตอนการคอมไพล์ (Compilation): ง่ายมาก แค่กด compile ก็จะได้โมเดลที่เทรนเสร็จแล้วมาใช้ต่อ
ขั้นตอนที่ 4: เพิ่ม NanoEdge AI Library เข้าไปในโค้ด Arduino
การนำ AI ที่เราสร้างมาใส่ในโค้ด Arduino นี่ง่ายมากๆ ตามนี้เลย:
- Include โมเดลและ knowledge
- เริ่มต้นการทำงานของโมเดล (initialize)
- ทำการตรวจจับ (detections)
แค่นั้นแหละ! และทุกอย่างทำผ่านฟังก์ชันหมดเลย นอกจากนี้พี่ยังเพิ่มการแสดงผลบน LED Matrix และสั่งให้พัดลมทำงานเมื่อตรวจจับคลาส "น้ำเดือด" ได้ เพื่อป้องกันน้ำเดือดล้นออกจากหม้ออีกด้วย
ทีนี้เรามีไลบรารี anomaly detection แล้ว ต่อไปก็ต้องเอามาใส่ในโค้ด Arduino ของเรา:
- เปิดไฟล์ .zip ที่ได้มา จะมีโฟลเดอร์ Arduino อยู่ข้างใน ซึ่งมี zip อีกอันนึง
- นำเข้าไลบรารีใน Arduino IDE: Sketch > Include library > Add .ZIP library... แล้วเลือกไฟล์ .zip ที่อยู่ในโฟลเดอร์ Arduino
ถ้าน้องใช้ NanoEdge AI Library อยู่ใน Arduino IDE อยู่แล้ว: ให้เข้าไปที่ document/arduino/library แล้วลบโฟลเดอร์ของ nanoedge เก่าออกไปซะ หลังจากนั้นค่อยทำตามขั้นตอนด้านบนเพื่อนำเข้าไลบรารีใหม่
สำคัญมาก: ถ้าเจอ error เกี่ยวกับ RAM นี่อาจเป็นเพราะไลบรารีจาก NanoEdge ใหญ่เกินไป ให้กลับไปที่ขั้นตอน VALIDATION STEP ใน NanoEdge แล้วเลือกไลบรารีที่ขนาดเล็กกว่า (กดที่มงกุฎด้านขวา) จากนั้น compile ใหม่แล้วเอามาแทนที่ใน Arduino IDE อีกครั้ง
โค้ดหลักแนบไว้ท้ายบทความแล้ว ด้านล่างนี้คือคำอธิบายแต่ละส่วนที่ import เข้ามา:
NanoEdge:
#include <NanoEdgeAI.h>
#include "knowledge.h"
//DON T FORGET TO CHANGE NEAI_MODE TO 1 to do detections
#define NEAI_MODE 1
/* Global variables definitions */
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
uint8_t neai_code = 0; //initialization code
uint16_t id_class = 0; // Point to id class (see argument of neai_classification fct)
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
"unknown",
"boiling_test3",
"not_boiling_test3",
};
void setup(){
//some code
/* Initialize NanoEdgeAI AI */
neai_code = neai_classification_init(knowledge);
if (neai_code != NEAI_OK) {
Serial.print("Not supported board.\n");
}
}
void loop(){
//some code
if (NEAI_MODE) {
neai_classification(neai_buffer, output_class_buffer, &id_class);
switch (id_class) {
case 1:
Serial.println("!!! Boiling !!!");
break;
case 2:
Serial.println(" Not Boiling ");
default:
Serial.println(" Error ");
break;
}
}
ตัวแปร id2class นี่ขึ้นอยู่กับชื่อคลาสที่เราใช้ใน NanoEdge นะน้อง ลำดับของคลาสน้ำเดือดหรือไม่เดือดอาจสลับกันได้ ต้องคัดลอกมาจากไฟล์ NanoEdgeAI.h ที่อยู่ในไฟล์ .zip ที่คอมไพล์แล้ว:
- YOUR_LIBRARY.zip\arduino\nanoedgeai_for_arduino.zip\nanoedgeai\src\NanoEdgeIA.h
ใช้เมทริกซ์แสดงข้อความ:
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
/* Declare matrix to display */
byte frame[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
//text to display
char text[30];
ArduinoLEDMatrix matrix;
void setup(){
//some code
matrix.begin();
}
void loop(){
//some code
// if we want to write something we set our text