AI Node (Edge AI Nodes)¶
ใช้ได้เฉพาะ EPG-002S, EPG-004S และ EPG-AI เท่านั้น
หน้านี้ใช้ได้เฉพาะเกตเวย์รุ่นที่มี NPU ในตัว (Rockchip RK3566/RK3588):
EPG-002S, EPG-004S และ EPG-AI เท่านั้น เกตเวย์รุ่นอื่นไม่มี
ฮาร์ดแวร์รองรับสิ่งนี้เลย — โหนด npu-* จะยังปรากฏใน palette แต่ทุก
คำสั่งที่เรียกไปยัง engine จะล้มเหลวทันที เพราะไม่มี daemon
npu-engined และไม่มี NPU ให้ประมวลผล
Edge AI Nodes นำการประมวลผลคอมพิวเตอร์วิทัศน์ (computer vision) แบบ เร่งความเร็วด้วย NPU (ตรวจจับวัตถุ) เข้ามาอยู่ในโฟลว์ Node-RED — "มีคนอยู่ ในเฟรมนี้ไหม" "หมวกนิรภัยหายไปกี่ใบ" "นับจำนวนรถบรรทุก" — โดยที่ Node-RED ไม่ต้องแตะพิกเซลหรือ NPU โดยตรงเลย ระบบนี้ประกอบด้วย 3 ส่วนที่ทำงานร่วมกัน:
| ส่วนประกอบ | หน้าที่ |
|---|---|
npu-engined |
daemon เบื้องหลัง (ทำงานอยู่แล้วบนเกตเวย์ที่รองรับ AI) ที่ดูแล NPU แหล่งภาพ/วิดีโอ และตัวเฟรมเองในหน่วยความจำที่ใช้ร่วมกัน |
@epithos/node-red-contrib-npu-ai |
แพ็กเกจโหนด Node-RED — โหนด npu-* ทั้ง 11 ตัว นี่คือส่วนที่คุณใช้สร้างโฟลว์จริง และเป็นเนื้อหาหลักของหน้านี้ |
Model Forge (npu-forge) |
เครื่องมือออฟไลน์บนเครื่อง x86+GPU ที่แปลงโมเดลที่เทรนแล้ว (ONNX) ให้เป็นบันเดิล .npumodel สำหรับฮาร์ดแวร์นี้ — ไม่ใช่สิ่งที่รันบนตัวเกตเวย์เอง |
ข้อความของ Node-RED ไม่เคยพกพิกเซลของภาพไปด้วยโดยตรง (ยกเว้น 2 กรณี เท่านั้น ดูหัวข้อ "การนำพิกเซลเข้า-ออก" ด้านล่าง) — แต่จะพก frame handle ชิ้นเล็ก ๆ ที่ชี้ไปยังพิกเซลที่อยู่ในหน่วยความจำร่วมของ engine แทน วิธีนี้ทำให้ภาพขนาดใหญ่ไม่ไปกองอยู่ใน event loop ของ Node.js และไม่ถูก เก็บไว้ในประวัติข้อความของโฟลว์
รายชื่อโหนด¶
กรอง palette ด้วยคำว่า "npu" จะเจอโหนดเหล่านี้ภายใต้หมวด NPU (บวกกับ
config node npu-engine ซึ่งอยู่ในหมวด config):

| โหนด | หน้าที่ |
|---|---|
npu-engine (config) |
การเชื่อมต่อไปยัง daemon npu-engined หนึ่งตัว โหนดอื่นทุกตัวด้านล่างอ้างอิงถึงตัวนี้ และยังเป็นที่ตั้งค่า Labels ที่ใช้ร่วมกันด้วย |
npu-model (config) |
ระบุว่าโหนด npu-detect ควรใช้บันเดิล .npumodel ตัวไหนที่ติดตั้งไว้ |
npu-camera |
เปิดแหล่งภาพ (โฟลเดอร์ภาพ, ไฟล์วิดีโอ หรือสตรีมที่ป้อนด้วย push) และส่ง frame handle ออกมาหนึ่งอันต่อเฟรมที่ได้รับ |
npu-buffer-to-frame |
ลงทะเบียน Buffer ของไบต์ภาพ JPEG/PNG/raw ให้เป็น frame handle — พิกเซลที่เข้าสู่ engine จาก Node-RED |
npu-detect |
รันการตรวจจับวัตถุบนเฟรมเทียบกับโมเดล → รายการผลตรวจจับ |
npu-watch |
อยู่ถัดจาก npu-detect — เฝ้าดู label เดียว รายงานว่ามี/นับจำนวน/สแนปช็อต ไม่ได้เรียกโมเดลเอง |
npu-draw |
วาดกรอบ/label ของผลตรวจจับลงบนเฟรม คืนค่าเป็น frame handle ใหม่ |
npu-roi |
ครอปพื้นที่สี่เหลี่ยมหนึ่งจุดขึ้นไปออกจากเฟรม เป็น frame handle ใหม่ |
npu-filter |
กรองรายการผลตรวจจับด้วย JS ล้วน ๆ ตาม label/score/ขนาด/อัตราส่วนภาพ — ไม่เรียก engine เลย ใช้งานได้แม้ engine จะออฟไลน์ |
npu-frame-to-jpeg |
แปลง frame handle ให้เป็นไบต์ JPEG/PNG ใน msg.payload — พิกเซลที่ออกจาก engine |
npu-engine-status |
ตรวจสอบสถานะ/ความสามารถของ engine แล้วส่งออกเป็น msg.payload สำหรับแดชบอร์ดหรือหัวข้อ MQTT health-check |
โหนดฟังก์ชันทุกตัวมี 2 เอาต์พุต — (1) ผลลัพธ์ (2) error — และแสดง สถานะการเชื่อมต่อ/สุขภาพ (fps, การดรอปเฟรม, offline/degraded) บนตัวโหนด เอง
การเชื่อมต่อกับ engine¶
ดับเบิลคลิกโหนด npu-* ตัวใดก็ได้ แล้วคลิกไอคอนดินสอข้าง Engine เพื่อ
เปิด config node npu-engine ที่ใช้ร่วมกัน:

| ฟิลด์ | หมายเหตุ |
|---|---|
| Runtime dir | ต้องตรงกับ runtime directory ของโปรเซส npu-engined ที่กำลังรันอยู่ — /run/npu-engine ตามการตั้งค่า systemd จริงที่แสดงด้านบน เว้น Control/Events socket ว่างไว้เพื่อใช้ผัง path เริ่มต้นของ engine เองใต้ไดเรกทอรีนั้น |
| Request timeout (ms) | ระยะเวลารอผลตอบกลับของคำสั่งหนึ่งครั้งก่อนถือว่าล้มเหลว |
| Health timeout (ms) | engine จะส่ง health ping มาทุกราว 5 วินาที หากไม่มีสัญญาณเข้ามานานเกินนี้ (ค่าเริ่มต้น 15 วินาที — พลาด 3 ครั้งติด) โหนดทุกตัวบนการเชื่อมต่อนี้จะขึ้นสถานะแดงเป็น offline แม้ socket จะยังดูเหมือนเชื่อมต่ออยู่ |
| Test connection | การตรวจสอบแบบอ่านอย่างเดียว — รายงาน backend, SoC, สุขภาพของระบบ และจำนวนโมเดลที่ลงทะเบียนอยู่ในขณะนี้ |
โหนดทุกตัวที่ใช้ config node npu-engine ตัวเดียวกันจะใช้คู่ socket
เดียวกันซ้ำ และเชื่อมต่อใหม่อัตโนมัติ (พร้อม backoff) หาก daemon
รีสตาร์ท
Labels¶
อยู่บน config node npu-engine เช่นกัน เนื่องจากในทางปฏิบัติมีเพียงโมเดล
เดียวที่รันอยู่ในแต่ละช่วงเวลาบนบอร์ดที่มี NPU core เดียว (RK3566 — ดู
หัวข้อ "มีโมเดลเดียวที่รันได้ในแต่ละช่วงเวลาบน RK3566" ด้านล่าง):
- Use the model's built-in labels.txt (ค่าเริ่มต้น) — ชื่อ class มา
จาก
labels.txtของบันเดิล.npumodelที่โหลดอยู่โดยตรง - Preset list — รายการสำเร็จรูป (ปัจจุบันมีแค่
coco80ลำดับ class มาตรฐาน 80 ชนิดของ COCO ที่ทั้งโมเดลเริ่มต้นและ YOLOv8/v11 ที่เทรนด้วย COCO ใช้ร่วมกัน) - Custom list — วางชื่อของคุณเอง หนึ่งชื่อต่อบรรทัดหรือคั่นด้วย
comma ตามลำดับ
classId
การตั้งค่านี้จะเปลี่ยน label ของทุกผลตรวจจับจากทุกโหนด npu-detect/
npu-watch บน engine นั้นตาม classId ที่เป็นตัวเลข — เป็นเพียงการ
override ชั้นการแสดงผลเท่านั้น ไม่ได้เปลี่ยนสิ่งที่โมเดลตรวจจับได้จริง
การเลือกโมเดล¶
npu-detect ต้องรู้ว่าจะรันโมเดลไหน คุณเลือกได้สองทาง: ชี้ไปที่ config
node Model (สร้างจาก config node npu-model — เลือกบันเดิลที่ติดตั้ง
ไว้แล้วจาก dropdown ซึ่งมีเครื่องหมาย [loaded] กำกับตัวที่โหลดอยู่ตอนนี้
พร้อมปุ่ม Load now สำหรับ warm up โมเดลล่วงหน้าแทนที่จะรอให้คำขอ
ตรวจจับครั้งแรกเป็นตัวโหลดเอง) หรือข้าม config node แล้วพิมพ์ชื่อ/เวอร์ชัน
โมเดลลงในฟิลด์ or model name ตรง ๆ — ซึ่งเป็นวิธีที่ตัวอย่างโฟลว์ทั้ง
สองของเกตเวย์ใช้จริง เช่น hardhat-detect หรือ yolox-s-coco
การติดตั้งบันเดิลโมเดลใหม่ก็ทำผ่านจุดเดียวกัน จากส่วน Upload new ของ
config node npu-model: เลือกไฟล์ zip บันเดิล .npumodel (ผลลัพธ์จาก
npu-forge convert ที่รันแยกต่างหากบนเครื่อง x86+GPU — ตัวเอดิเตอร์
ไม่ รับไฟล์ .onnx/.rknn ดิบ) แล้วคลิก Upload & install engine
จะตรวจสอบความถูกต้องของบันเดิล (schema ของ manifest, checksum ของแต่ละ
variant) ก่อนยอมรับ
มีโมเดลเดียวที่รันได้ในแต่ละช่วงเวลาบน RK3566¶
RK3566 (EPG-002S) มี NPU เพียงคอร์เดียว การโหลดโมเดลอื่นจึงจะดันโมเดลที่ โหลดอยู่ก่อนหน้าออกไปโดยอัตโนมัติเสมอ — ไม่มีทางเลี่ยงบนฮาร์ดแวร์นี้ ส่วน เกตเวย์ที่ใช้ RK3588 (EPG-004S/EPG-AI) มี NPU หลายคอร์ จึงเก็บโมเดลไว้ใน หน่วยความจำพร้อมกันได้มากกว่าหนึ่งตัว ควรวางแผนโฟลว์ให้สอดคล้องกับข้อ จำกัดนี้: หากมีโฟลว์สาธิตสองชุดบนเกตเวย์ RK3566 ตัวเดียวกัน แต่ละชุด ต้องการโมเดลคนละตัว โมเดลทั้งสองจะแย่งกันเป็นตัวที่โหลดอยู่จริง — ทุกครั้ง ที่เรียกตรวจจับจะดันโมเดลอีกตัวออกไปโดยปริยาย
npu-detect: การรันการตรวจจับ¶
ป้อน frame handle และ (ถ้าต้องการ) การอ้างอิงโมเดลเข้าไป:

| ฟิลด์ | หมายเหตุ |
|---|---|
| Model | การอ้างอิง config node npu-model ถ้าคุณตั้งค่าไว้ |
| or model name | ใช้เฉพาะเมื่อไม่ได้ตั้ง config node Model ไว้ — ชื่อเปล่า (yolox-nano-coco) หรือ name@version นี่คือวิธีที่ตัวอย่างโฟลว์ทั้งสองที่มาพร้อมเกตเวย์ใช้จริง |
| Threshold | ค่าความมั่นใจขั้นต่ำที่จะเก็บไว้ (ใช้ค่าเริ่มต้นของโมเดลถ้าเว้นว่าง) |
| IoU | เกณฑ์ IoU สำหรับ non-max-suppression (ใช้ค่าเริ่มต้นของโมเดลถ้าเว้นว่าง) |
| Classes | class ID คั่นด้วย comma ที่จะจำกัดผลลัพธ์ไว้เฉพาะ; เว้นว่าง = ทั้งหมด |
msg.payload จะได้ผลลัพธ์กลับมาแบบนี้:
{
model: "[email protected]",
inferMs: 191.9, preMs: 3.1, postMs: 1.8,
detections: [
{ label: "Hardhat", classId: 0, score: 0.91,
box: { x: 412, y: 130, w: 220, h: 480 },
boxNorm: { x: 0.2146, y: 0.1204, w: 0.1146, h: 0.4444 } }
]
}
สามารถ override ต่อข้อความได้ผ่าน msg.npu.model/threshold/iou/
classes/roi เอาต์พุตที่ 2 จะทำงานเมื่อไม่ได้ตั้งค่าโมเดล, frame handle
หมดอายุ, หรือโมเดลที่ระบุไม่ได้ติดตั้งไว้ — พร้อมสถานะเฉพาะเจาะจง ("model
not found", "frame expired") แทนที่จะเป็น error ทั่วไป
npu-watch: "มี X อยู่ไหม มีกี่ตัว ขอดูภาพหน่อย"¶
อยู่ ถัดจาก npu-detect — ไม่ได้เรียกโมเดลเอง แค่กรองรายการผลตรวจจับ
ที่มีอยู่แล้วหา label เดียว:

| ฟิลด์ | หมายเหตุ |
|---|---|
| Watch for label | ข้อความ label ที่ต้องตรงเป๊ะ (ตรงกับค่าที่ตั้งค่า Labels บน engine แปลงออกมา) |
| Min score | ความมั่นใจขั้นต่ำที่จะนับว่า "มีอยู่" |
| Snapshot JPEG quality | คุณภาพของภาพสแนปช็อตที่สร้างขึ้น |
| Always snapshot | สร้างสแนปช็อตทุกครั้ง แม้ label นั้นจะไม่มีอยู่ เทียบกับสร้างเฉพาะตอนที่เจอ |
เอาต์พุต: { label, present, count, detections: [...เฉพาะที่ตรงกัน], snapshot: "data:image/jpeg;base64,..." }
— snapshot ใส่ลงใน src ของ image widget บนแดชบอร์ดได้ตรง ๆ และ
msg.frame จะพก handle ใหม่ที่วาดเฉพาะกรอบที่ตรงกัน (ธรรมเนียมเดียวกับ
npu-draw)
npu-detect หนึ่งตัวป้อนให้โหนด npu-watch หลายตัวพร้อมกันได้ แต่ละตัว
เฝ้าดูคนละ label — ดูหัวข้อ "ตัวอย่าง: เฝ้าดูหลาย class พร้อมกัน" ด้านล่าง
การนำพิกเซลเข้า-ออก¶
มีเพียงสองโหนดเท่านั้นที่เป็นจุดที่ไบต์พิกเซลข้ามพรมแดนระหว่าง Node-RED กับ engine จริง ๆ:
npu-buffer-to-frame— ขาเข้า: รับ Buffer จากmsg.payload(JPEG/PNG ตรวจจับอัตโนมัติจาก magic bytes หรือ rawrgb24ที่ตั้งค่า width/height ไว้) แล้วลงทะเบียนกับ engine ส่งออกเป็น frame handlenpu-frame-to-jpeg— ขาออก: รับ frame handle แล้วแปลงเป็นไบต์ JPEG/PNG ในmsg.payloadเป็น Buffer ดิบ หรือ (ถ้าติ๊ก output a data: URL string) เป็นสตริงdata:image/jpeg;base64,...พร้อมใช้กับ image widget บนแดชบอร์ด

พรีวิวภาพในเอดิเตอร์โดยไม่ต้องมีแดชบอร์ด
เว้น output a data: URL string ไม่ติ๊กไว้ (โหนดจะส่ง Buffer
ดิบออกมา) แล้วป้อนเข้าโหนด debug ธรรมดาตรง ๆ debug sidebar ของ
Node-RED เองจะเรนเดอร์ Buffer ที่หน้าตาเหมือนภาพให้เป็นภาพย่อที่คลิกได้
— ไม่ต้องใช้แพ็กเกจแดชบอร์ด ไม่ต้องเพิ่มโหนดใด ๆ:

การครอปและการวาด¶
npu-roiครอปเฟรมได้สองแบบ: ครอปตามผลตรวจจับแต่ละรายการ (msg.payload.detections[].box— หนึ่งครอปต่อหนึ่งกรอบ) หรือครอปตาม สี่เหลี่ยมตำแหน่งคงที่ที่คุณตั้งค่าไว้ คืนค่าเป็น frame handle ใหม่หนึ่ง หรือหลายอัน ส่งออกเป็นข้อความเดียวที่มี array ของ handle หรือหนึ่ง ข้อความต่อหนึ่งครอปก็ได้ มีตัวเลือก padding และครอปเป็นสี่เหลี่ยมจัตุรัส ด้วย ไม่รองรับ ROI แบบหลายเหลี่ยม (polygon) — รับเฉพาะสี่เหลี่ยมผืนผ้าnpu-drawรับเฟรมกับรายการผลตรวจจับ แล้ววาดกรอบ/label/score ลงบน frame handle ใหม่ — ตัวต้นฉบับไม่ถูกแตะต้อง ส่งผลลัพธ์ต่อไปยังnpu-frame-to-jpegเพื่อดูภาพจริงnpu-filterคือ "if แบบไม่ต้องเขียนโค้ด" สำหรับรายการผลตรวจจับ: allow-list ของ label, score ต่ำสุด/สูงสุด, ความกว้าง/สูงขั้นต่ำของกรอบ, อัตราส่วนภาพต่ำสุด/สูงสุด เป็น JavaScript ล้วน ๆ ไม่เรียก engine — ยัง ทำงานได้แม้ engine เองจะออฟไลน์
npu-engine-status¶
ทุกครั้งที่มีข้อความเข้า (หรือตามรอบเวลาที่ตั้งไว้) จะตรวจสอบสุขภาพ/
ความสามารถของ engine แล้วส่งออกเป็น msg.payload:
{ soc, npuCores, driver, runtime, apiVersion, backend, uptime, models, sources, health, error }
ป้อนจากโหนด inject เพื่อใช้กับ tile บนแดชบอร์ดหรือหัวข้อ MQTT
health-check
ตัวอย่าง: เฝ้าระวังความปลอดภัยด้วยการตรวจหมวกนิรภัย¶
ตัวอย่างโฟลว์ตรวจสอบการสวมอุปกรณ์ป้องกัน (PPE) ของเกตเวย์เอง —
npu-camera → npu-detect (โมเดลตรวจหมวกนิรภัย/ไม่สวมหมวกนิรภัย) →
npu-watch (เฝ้าดู "Hardhat") → พรีวิวสแนปช็อตใน debug sidebar:

โหนด npu-camera ในที่นี้เป็นแหล่งภาพแบบ folder (โฟลเดอร์ภาพ/เฟรม
วิดีโอเดินตรวจที่ engine วนอ่านไปเรื่อย ๆ) — ดูหัวข้อ "รายชื่อโหนด"
ด้านบนสำหรับแหล่งภาพชนิดอื่น สถานะที่แสดงบนโหนดเป็นตัวเลขจริงแบบเรียล
ไทม์จากเกตเวย์ที่กำลังทำงานอยู่: เฟรมที่สตรีมเข้ามา ผลตรวจจับต่อรอบ เวลา
ที่ใช้ในการตรวจจับ และจำนวนครั้งที่เจอ label ที่เฝ้าดู
ตัวอย่าง: เฝ้าดูหลาย class พร้อมกัน¶
npu-detect หนึ่งตัวสามารถกระจายผลไปยังโหนด npu-watch หลายตัว แต่ละตัว
เฝ้าดูคนละ label ได้ โดยไม่ต้องรันโมเดลมากกว่าหนึ่งครั้งต่อเฟรม —
ตัวอย่างโฟลว์ที่สองของเกตเวย์นำโมเดลตรวจจับ COCO ทั่วไปกลับมาใช้ซ้ำ
(yolox-s-coco — ไม่ต้องใช้โมเดลใหม่ เพราะ 80 class ของ COCO มีชนิดยาน
พาหนะอยู่แล้ว) แล้วกระจายไปยังการเฝ้าดู 4 ทางพร้อมกัน:

npu-draw (วาดกรอบยานพาหนะทุกคันเพื่อทำสแนปช็อตภาพรวม) และโหนด
npu-watch แต่ละตัวต่างอ่านรายการผลตรวจจับชุดเดียวกันจากต้นทาง — โมเดล
รันเพียงครั้งเดียวต่อเฟรม ไม่ว่าจะเฝ้าดูกี่ label ก็ตาม
ข้อจำกัดที่ทราบอยู่แล้ว¶
สืบทอดมาจากบันทึกทางวิศวกรรมของโปรเจกต์เองอย่างตรงไปตรงมา — อย่าสมมติว่า สิ่งต่อไปนี้ใช้งานได้เพียงเพราะมีฟิลด์ให้กรอก:
- ไม่รองรับกล้อง RTSP และ USB/V4L2 แบบสด Kind ของ
npu-cameraจำกัดอยู่แค่folder(ลำดับภาพ),file(ไฟล์วิดีโอ ถอดรหัสด้วย ซอฟต์แวร์) และpush(ป้อนโดยnpu-buffer-to-frameหรือผู้เรียกจาก ภายนอก) กล้องเครือข่าย/USB แบบสดเป็นแผนงานในอนาคต ยังใช้ไม่ได้ในตอนนี้ - ตัวเลขการดรอปเฟรมของ
npu-cameraเป็นค่าประมาณ อนุมานจากช่องว่าง ของหมายเลขลำดับเฟรมฝั่ง client — engine ยังไม่มีตัวนับการดรอปที่แม่นยำ ต่อแหล่งภาพให้ใช้ - frame handle จะหมดอายุ 5 วินาทีหลังถูกส่งออกมา ถ้าไม่มีอะไรมาใช้
งานมัน โฟลว์ที่ทำงานช้าเกินไปเทียบกับอัตราเฟรมของกล้องจะเจอ error
E_FRAME_EXPIREDที่เอาต์พุตที่ 2 ของโหนดที่พยายามใช้ handle ที่หมด อายุแล้ว — นี่คือพฤติกรรม backpressure ที่ตั้งใจให้เป็นแบบนี้ ไม่ใช่บั๊ก ที่ต้องหาทางเลี่ยง - มีโมเดลเดียวที่รันได้ในแต่ละช่วงเวลาบน RK3566 (EPG-002S) — ดูหัวข้อ "มีโมเดลเดียวที่รันได้ในแต่ละช่วงเวลาบน RK3566" ด้านบน
- บันเดิลโมเดลเริ่มต้นที่มีมาให้ใช้ตระกูลที่มีสัญญาอนุญาตแบบเปิดกว้าง (YOLOX, PP-YOLOE, MobileNetV3, PP-OCRv4) สถาปัตยกรรม YOLOv8/v11 ก็ รองรับโดย engine หากคุณนำ weight ของตัวเองมาใช้ แต่ต้นทางมีสัญญาอนุญาต แบบ AGPL-3.0 จึงไม่ใช่ตัวเลือกเริ่มต้นที่ระบบเสนอให้ — เป็นทางเลือกด้าน สัญญาอนุญาต ไม่ใช่ข้อจำกัดทางเทคนิค
ต่อไป: MQTT broker (Aedes) หรือย้อนกลับไปที่ การเชื่อมต่อ Modbus / PLC สำหรับการเชื่อมต่อ PLC แทน คอมพิวเตอร์วิทัศน์