ทั้งไฟล์อ่านเป็นประโยคเดียว: "หาโมเดลจากชื่อ → สั่งรัน → วนอ่านผลขึ้นจอ → พอเจอคลาสเป้าหมายมั่นใจพอ ก็สั่งการ → หยุดตอนออก"
ตัวเลขช่อง (1–4) ชี้จุดที่คุณต้องเติมในไฟล์ฝึก — เหมือนบทเรียน 1.1–1.3 แต่ช่องที่ 4 เปลี่ยนจาก
stop()มาเป็นfire_action()ซึ่งคือหัวใจใหม่ของชุดบทเรียนนี้
ช่องเติมที่ 1: หาโมเดลจากชื่อ (ให้ไว้แล้ว) แล้วสั่งให้ CM55 เริ่มรัน:
model = find_model(MODEL_KEYWORD) # ให้ไว้แล้ว: คืน dict ทั้งก้อน
labels = model['labels']
try:
# เติม: สั่งให้ CM55 รันโมเดลนี้ ด้วย edge_ai.select(model['index'])
pass
lcd.console('<span class=ok> เริ่มอนุมาน…</span>')
except OSError as e:
lcd.console('<span class=error> โหลดไม่สำเร็จ: %s</span>' % e)
pass ด้วย edge_ai.select(model['index']) — เอา index จาก dict ไปสั่งtry เพราะ select() โยน OSError ได้ (ข้ามคอร์อาจพลาด — เหมือนบทเรียน 1.1–1.3)--- ตลอด เพราะไม่มีโมเดลรัน result() คืน None
MODEL_KEYWORDอยู่บนหัวไฟล์ — remix ได้ทันที เปลี่ยนเป็น"Cough"แอปก็กลายเป็นตัวจับเสียงไอ โดยไม่แตะ logic ข้างล่างเลย
ช่องเติมที่ 2 และ 3: จังหวะ 2 เดิมจากบทเรียน 1.1–1.3 อ่าน verdict แล้วเอาคลาสที่ชนะขึ้นจอ:
# เติม: อ่านผลอนุมานล่าสุดมาเก็บใน r -> r = edge_ai.result()
r = None
pass
if r and r['seq'] != last_seq: # มีผลใหม่จริงไหม (seq เปลี่ยน)
last_seq = r['seq']
# เติม: แสดงคลาสที่ชนะ ด้วย verdict.text(r['label'] or '-')
pass
conf.text("conf: %.0f %%" % (r['conf'] * 100))
top = r['top']
for i, (lb, br) in enumerate(rows):
if i < len(r['scores']):
br.value(int(r['scores'][i] * 100))
br.color(GREEN if i == top else DIM)
r = edge_ai.result() · ช่อง 3: verdict.text(r['label'] or '-')seq ก่อนเสมอ — วาดจอเฉพาะตอนมีผลใหม่ (เหตุผลเดียวกับบทเรียน 1.1–1.3)สองช่องนี้เป็น "ของเดิม" ที่คุณทำเป็นแล้วจากบทเรียน 1.1–1.3 — วางไว้ให้ทวน จังหวะที่ 3 ต่างหากคือของใหม่จริงๆ ที่ต้องโฟกัส
ช่องเติมที่ 4: จังหวะ 3 (ของใหม่) — พอวาดจอเสร็จ เช็กว่าเข้าเงื่อนไขไหม ถ้าใช่ก็สั่งการ:
hit = (r['label'] == TARGET_CLASS
and r['conf'] >= edge_ai.CONF_FLOOR) # label ตรง + มั่นใจพอ
if hit and not fired:
# เติม: สั่งการเมื่อจับ TARGET ได้ครั้งแรก -> fire_action(r['conf'])
pass
fired = True
elif not hit:
fired = False # ออกจากคลาสแล้ว รีเซ็ต
banner.text("รอจับ %s ..." % TARGET_CLASS)
banner.color(RED)
pass ด้วย fire_action(r['conf']) — ส่ง conf เข้าไปให้ action โชว์and not fired = ยิงครั้งเดียวต่อการเจอ (edge-trigger) ไม่บี๊บรัวนี่คือบรรทัดที่ทำให้แอปชุดบทเรียนนี้ต่างจากบทเรียน 1.1–1.3 — verdict กลายเป็น action ตรงจุดนี้เป๊ะ เติมเสร็จเมื่อไร แอปของคุณ "ทำงาน" ไม่ใช่แค่ "รายงาน"
ปุ่ม back และการเก็บกวาดตอนออก (ให้ไว้แล้ว — เหมือนบทเรียน 1.1–1.3):
finally:
edge_ai.stop() # ให้ไว้แล้ว: ออกยังไงก็หยุดเครื่องยนต์เสมอ
lcd.console('<span class=ok> จบการทำงาน</span>')
finally ให้ไว้แล้ว: ไม่ว่าจะออกด้วยปุ่ม back หรือ error โมเดลจะถูกหยุดเสมอon_result ต้องถอน callback ด้วย: edge_ai.on_result(None) ก่อน stop()นิสัย embedded เดิม: ออกจากงานยังไง ทิ้งเครื่องไว้ให้เรียบร้อยแบบนั้น — หยุดโมเดล ถอน callback ที่ต่อไว้ ไม่ปล่อยอะไรค้างหลังโปรแกรมจบ
หัวใจของ MVP วันนี้คือ remix — และจุด remix แรกอยู่บนหัวไฟล์แค่สองบรรทัด:
MODEL_KEYWORD = "Motion" # → "Baby Cry" / "Cough" / "Siren" / "Push"
TARGET_CLASS = "shaking" # → คลาสของโมเดลใหม่ (ดูจาก labels ในคอนโซล)
MODEL_KEYWORD = สลับทั้งโมเดลและเซนเซอร์ (IMU → MIC → RADAR) โดยไม่แตะ logicTARGET_CLASS = เปลี่ยนว่า "จับอะไรแล้วสั่งการ" — ต้องเป็นชื่อจาก labels ของโมเดลนั้นเป๊ะMODEL_KEYWORD = "Cough", TARGET_CLASS = "cough"อยากรู้ว่าโมเดลใหม่มีคลาสอะไร? รันแล้วดูบรรทัด
โมเดล: ... คลาส: ...ในคอนโซล หรือถาม REPL:edge_ai.models()— ถามฮาร์ดแวร์ก่อนเสมอ
จุด remix ที่สองคือ การกระทำ — แก้แค่ใน fire_action() ที่เดียว logic ตรวจจับไม่ต้องแตะ:
ui.tone(60, ...) (โดกลาง) แทน 72 หรือใช้ ui.sfx(ui.SFX_UI_SELECT) เล่นเสียงสำเร็จรูปconf สูงมากบี๊บสองครั้ง ถ้าพอผ่านเกณฑ์บี๊บครั้งเดียวเพราะเราแยก "ตัดสินใจ" ออกจาก "ลงมือ" การ remix action จึงปลอดภัย — คุณเปลี่ยนสิ่งที่แอป ทำ ได้ โดยไม่กระทบสิ่งที่แอป ตรวจจับ
เปิด s03_anatomy_edgeai.py ในไฟล์มี pass วางไว้ 4 จุด ตรงที่ต้องเติมคำสั่งจริง:
| # | จุด | เติมด้วย | ถ้าลืม |
|---|---|---|---|
| 1 | หลัง find_model | edge_ai.select(model['index']) |
จอค้าง --- ไม่มีผล |
| 2 | ในลูป | r = edge_ai.result() |
จอไม่ขึ้นคลาสเลย |
| 3 | มีผลใหม่ | verdict.text(r['label'] or '-') |
แถบขยับ แต่ตัวใหญ่ไม่เปลี่ยน |
| 4 | เข้าเงื่อนไข hit | fire_action(r['conf']) |
เจอคลาสถูก แต่ไม่บี๊บ ไม่มีแบนเนอร์ |
ขั้นตอน:
MODEL_KEYWORD + TARGET_CLASS ที่อยากลอง (เริ่มจาก Motion/shaking ก็ได้)# เติม: ทีละจุด แล้วแทน pass ด้วยคำสั่งตามคำใบ้ช่อง 1–3 คือของเดิมจากบทเรียน 1.1–1.3 (แค่ทวน) ช่อง 4 คือของใหม่ — เติมครบเมื่อไร คุณได้แอป Edge AI ที่ "ลงมือทำ" ตัวแรกของตัวเอง
อยากเข้าใจ softmax/argmax ให้ลึกกว่าในบทเรียน ลองดูสื่อคุณภาพเหล่านี้ (ลิงก์ไปต้นทาง ไม่ได้ฝังวิดีโอไว้ในสไลด์):
วิดีโอ
เอกสาร / ภาพอ้างอิง
วิดีโอ/ภาพภายนอกเป็นของเจ้าของต้นฉบับ ใช้เพื่อการศึกษา อ้างอิงลิงก์ต้นทาง
MVP ของบทเรียน 1.6–1.7 (เกณฑ์ผ่านของชุดบทเรียน): คุณ remix s03_anatomy_edgeai.py ได้จริง — สลับโมเดล (เปลี่ยน MODEL_KEYWORD/TARGET_CLASS) + สั่งการเมื่อเจอ verdict ที่เข้าเงื่อนไข
label และ conf >= CONF_FLOOR และทำไมต้องมี fired"สั่งการได้" ไม่ใช่แค่ "เห็นแบนเนอร์" — คุณต้องบอกได้ว่าแอปนี้ต่างจากบทเรียน 1.1–1.3 ตรงไหน (จังหวะ action) และ remix ของคุณเปลี่ยนอะไรไปจากต้นฉบับ
ถ้าติด ให้ไต่บันไดนี้ทีละขั้น อย่าเพิ่งกระโดดไปดูเฉลย เพราะของจะเข้าหัวตอนที่คุณพยายามเองก่อน:
# เติม: ทั้ง 4 จุดในไฟล์ฝึก + ตารางหน้าที่แล้ว บอกว่าแต่ละช่องเติมอะไรs03_anatomy_edgeai.py มีโครงครบทั้งไฟล์แล้ว เหลือแค่ 4 บรรทัดให้เติมs03_anatomy_edgeai.py เติมครบพร้อมคอมเมนต์อธิบายทุกช่อง (อ่านให้เข้าใจ ปิดไฟล์ แล้วพิมพ์เอง)s03_anatomy_edgeai_full.py ยกไปใช้ on_result + แยกสี CONF_FLOOR + นับจำนวน action + latencyลองเขียนเองให้สุดก่อนนะ ถ้าติดจริงๆ ค่อยเปิดเฉลยดูทีละช่อง แล้วกลับมาพิมพ์เอง — เดี๋ยวเราค่อย ๆ แกะไปด้วยกัน
การ remix แอป Edge AI ตัวเดียวซ่อนแนวคิดที่จะใช้ไปตลอด โมดูล 6 (Apps):
ฝั่ง Edge AI / ระบบ
find_model() ไม่ hard-code index (ทนต่อการเปลี่ยนเฟิร์มแวร์)label + conf >= CONF_FLOOR ไม่ใช่ป้ายคลาสเดียวๆon_result(cb) เฟิร์มแวร์เรียก cb ให้ตอนคลาสเปลี่ยน (แทน poll เอง)ฝั่ง MicroPython / โครงโปรแกรม
hit แยกจาก fire_action() remix ง่ายfired ยิง action ครั้งเดียวต่อการเจอ ไม่รัวfinally: stop() (+ on_result(None) ในฉบับเต็ม)ทั้งหมดยังยืนบนคำสั่งเดิมของ
edge_ai— ชุดบทเรียนนี้ไม่ได้เพิ่มของยาก แต่สอน "ประกอบ" คำสั่งเดิมให้กลายเป็นแอปที่ลงมือทำได้
pattern "จับคลาสเป้าหมาย แล้วสั่งการ" ที่เราทำวันนี้ คือแก่นของสินค้า Edge AI จริงทุกตัว:
สังเกตว่าทุกสินค้าใช้ pattern เดียวกับแอปชุดบทเรียนนี้เป๊ะ — ต่างกันแค่ action ปลายทาง เราแค่กำลังเริ่มจากปลายทางเพื่อย้อนไปสร้างเองได้
งานทำเอง (ท้ายบทเรียน):
s03_anatomy_edgeai.py ให้ครบทั้ง 4 ช่อง รันได้จริง (Emulator หรือบอร์ด)MODEL_KEYWORD + TARGET_CLASS เป็นโมเดลอื่น (เช่น Motion → Cough) ยืนยัน action ยิงตามคลาสใหม่ใบ้ข้อ 3 — เงื่อนไข hit เช็กทั้ง label และ conf ถ้าคลาสถูกแต่มั่นใจไม่ถึงเกณฑ์ hit เป็น False action จึงไม่ยิง (นี่คือตัวกัน false positive)
วันนี้เราได้: แกะกายวิภาคแอป Edge AI เป็น 3 จังหวะ (select→result→action) · เลือกโมเดลจากชื่อ · เพิ่ม action บน verdict ด้วยเงื่อนไข label+conf · รู้จัก on_result · remix เป็นแอปของตัวเอง
ชุดบทเรียนถัดไป (บทเรียน 2.1–2.2) เราปิดกล่อง Onboarding แล้วเปิด Pillar 1 — DAQ: เริ่มเก็บข้อมูลเซนเซอร์ของเราเองลงไฟล์ CSV เพื่อเป็นวัตถุดิบฝึกโมเดลในบล็อกถัดๆ ไป เจอกันครับ