ส่วนหัวไฟล์คือ "ปุ่มออกแบบ" ที่ทีมปรับได้ แล้ว find_model หาโมเดลจากชื่อ (ถามฮาร์ดแวร์ ไม่ hard-code index):
MODEL_KEYWORD = "Motion" # โมเดลที่เฝ้า
HITS_NEEDED = 3 # debounce: เจอติดกันกี่ครั้งถึงสั่งการ
EMA_ALPHA = 0.4 # ความหนักของตัวกรอง conf
model = find_model(MODEL_KEYWORD)
labels = model['labels']
alert_idx = len(labels) - 1 # คลาสสุดท้าย = เหตุการณ์ที่สนใจ
conf_ema = dsp.EMA(alpha=EMA_ALPHA) # สร้างตัวกรองครั้งเดียว
alert_idx = len(labels) - 1 — กติกาออกแบบ: คลาสสุดท้ายคือ "เหตุการณ์" (shaking/baby_cry/Push/cough)
conf_emaสร้าง นอกลูป เพราะมันต้องจำอดีต — สร้างซ้ำในลูปจะล้างความจำทุกเฟรม กรองไม่ได้ผล (บทเรียน "สร้างครั้งเดียว" จากบทเรียน 1.1–1.3)
ช่องเติมที่ 1 (เสา Apps · start): เมื่อกด Load สั่งให้โมเดลเริ่มรัน:
elif h == load_id:
try:
# เติม: edge_ai.select(model['index'])
pass
running = True
streak = 0
fired = False
status.text("RUNNING"); status.color(GREEN)
conf_ema.reset() # เริ่มเฝ้ารอบใหม่ ล้างตัวกรอง
except OSError as e:
status.text("ERROR") # ข้ามคอร์พลาดได้ ต้องเผื่อ
pass ด้วย edge_ai.select(model['index']) — ต้องอยู่ใน try เพราะ select() โยน OSError ได้conf_ema.reset() ตอน Load — เริ่มเฝ้ารอบใหม่ต้องล้างความจำตัวกรองให้สะอาดขึ้น RUNNING หลัง
select()สำเร็จเท่านั้น เหมือนบทเรียน 1.1–1.3 — ถ้า error กระโดดไป except ไม่โกหกผู้ใช้ว่ากำลังเฝ้า
ช่องเติมที่ 2 (เสา DAQ): อ่านความเร่งดิบมาเป็นบริบท ทุกวนรอบที่กำลังเฝ้า:
if running:
# เติม: ax, ay, az = sensors.bmi270.acceleration()
ax, ay, az = 0.0, 0.0, 0.0
pass
mag = (ax*ax + ay*ay + az*az) ** 0.5
ctx.text("motion: %.1f" % mag)
pass ด้วย ax, ay, az = sensors.bmi270.acceleration() (ลบบรรทัด 0.0 ทิ้งหรือปล่อยไว้ก็ได้ เพราะถูกทับ)mag คือขนาดเวกเตอร์ความเร่ง — อยู่นิ่ง ~9.8, ถูกจับ/เขย่าพุ่งขึ้นmotion ค้างที่ 0.0 ตลอด (เพราะไม่ได้อ่านของจริง) — เสา DAQ ไม่ทำงานนี่คือเสาแรกสุดของวงจร (DAQ) ที่ยังมีบทบาทในผลิตภัณฑ์ปลายทาง — ทีมที่อยากต่อยอดการออกแบบ เอา
magไปทำ fusion gate ต่อได้ (โจทย์ต่อยอด)
ช่องเติมที่ 3 (เสา Apps · read): อ่านผลอนุมานล่าสุด แล้วทำงานเฉพาะตอนมีผลใหม่:
# เติม: r = edge_ai.result()
r = None
pass
if r and r['seq'] != last_seq: # มีผลใหม่จริงไหม
last_seq = r['seq']
...
pass ด้วย r = edge_ai.result() — คืน dict หรือ None ถ้ายังไม่มีผลr and r['seq'] != last_seq ก่อนเสมอ — วาด/ตัดสินใจเฉพาะตอนมีผลใหม่ (บทเรียน seq จากบทเรียน 1.1–1.3)r เป็น None ตลอด → การ์ดผลลัพธ์ไม่ขยับเลย
result()เป็นการ pull ผลจาก M55 — เรียกในลูปเมื่อไรก็ได้ ไม่บล็อกรอ คืนผลล่าสุดที่คอร์ AI คิดไว้
ช่องเติมที่ 4 (เสา Processing): กรองความมั่นใจให้นิ่งก่อนเอาไปเทียบเกณฑ์:
# เติม: conf_s = conf_ema.update(r['conf'])
conf_s = r['conf']
pass
sure = conf_s >= edge_ai.CONF_FLOOR
verdict.text(r['label'] or '-')
verdict.color(GREEN if sure else AMBER)
pass ด้วย conf_s = conf_ema.update(r['conf']) — .update() คืนค่าที่กรองแล้วออกมาเลยconf_s (ไม่ใช่ r['conf'] ดิบ) กับ CONF_FLOOR — ต่ำกว่าเกณฑ์เป็นเหลือง (not sure)จุดนี้คือที่ที่เสา Processing "แทรก" ระหว่าง verdict กับ decision — โมเดลพูด conf ดิบ เรากรองก่อน แล้วค่อยเชื่อ
ช่องเติมที่ 5 (เสา Apps · action): decision ผ่านสามด่านครบ → ยิง action:
hit = (top == alert_idx) and sure
if hit:
streak += 1
else:
streak = 0; fired = False
banner.text("รอจับ %s ..." % alert_name)
if streak >= HITS_NEEDED and not fired:
# เติม: fire_alert(r['label'], conf_s)
pass
fired = True
pass ด้วย fire_alert(r['label'], conf_s) — บี๊บ + แบนเนอร์ + นับครั้งfired = True หลังยิง — edge-trigger กันยิงรัวทุกเฟรมที่ยังเจออยู่ห้าช่องนี้คือกระดูกสันหลังของสามเสา: select (Apps) → sensors (DAQ) → result (Apps) → EMA (Processing) → fire_alert (Apps) เติมครบ = ผลิตภัณฑ์ทำงานครบวง
เปิด s20_capstone.py ไล่หา # เติม: ทั้ง 5 จุด แล้วแทน pass ด้วยคำสั่งจริง:
| # | เสา | จุด | เติมด้วย | ถ้าลืม |
|---|---|---|---|---|
| 1 | Apps | ปุ่ม Load | edge_ai.select(model['index']) |
RUNNING แต่ไม่มีผล |
| 2 | DAQ | ในลูป | ax, ay, az = sensors.bmi270.acceleration() |
motion ค้าง 0.0 |
| 3 | Apps | ในลูป | r = edge_ai.result() |
การ์ดไม่ขยับ |
| 4 | Processing | มีผลใหม่ | conf_s = conf_ema.update(r['conf']) |
สี/สถานะกระพริบ |
| 5 | Apps | ครบเกณฑ์ | fire_alert(r['label'], conf_s) |
ครบแล้วแต่เงียบ |
ขั้นตอน:
# เติม:เติมครบทั้งห้าแล้วยังไม่พอสำหรับ capstone — ขั้นต่อไปคือ ออกแบบ ของทีม: เฝ้าอะไร, action อะไร, ตั้งเกณฑ์เท่าไร เพราะอะไร
ไม่มีบอร์ดก็ทำ capstone ได้เต็มรูปแบบ (Guardian ใช้ IMU + edge_ai ที่ Emulator รองรับครบ):
s20_capstone.py เติม 5 ช่อง! ALERT: shaking ! + ตัวนับเพิ่ม แล้วลองทำพีคแวบเดียว — Guardian ไม่เตือนEmulator ใช้เซนเซอร์จำลอง แต่ API เหมือนบอร์ดจริงทุกบรรทัด — ซ้อมออกแบบที่บ้านได้เต็มที่ แล้วมายืนยันกับของจริงบนบอร์ด
โค้ด capstone ชุดเดียวรันได้ทั้งบนเบราว์เซอร์ (Emulator) และบน MCU จริง (Cortex-M55) โดย API เหมือนกันทุกบรรทัด ส่วน Cortex-A ใช้ไฟล์โมเดลเดียวกันแต่รันด้วยสคริปต์ Python อย่าง eval_pc.py ไม่ใช่โค้ด MicroPython นี้:

จอ emulator ที่รันได้จริง — หน้าเมนู Edge AI ของ BENTO Emulator (dropdown, Load/Stop, แถบคะแนน) ซึ่ง s20_capstone.py ใช้องค์ประกอบแบบเดียวกัน แล้วเพิ่มแบนเนอร์ ALERT กับตัวนับ
สเปกตรัม MCU → Cortex-A → Web คือธีมของทั้งคอร์ส: เราฝึกโมเดลครั้งเดียว รันได้ทุกเป้าหมาย ส่วนแอป MicroPython นี้รันได้บน Emulator กับบอร์ด ภาพนี้คือฝั่ง Web — ซ้อมที่บ้านให้ชิน แล้วเอา
s20_capstone.pyไฟล์เดิมไปลงบอร์ดจริงได้เลย
บนบอร์ดจริงพิสูจน์กับของจริง เซนเซอร์จริง NPU จริง:
s20_capstone.py ใน BENTO IDE กด Program to Devicelatency จริงของ NPU (ฉบับเต็ม)HITS_NEEDED / EMA_ALPHA แล้วสังเกตว่า "ไวขึ้น/เตือนมั่วขึ้น" อย่างไรจูนค่าออกแบบบนของจริงคือหัวใจ capstone — จดค่าที่คุณเลือกและ เหตุผล ลงบันทึกการเรียน นั่นคือหลักฐานการตัดสินใจเชิงวิศวกรรม
Guardian คือฐาน ทีมที่อยากไปไกลกว่า MVP มีสี่ทิศให้ต่อ (แต่ละทิศคือทั้งบล็อกของคอร์ส):
.tflite จากบทเรียน 5.3–5.9 มาแทนโมเดลสำเร็จรูป → Guardian เฝ้า "คลาสของคุณเอง"mag (DAQ) กับ verdict: เตือนเฉพาะตอนอุปกรณ์นิ่ง / มีคนอยู่ (เรดาร์) → ลด false positiveaction = publish MQTT (บทเรียน 6.5–6.6) แทนเสียง → เหตุการณ์ Edge วิ่งไปแดชบอร์ดทิศทางวิจัย: on-device learning, personalization ต่อผู้ใช้, การประเมิน false-positive rate จริงในสนาม — capstone ที่ดีจะ "ตั้งคำถามวิจัยหนึ่งข้อ" ไว้ท้ายรายงาน
อยากต่อยอด capstone หรือหาไอเดียโปรเจกต์ tinyML เพิ่ม เริ่มจากแหล่งเหล่านี้ได้เลย:
วิดีโอ (ช่องการศึกษาที่น่าเชื่อถือ)
ภาพ/เอกสารอ้างอิง (เปิดอ่านฟรี)
วิดีโอ/ภาพภายนอกเป็นของเจ้าของต้นฉบับ ใช้เพื่อการศึกษา อ้างอิงลิงก์ต้นทาง — เปิดดูจากลิงก์โดยตรง ไม่ได้ฝังไว้ในสไลด์
MVP ของบทเรียน 8.1–8.2 (เกณฑ์ผ่านของชุดบทเรียน): คุณส่งมอบ Guardian ที่ทำงาน ครบ ≥3 เสา (DAQ + Processing + Apps) — เลือกโมเดล เฝ้าเหตุการณ์เป้าหมาย ผ่านชั้นตัดสินใจ (conf กรอง + debounce) แล้ว action ยิงจริง พร้อม อธิบายการออกแบบ ได้
CONF_FLOOR/HITS_NEEDED/EMA_ALPHA เท่านั้น"ส่งมอบได้" ไม่ใช่แค่ "รันผ่าน" — ต้องเดโมให้คนอื่นดู เล่าเหตุผลการออกแบบ และชี้ได้ว่าจะต่อยอดทิศไหน
ถ้าติด ไต่บันไดนี้ทีละขั้น อย่าเพิ่งกระโดดไปดูเฉลย ของจะเข้าหัวตอนที่คุณพยายามเองก่อน:
# เติม: ทั้ง 5 จุดในไฟล์ฝึก + ตารางเสา/จุด/คำสั่งหน้าที่แล้วs20_capstone.py มีโครงครบทั้งไฟล์ เหลือ 5 บรรทัดกระดูกสันหลังให้เติมs20_capstone.py เติมครบพร้อมคอมเมนต์อธิบายทุกเสา (อ่านให้เข้าใจ ปิดไฟล์ แล้วประกอบเอง)s20_capstone_full.py ฉบับขัดเรียบร้อย: เลือกโมเดลสดจาก dropdown + latency + reset ตัวกรอง + นับ alertcapstone มีขั้นที่ห้าที่เฉลยไม่ได้ให้: การออกแบบของทีม — เฉลยให้แค่โครง Guardian ส่วน "เฝ้าอะไร action อะไร" เป็นของคุณ
capstone ไม่ได้สอนของใหม่ มันเรียก "ของเก่าที่เข้าใจแล้ว" กลับมาพร้อมกัน:
ฝั่งเสาข้อมูล
sensors.bmi270.acceleration() อ่านบริบทดิบdsp.EMA กรองความมั่นใจให้ตัดสินใจนิ่งedge_ai verdict → debounce → actionฝั่งวิศวกรรม/โครงโปรแกรม
ui.poll (จากบทเรียน 1.4–1.5)try/except OSError — จากบทเรียน 1.1–1.3finally: edge_ai.stop() คืนเครื่องสู่สถานะที่รู้แน่พลังของ capstone: คุณเห็นว่าทุกบทเรียนไม่ได้แยกกัน มันคือชิ้นส่วนของผลิตภัณฑ์เดียว — และตอนนี้คุณต่อมันเป็นแล้ว
โครง "เฝ้า → กรอง → สั่งการ" ที่สร้างวันนี้ คือแก่นของสินค้า Edge AI จริงหลายหมวด:
โครงเดียวกันหมด ต่างแค่ "จูนเกณฑ์ให้เข้ากับต้นทุนของการพลาด" — capstone ฝึกให้คุณคิดเรื่องนี้เป็น ไม่ใช่แค่เขียนโค้ดให้รันได้
งานทำเอง (ท้ายบทเรียนและท้ายหลักสูตร):
s20_capstone.py ให้ครบทั้ง 5 ช่อง รันได้จริง (Emulator หรือบอร์ด)CONF_FLOOR/HITS_NEEDED/EMA_ALPHA แล้ว เขียนเหตุผล ลงบันทึกการเรียนใบ้ข้อ 3 — เตรียม "เคสหลอก" ไว้ล่วงหน้า (ท่า/เสียงก้ำกึ่ง) เพื่อพิสูจน์ว่า debounce ทำงาน นั่นคือหลักฐานว่า Guardian เป็นผลิตภัณฑ์ ไม่ใช่เดโม
ทั้งคอร์สเราได้: เดินครบ 5 เสาของวงจรชีวิตข้อมูล · ฝึกโมเดลเอง · รันข้ามเป้าหมาย (MCU/Web/PC) · และวันนี้ ร้อยทุกอย่างเป็นผลิตภัณฑ์เดียวที่ส่งมอบได้
ขอบคุณที่เดินมาจนจบคอร์สครับ จากบทเรียนแรกที่เมนู 6 โมเดลเป็นกล่องดำ วันนี้คุณเปิดกล่องได้ทุกชั้นและประกอบกล่องของตัวเองเป็นแล้ว — เอา Guardian ตัวนี้ไปต่อยอดเป็นของจริงได้เลย