บทเรียน 6.5 — sensor fusion: verdict ของโมเดลกับเซนเซอร์ดิบ

เอา verdict ของโมเดล มารวมกับเซนเซอร์ดิบ แล้วสตรีมขึ้นคลาวด์

โมดูล 6 — แอป Edge AI

โมดูล 6 (Apps) — ชุดบทเรียนปิดกล่อง (fusion + IoT)

คาถาประจำบทเรียน: "โมเดลตอบว่า 'เจออะไร' — แต่การตัดสินใจที่เชื่อถือได้เกิดตอนเอา verdict มายืนยันกับเซนเซอร์ดิบอีกตัว แล้วส่งเหตุการณ์นั้นออกไปให้โลกภายนอกรู้"

MicroPython บนบอร์ด BENTO (PSoC Edge · Cortex-M55 + Ethos-U55 NPU)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เปิดบทเรียนด้วยของจริงก่อน

ยังใช้แนว กลับด้าน เหมือนทั้งคอร์ส — ชุดบทเรียนนี้เราจะรันแอปกันขโมย 3 เซนเซอร์ที่ทำงานได้จริงก่อน แล้วค่อยแกะว่ามัน "รวมสัญญาณหลายตัว" ยังไง แล้วต่อยอดให้มันคุยกับคลาวด์

รันแอปโหวตจริงก่อน 10_motion_alarm แกะการรวมสัญญาณ verdict + เซนเซอร์ดิบ ต่อ IoT เอง WiFi + MQTT สู่ Capstone 8.1–8.2

นี่คือขั้น Investigate → Modify → Make ของ PRIMM: เราเห็นแอปหลายเซนเซอร์ทำงานแล้ว (Run) ชุดบทเรียนนี้เปิดฝาดูวิธีรวมสัญญาณ (Investigate) แล้วเปลี่ยนจาก "โหวตดิบ 3 ตัว" เป็น "verdict ของโมเดล + เซนเซอร์ดิบ 1 ตัว → ส่งขึ้นคลาวด์" (Modify/Make)

บทเรียน 6.1–6.2 เราสร้างแอปโมเดลเดียว บทเรียน 6.3–6.4 เราต่อ action pipeline — ชุดบทเรียนนี้เป็นก้าวสุดท้ายของ โมดูล 6 (Apps): ทำให้การตัดสินใจ เชื่อถือได้ขึ้น (fusion) แล้ว ออกไปไกลกว่าบอร์ด (IoT)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เป้าหมายของชุดบทเรียนนี้

จบชุดบทเรียนนี้เราจะเดินครบ 4 เรื่อง แล้วปิดท้ายด้วยการสตรีมเหตุการณ์ Edge AI ขึ้นคลาวด์:

  1. Sensor fusion คืออะไร — ทำไม verdict ของโมเดลอย่างเดียวยังไม่พอ
  2. verdict + raw sensor — เอาคำตอบของโมเดล (what) มายืนยันกับสัญญาณดิบ (how strong)
  3. IoT streaming — wifi.connect() ต่อเน็ต แล้ว mqtt.publish() ส่งเหตุการณ์ออกไป
  4. degrade อย่างสง่างาม — โค้ดชุดเดียวรันได้ทั้งบอร์ด (มีเน็ต) และ Emulator (ไม่มีเน็ต)
  5. ลงมือ: เติม s17_fusion_iot.py — fuse verdict กับ gyro ดิบ แล้ว publish ขึ้น MQTT

ปลายทางของวันนี้: พอโมเดลจับ shaking และ gyro ดิบแรงพอ แอปจะยิงเหตุการณ์เดียว ขึ้น MQTT broker (หรือลง console ถ้าอยู่ Emulator)

วันนี้เราต่อยอดจาก "verdict → action" (บทเรียน 6.3–6.4) ไปอีกสองชั้น: action ที่ ผ่านการยืนยัน (fusion) และ action ที่ ไปถึงคลาวด์ (IoT)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ชุดบทเรียนนี้อยู่ตรงไหนของคอร์ส

บทเรียน 6.5–6.6 เป็นบทเรียน ปิดกล่อง โมดูล 6 (Apps) — จากอ่านผล (บทเรียน 6.1–6.2) สู่สั่งการ (บทเรียน 6.3–6.4) จนถึงตัดสินใจแบบรวมสัญญาณ + ส่งออก (บทเรียน 6.5–6.6) ก่อนเข้าสู่ โมดูล 7 (Researcher)

บทเรียน 6.1–6.2 แอปโมเดลเดียว บทเรียน 6.3–6.4 action pipeline บทเรียน 6.5–6.6 (วันนี้) fusion + IoT บทเรียน 7.1–7.2+ ใต้ฝากระโปรง
  • บทเรียน 6.1–6.4 ให้เรา "อ่าน verdict แล้วสั่งการบนบอร์ด" — action จบในกล่องเดียว
  • บทเรียน 6.5–6.6 ต่อยอด: การตัดสินใจ ผ่านการยืนยันด้วยเซนเซอร์ที่สอง (fusion) แล้ว ส่งออกนอกบอร์ด (IoT) — บอร์ดกลายเป็นโหนดในระบบที่ใหญ่ขึ้น
  • จบชุดบทเรียนนี้ โมดูล 6 (Apps) ครบ แล้วบทเรียน 7.1–7.2 เราจะมุดลงไปดูสแตก Edge AI จริงๆ (tri-core, ai_engine, IPC)

"กลับด้าน" ยังทำงานเหมือนเดิม: เห็นแอปหลายเซนเซอร์สำเร็จก่อน (10_motion_alarm.py) แล้วย้อนเข้าใจ จนต่อยอดเป็นระบบ IoT ของเราเองได้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ทบทวนเร็ว — verdict + action จากชุดบทเรียนก่อนหน้า

ก่อนเติม fusion เรียกของเดิมกลับมาในหัวก่อน ชุดบทเรียนนี้ยืนบน pattern เดิมเป๊ะ แค่เพิ่มสองชั้นบนสุด:

แนวคิด มาจากบทเรียน ชุดบทเรียนนี้ใช้ยังไง
edge_ai.select() / result() 1, 3, 15 เลือกโมเดล + อ่าน verdict (เหมือนเดิม)
label + conf >= CONF_FLOOR 3, 16 เงื่อนไข "โมเดลมั่นใจพอ" (ชั้นแรกของ fusion)
edge-trigger (fired) 3, 16 ยิงเหตุการณ์ครั้งเดียวต่อการเจอ (ไม่ spam broker)
sensors.bmi270.motion() 4, 7 อ่านเซนเซอร์ดิบ (ชั้นที่สองของ fusion)

ชุดบทเรียนนี้เพิ่มสองแนวคิดใหม่บนฐานนี้: การรวม verdict กับเซนเซอร์ดิบ (fusion) และ การส่งเหตุการณ์ออกทางเน็ต (wifi + mqtt)

ถ้ายังไม่แม่นเรื่อง verdict → action เปิด s03_anatomy_edgeai.py อ่านทวนก่อน — ชุดบทเรียนนี้ต่อจากตรงนั้นพอดี

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

รันของจริงก่อน — แอปกันขโมย 3 เซนเซอร์

ก่อนแกะโค้ด รันแอปอ้างอิงให้เห็นการรวมสัญญาณด้วยตาก่อน (ทำได้บน Emulator และ PSoC Edge AI Kit ส่วนบน TESAIoT Dev Kit ตัวอย่างนี้ยังเปิดไมโครโฟน PDM ไม่ได้ ดูหมายเหตุหัวไฟล์):

  1. เปิด ide.tesaiot.dev หรือ BENTO IDE เสียบบอร์ด
  2. รัน 10_motion_alarm.py — ระบบเฝ้าระวัง 3 เซนเซอร์
  3. กดสวิตช์ Arm แล้วลอง: ยื่นมือเข้าเรดาร์ · เขย่าบอร์ด · ส่งเสียงดัง
  4. สังเกต: มัน ไม่ได้ปลุกทุกครั้งที่เซนเซอร์ตัวเดียวไหว — ต้อง "โหวต 2 ใน 3" ถึงจะขึ้น !! INTRUDER !!
  5. ลองทำให้เซนเซอร์ตัวเดียวไหว (แค่เขย่าเบาๆ) ดูว่ามัน ไม่ยอมปลุก — นั่นแหละคือ fusion

จับความรู้สึกนี้ไว้: "เซนเซอร์ตัวเดียวไม่พอ ต้องให้หลายตัวเห็นตรงกันก่อนถึงจะเชื่อ" — ชุดบทเรียนนี้เราจะเอาหลักเดียวกันมาใช้กับ verdict ของโมเดล + เซนเซอร์ดิบ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ปัญหาของโมเดลเดี่ยว — false positive

โมเดลไม่ได้ถูกเสมอ บางท่า/บางเสียงมันก็ "เดา" คลาสผิดด้วยความมั่นใจพอสมควร ถ้าเราสั่งการทุกครั้งที่ verdict เข้าเงื่อนไข action จะยิงพลาดบ่อย

โมเดลเดี่ยว (บทเรียน 6.3–6.4) verdict "shaking" 62% → ยิง action แต่จริงๆ แค่วางบอร์ดแรงไปหน่อย false positive → ปลุกพร่ำเพรื่อ fusion (ชุดบทเรียนนี้) verdict "shaking" 62% AND gyro ดิบ > เกณฑ์ → ค่อยยิง สองสัญญาณเห็นตรงกัน → เชื่อได้
  • โมเดลให้ ป้ายคลาส + ความน่าจะเป็น แต่มันไม่รู้ "แรงจริงแค่ไหน" ในหน่วยฟิสิกส์
  • เซนเซอร์ดิบให้ ตัวเลขจริง (เช่น gyro องศา/วินาที) ที่โมเดลไม่เห็นตรงๆ
  • เอาสองอย่างมา ยืนยันซึ่งกันและกัน = ตัดสินใจที่ทนต่อ false positive มากขึ้น

นี่คือเหตุผลที่ระบบจริงไม่ค่อยเชื่อเซนเซอร์ตัวเดียว — รถยนต์ใช้ทั้งกล้อง+เรดาร์+lidar ก่อนเบรก เพราะแต่ละตัวพลาดคนละแบบ เอามารวมกันจึงน่าเชื่อถือ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

Sensor fusion คืออะไร

Sensor fusion = รวมข้อมูลจากหลายแหล่งเข้าเป็นการตัดสินใจเดียวที่ดีกว่าใช้แหล่งเดียว ชุดบทเรียนนี้เราทำแบบง่ายที่สุดแต่ทรงพลัง: model verdict + raw sensor gate

verdict ของโมเดล label + conf (NPU/M55) เซนเซอร์ดิบ gyro energy (M33) รวม (AND) เห็นตรงกัน? fused decision เชื่อถือได้ → ยิงเหตุการณ์
  • โมเดล เก่งเรื่อง "รู้จำรูปแบบ" (นี่คือท่าเขย่าไหม) แต่ไม่รู้ค่าฟิสิกส์
  • เซนเซอร์ดิบ เก่งเรื่อง "ค่าจริง" (แรงกี่องศา/วินาที) แต่ไม่รู้ว่ามันเป็นรูปแบบอะไร
  • fusion = เอาจุดแข็งสองอย่างมาค้ำกัน — action ยิงเมื่อ ทั้งคู่ เห็นตรงกันเท่านั้น

เราเลือก fusion แบบ AND ในชุดบทเรียนนี้เพราะเข้าใจง่ายและกัน false positive ได้ทันที ในงานจริงมี fusion ที่ซับซ้อนกว่านี้ (ถ่วงน้ำหนัก · Kalman) แต่หลักคิดเริ่มจากตรงนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

สอง "รส" ของ fusion ที่ใช้บ่อย

fusion ในชุดบทเรียนนี้ (verdict + raw gate) เป็นแบบ corroboration แต่รู้ไว้ว่ามีอีกแบบที่แอปอ้างอิงใช้ (10_motion_alarm.py):

corroboration gate (ชุดบทเรียนนี้) สัญญาณหลัก 1 ตัว (verdict โมเดล) + ประตูยืนยัน 1 ตัว (raw gyro) ยิงเมื่อทั้งคู่ผ่าน (AND) โฟกัส: กัน false positive majority vote (10_motion_alarm) 3 เซนเซอร์ดิบ (radar/imu/mic) โหวต ≥ 2 ใน 3 → ปลุก ยอมให้เซนเซอร์ตัวหนึ่งพลาดได้ โฟกัส: ทนต่อเซนเซอร์เสีย
  • corroboration (AND) — เข้มงวด: ต้องผ่านทุกด่าน เหมาะกับ "อย่าปลุกถ้าไม่ชัวร์"
  • majority vote (≥k of n) — ยืดหยุ่น: ยอมให้ตัวหนึ่งพลาด เหมาะกับ "อย่าพลาดของจริงแม้เซนเซอร์ตัวหนึ่งเสีย"
  • ฉบับเต็มของเรา (examples/) จะให้ลองสลับ raw gate เป็น sensors.radar() เพื่อชิมรสของ multi-modal ด้วย

ไม่มีแบบไหน "ถูกกว่า" — เลือกตามความเสี่ยง งานปลุกภัยเลือก vote (พลาดไม่ได้) งานสั่งการอัตโนมัติเลือก AND (ยิงพลาดแล้วกวนใจ)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

คณิตของ fusion (1) — โหวต k จาก n

การ "โหวต 2 ใน 3" ที่เห็นตอนรัน 10_motion_alarm.py เขียนเป็นสูตรสั้นๆ ได้แบบนี้ — ไม่ต้องกลัว เดี๋ยวเราค่อยๆ แกะทีละตัว:

fire  =  [  ∑i=1nsi  ≥  k  ]\text{fire} \;=\; \Big[\; \sum_{i=1}^{n} s_i \;\ge\; k \;\Big]

อ่านสัญลักษณ์ทีละตัว (ภาษาคนธรรมดา):

  • nn = จำนวนเซนเซอร์ทั้งหมด — แอปกันขโมยมี radar · imu · mic จึง n=3n=3
  • sis_i = ผลของเซนเซอร์ตัวที่ ii เป็นเลขฐานสอง: si=1s_i=1 ถ้า "เห็นสัญญาณ", si=0s_i=0 ถ้า "เงียบ"
  • ∑i=1nsi\sum_{i=1}^{n} s_i = นับว่ามีกี่ตัวที่เห็นตรงกัน (บวก 1 ทุกตัวที่ไหว)
  • kk = เกณฑ์เสียงข้างมากที่เราตั้ง — ชุดบทเรียนนี้ k=2k=2 จึงกลายเป็น "2 ใน 3"
  • [ ⋅ ][\,\cdot\,] = วงเล็บ Iverson: เงื่อนไขจริงคืนค่า 11 (ปลุก), เท็จคืนค่า 00 (เงียบ)

ทำไมสำคัญกับชุดบทเรียนนี้: ตั้ง k=2, n=3k=2,\, n=3 คือ majority vote ที่ทน "เซนเซอร์ตัวหนึ่งพลาด" ได้ (11 ตัวเงียบยัง fire ได้) — ตรงกับความรู้สึกตอนเขย่าเบาๆ แล้วมัน "ไม่ยอมปลุก"

จำภาพนี้ไว้: ยิ่ง kk ใกล้ nn ยิ่งเข้มงวด (ต้องเห็นตรงกันหลายตัว) — พอ k=nk=n เมื่อไร มันก็กลายเป็น AND ที่เราใช้ในชุดบทเรียนนี้พอดี

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

คณิตของ fusion (2) — ถ่วงน้ำหนัก + AND

บางเซนเซอร์เชื่อได้มากกว่าตัวอื่น เราจึงให้ "น้ำหนัก" wiw_i ต่างกันได้ แล้วรวมเป็นคะแนนเดียว:

S  =  ∑i=1nwi sifire  =  [  S≥θ  ]S \;=\; \sum_{i=1}^{n} w_i\, s_i \qquad\qquad \text{fire} \;=\; \big[\; S \ge \theta \;\big]

  • wiw_i = น้ำหนักความเชื่อถือของเซนเซอร์ตัวที่ ii — ยิ่งไว้ใจ ยิ่งให้มาก
  • SS = คะแนนรวมแบบถ่วงน้ำหนัก (เซนเซอร์สำคัญออกเสียงดังกว่า)
  • θ\theta = เกณฑ์ (threshold) ที่คะแนนรวมต้องข้ามถึงจะ fire

corroboration gate (AND) ที่เราเขียนชุดบทเรียนนี้เป็น กรณีพิเศษ ของสูตรข้างบน — มีแค่สองสัญญาณ (n=2n=2: verdict กับ raw gyro), ให้ wi=1w_i=1 เท่ากัน, แล้วตั้ง θ=n\theta = n:

AND  ≡  (k=n)  ≡  (θ=∑i=1nwi)\text{AND} \;\equiv\; \big(k = n\big) \;\equiv\; \Big(\theta = \sum_{i=1}^{n} w_i\Big)

  • ตั้ง θ\theta เท่าผลรวมน้ำหนัก → ต้องผ่าน ทุกตัว ถึง fire = นั่นคือ model_hit and raw_ok
  • ลด θ\theta ลง → ผ่อนเป็นโหวตเสียงข้างมาก · เพิ่ม wiw_i ของ raw gyro → ให้เซนเซอร์ดิบมีสิทธิ์ยับยั้งแรงขึ้น

เห็นไหมว่าทั้ง vote, AND และ weighted เป็นสูตรเดียวกัน ต่างกันแค่ค่า kk, wiw_i, θ\theta — โค้ด fused = model_hit and raw_ok ในชุดบทเรียนนี้คือมุมที่เข้มงวดที่สุดของสูตรนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

verdict (what) + raw sensor (how strong)

หัวใจของ fusion ชุดบทเรียนนี้: โมเดลกับเซนเซอร์ดิบ ตอบคนละคำถาม — เอามาประกบกันจึงได้ภาพครบ

โมเดล (edge_ai) เซนเซอร์ดิบ (sensors)
ตอบอะไร "นี่คือท่าอะไร" (label) "แรงเท่าไรจริงๆ" (ตัวเลข)
หน่วย ความน่าจะเป็น 0..1 (conf) ฟิสิกส์ (องศา/วินาที, dBFS, เมตร)
รันที่ไหน CM55 + NPU CM33 (Python ของเรา)
จุดอ่อน เดาผิดได้ (false positive) ไม่รู้ว่ารูปแบบคืออะไร
  • โมเดลอาจตอบ shaking ตอนที่คุณแค่ยกบอร์ดเร็วๆ — conf อาจสูงพอผ่าน CONF_FLOOR ด้วยซ้ำ
  • แต่ถ้าเราเช็ก gyro ดิบด้วย จะเห็นว่าตอนยกเบาๆ ค่ามันไม่ถึงเกณฑ์จริง → fusion บอกว่า "ยังไม่ใช่"

จำประโยคนี้ไว้: โมเดลบอก "อะไร" เซนเซอร์ดิบบอก "แค่ไหน" — เอาสองมิตินี้มา AND กัน คือ fusion ที่ง่ายที่สุดและได้ผลจริง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

gate ด้วย raw feature — ทบทวน บทเรียน 3.3–3.4

ประตูยืนยัน (gmag > MOTION_FLOOR) คือ rule classifier ที่เราทำเป็นแล้วในบทเรียน 3.3–3.4 เราแค่เอามันมาต่อท้าย verdict ของโมเดล

# ฟีเจอร์ดิบจาก IMU (เหมือนบทเรียน 2.1–2.2 + 3.3–3.4): พลังงานการหมุนรวม 3 แกน
ax, ay, az, gx, gy, gz = sensors.bmi270.motion()
gmag = abs(gx) + abs(gy) + abs(gz)     # องศา/วินาที รวม — ยิ่งสูง ยิ่งหมุนแรง

raw_ok = gmag > MOTION_FLOOR           # ประตูฟิสิกส์ (rule จากบทเรียน 3.3–3.4)
  • gmag คือฟีเจอร์แบบเดียวกับที่ 10_motion_alarm.py ใช้ (abs(gx)+abs(gy)+abs(gz) เทียบ baseline)
  • นี่คือ "การประมวลผลสัญญาณ" ขั้นต้น (Processing/Analysis ในวงจร 5 ขั้น) เอามาค้ำ verdict
  • MOTION_FLOOR เป็นค่าคงที่บนหัวไฟล์ — remix ได้: ตั้งสูง = เข้มงวด, ตั้งต่ำ = ไวขึ้น

fusion ไม่ใช่เวทมนตร์ — มันคือ "โมเดล (บทเรียน 1.6–1.7) + rule เซนเซอร์ (บทเรียน 3.3–3.4)" ที่คุณทำเป็นทั้งคู่แล้ว เอามาต่อกัน ชุดบทเรียนนี้แค่ประกอบร่าง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

โครง 4 จังหวะของแอปชุดบทเรียนนี้

แอปชุดบทเรียนนี้ต่อจากโครง 3 จังหวะของบทเรียน 1.6–1.7 (select → result → action) แล้วแทรก fuse เข้าไปกลาง แล้วขยาย action เป็น publish

1 · select find_model → select() + ต่อ WiFi/MQTT 2 · result verdict + วาดจอ label · conf 3 · fuse verdict AND raw gate gyro ดิบ ← ของใหม่ 4 · publish mqtt.publish(event) ขึ้นคลาวด์ ← ของใหม่ เลือก ──▶ อ่าน ──▶ รวมสัญญาณ ──▶ ส่งออก จังหวะ 1–2 = ของเดิม · จังหวะ 3 (fuse) + 4 (publish) = หัวใจใหม่ของชุดบทเรียนนี้

จังหวะ 3 กับ 4 คือสิ่งที่ทำให้แอปชุดบทเรียนนี้ต่างจากบทเรียน 6.3–6.4 — เดิม action จบบนบอร์ด คราวนี้ action ผ่านการยืนยัน แล้ว เดินทางออกไปหาคลาวด์

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

อ่านเซนเซอร์ดิบ — sensors.bmi270.motion()

จังหวะ fuse เริ่มที่อ่านสัญญาณดิบมาประกบ verdict sensors.bmi270.motion() คืน 6 ค่าในครั้งเดียว:

import sensors
ax, ay, az, gx, gy, gz = sensors.bmi270.motion()
# ax,ay,az = ความเร่ง 3 แกน (m/s²) · gx,gy,gz = อัตราหมุน 3 แกน (°/s)
gmag = abs(gx) + abs(gy) + abs(gz)      # พลังงานการหมุนรวม
  • motion() เป็นการอ่าน ดิบ บน CM33 — ไม่ผ่าน NPU ไม่ผ่านโมเดล เป็นตัวเลขฟิสิกส์ตรงๆ
  • เราเลือกใช้ gyro (gx,gy,gz) เพราะ "เขย่า/หมุน" เห็นชัดที่อัตราหมุน — ตรงกับโมเดล Motion
  • อยากใช้เซนเซอร์อื่นเป็น gate ก็ได้: sensors.radar()["presence"] (มีคนไหม) เป็น gate แบบ multi-modal

เซนเซอร์ตัวเดียวกับที่ป้อนโมเดล (IMU) แต่เราอ่าน คนละเส้นทาง: โมเดลเห็นหน้าต่างสัญญาณผ่าน NPU ส่วนเราอ่านค่าปัจจุบันดิบๆ — สองมุมมองของสัญญาณเดียวกัน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เงื่อนไข fused — สองด่านต้องผ่านทั้งคู่

การตัดสินใจแบบ fused = verdict ของโมเดลผ่าน และ เซนเซอร์ดิบผ่าน ทั้งสองด่านต้องจริงพร้อมกัน:

model_hit = (r['label'] == TARGET_CLASS            # 1) ใช่คลาสเป้าหมาย
             and r['conf'] >= edge_ai.CONF_FLOOR)  #    + โมเดลมั่นใจพอ
raw_ok    = gmag > MOTION_FLOOR                     # 2) เซนเซอร์ดิบแรงพอจริง

fused = model_hit and raw_ok                        # AND — ต้องผ่านทั้งคู่
  • ด่านแรก (model_hit) คือของเดิมจากบทเรียน 1.6–1.7 / 6.3–6.4 — โมเดลตอบถูกคลาส + มั่นใจถึงเกณฑ์
  • ด่านสอง (raw_ok) คือของใหม่ — ค่าฟิสิกส์ยืนยันว่า "แรงจริง" ไม่ใช่โมเดลเดาเอา
  • and ทำให้ false positive ของโมเดลถูกกรองออก ถ้าเซนเซอร์ดิบไม่เห็นด้วย

ลองคิดกลับกัน: ถ้าคุณ เขย่าแรงมาก แต่โมเดลบังเอิญตอบ idle — fused ก็ยังเป็น False เพราะ model_hit ไม่ผ่าน สอง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

edge-trigger — ยิงเหตุการณ์ครั้งเดียว

เหมือนบทเรียน 6.3–6.4 เราไม่อยากส่ง MQTT รัวทุกเฟรมที่ยัง fused อยู่ — ใช้ธง fired ยิง "ตอนขอบขาขึ้น" ครั้งเดียว

if fused and not fired:        # เพิ่งเข้าเงื่อนไข fused → ส่งครั้งเดียว
    publish_event(r['conf'], gmag)
    fired = True
elif not fused:                # ออกจากเงื่อนไขแล้ว → รีเซ็ต
    fired = False
  • ยิ่งสำคัญกับ IoT: broker สาธารณะและ bandwidth มีจำกัด — spam ทุกเฟรม = โดน rate-limit / เปลืองพลังงาน
  • fired ตั้ง True ตอนส่ง เคลียร์ False ตอนหลุดเงื่อนไข → หนึ่งเหตุการณ์ = หนึ่งข้อความ MQTT

pattern เดียวกับปุ่มกด (บทเรียน 1.6–1.7) และ debounce (บทเรียน 6.3–6.4) — เหตุการณ์ที่ส่งออกนอกบอร์ดยิ่งต้องคุมจังหวะ เพราะปลายทางคือระบบที่เราไม่ได้คุมคนเดียว

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0