ในชิปตัวเดียวกันมีซีพียูสองตัวที่ทำงานคนละแบบ
ใครอ่านเซนเซอร์ตัวไหน ต่างกันระหว่างสองบอร์ด: บน Eva Kit CM55 เป็นเจ้าของบัสเซนเซอร์ทั้งหมด (IMU แผ่นสัมผัส ลูกบิด) Python จึงต้องขอค่าผ่าน IPC และ sensors.init() ถูกปฏิเสธ · บน Dev Kit CM33 อ่าน IMU/เข็มทิศเองได้ (sensors.init() ทำงาน) ส่วนแผ่นสัมผัสกับลูกบิดยังอ่านผ่าน CM55 เหมือนกัน — sensors.snapshot() ซ่อนความต่างนี้ให้ คืน dict รูปเดียวกันทั้งสองบอร์ด
โค้ด Python ของเราอยู่ฝั่ง CM33 เสมอ อยากให้อะไรขึ้นจอ ต้อง ฝากข้อความข้ามไปให้ CM55 วาด
IoT = อุปกรณ์มีเซนเซอร์ + ต่อเน็ต ส่งข้อมูลขึ้นระบบกลาง
AIoT = ย้าย การตัดสินใจ ลงมาไว้ที่ตัวอุปกรณ์เอง ไม่ต้องรอถามคลาวด์ทุกครั้ง
ตัวอย่างที่จับต้องได้: เครื่องจักรตัวหนึ่งสั่นผิดปกติ

เทอร์โมสตัทสัมผัสในบ้านจริงตัวนี้ทำครบวงในกล่องเดียว — วัดอุณหภูมิ ตัดสินว่าร้อนไปหรือเย็นไป แล้วสั่งคอมเพรสเซอร์ทำงาน ลองชี้ให้ได้ว่าสามหน้าที่นั้นอยู่ตรงไหนของกล่องนี้
และนี่คือรูปร่างของไฟล์ที่ 8 กับ 9 ที่เพิ่งรันไปเป๊ะ ๆ — วัดค่า ตัดระดับ แล้วรายงาน
โรงงาน — Predictive Maintenance
มอเตอร์ปั๊มน้ำมีเซนเซอร์ความสั่นติดอยู่ ระบบบนตัวมันรู้ว่า "เสียงสั่นปกติ" หน้าตาแบบไหน พอลูกปืนเริ่มสึก รูปแบบการสั่นเปลี่ยนก่อนพัง 2-3 สัปดาห์ ระบบแจ้งซ่อมล่วงหน้า แทนที่จะรอสายพานหยุดกลางกะ
อาคาร — Smart Building
เซนเซอร์ในห้องประชุมนับคนจากความเคลื่อนไหวและเสียง แล้วสั่งแอร์ให้แรงตามจำนวนคนจริง ไม่ใช่ตั้งไว้ 22 องศาทั้งวัน ค่าไฟลดได้ 20-30% โดยไม่มีใครต้องกดสวิตช์
สุขภาพ — Fall Detection
อุปกรณ์ติดตัวผู้สูงอายุ แยกให้ออกระหว่าง "นั่งลงเร็ว" กับ "ล้ม" — สองอย่างนี้กราฟความเร่งคล้ายกันมาก ค่าเดียวที่จุดเดียวแยกไม่ออก ต้องดูรูปร่างของสัญญาณทั้งช่วง



ทั้งสามเคสนี้ ตัวเซนเซอร์กับตัวตัดสินใจอยู่ที่เดียวกัน — นั่นแหละ AIoT

| ของบนบอร์ด | มันวัด/ทำอะไร | เจอในเมนูไหน · ใช้เองบทเรียนไหน |
|---|---|---|
| BMI270 | ความเร่ง 3 แกน + การหมุน 3 แกน (ทั้งสองบอร์ด) | Home, Dashboard, Smart Watch · เราใช้เองบทเรียน 3.1–3.6 |
| BMM350 | สนามแม่เหล็กโลก → ทิศเหนือ (ทั้งสองบอร์ด) | Dashboard (เข็มทิศ) · บทเรียน 3.7–3.9 |
| CapSense | แผ่นสัมผัส — Eva: ปุ่มสัมผัส 2 ปุ่ม + แถบเลื่อน (5 อิเล็กโทรด อ่านเป็นค่าเดียว 0–100) · Dev Kit: ดูตำแหน่งที่บอร์ดของทีม | Home (Eva: Controls ด้วย) · บทเรียน 2.7–2.9 |
| Potentiometer | ลูกบิดหมุน → ค่าอนาล็อก — Eva: ลูกบิดสีน้ำเงิน 1 ตัว · Dev Kit: VR1–VR4 (sensors.pot อ่าน VR1) |
Home (Eva: Controls ด้วย) · บทเรียน 2.7–2.9 |
| LED + ปุ่มผู้ใช้ | LED — Eva 3 ดวง · Dev Kit 5 ดวง (ถาม gpio.num_leds() อย่าจำเลข) · ปุ่มที่ Python ใช้ได้ 1 ปุ่ม เรียกด้วยชื่อจาก gpio.button(0).name() ไม่ใช่ป้ายบนแผ่นวงจร |
Eva: Controls · บทเรียน 2.1–2.3 |
| ไมโครโฟน PDM | เสียงรอบตัว | ยังไม่มีเมนูของตัวเอง · บทเรียน 3.7–3.9 ใช้ผ่านโมดูล mic |
| WiFi/BT (Eva: CYW55513IUBG) | Wi-Fi + Bluetooth ใช้วิทยุร่วมกัน (Eva: Wi-Fi 6 2.4/5 GHz + Bluetooth 5.4) | Wi-Fi Setting · ชุดบทเรียนถัดไปเราต่อเอง |
| จอสัมผัส 4.3" | หน้าต่างของทุกอย่าง — พื้นที่วาด 792×398 เท่ากันทั้งสองบอร์ด | ทุกเมนู · วันนี้เลย |
| เฉพาะ Dev Kit | SHT40 (อุณหภูมิ/ความชื้น) · DPS368 (ความกดอากาศ) · เรดาร์ · RGB dot matrix · CAN · ปุ่มเสริมสองปุ่ม (import buttons) |
Home (แถว Temp / Humid) · บทเรียน 4.1–5.3 ใช้ SHT40 เมื่อบอร์ดมี |
จำตารางนี้ไว้ — คอลัมน์ขวาคือแผนที่ของทั้งหลักสูตร เราจะไล่หยิบของในตารางนี้มาสั่งงานเองทีละตัว · ตัวเลขที่ต่างกันระหว่างสองบอร์ด (จำนวน LED, จำนวนลูกบิด) ให้ถามบอร์ดด้วยโค้ดเสมอ ไม่ต้องจำ
สี่อย่างนี้เป็นงานของผู้สอน ไม่ใช่ของผู้เรียน ตรวจให้ครบก่อนเริ่ม แล้วบทเรียนจะเดินได้ตลอดชุดบทเรียนโดยไม่สะดุด · ข้อที่สามตรวจเหมือนกันทั้งสองบอร์ด: แตะแผ่นสัมผัสแล้วแถว Touch บนหน้า Home ต้องเปลี่ยน — ถ้าไม่เปลี่ยน สาเหตุที่ต้องสงสัยก่อนคือชิป CapSense ยังไม่ถูก flash ซึ่งเกิดได้กับทั้งสองบอร์ด เพราะแผ่นสัมผัสของทั้งคู่ต่อกับชิป PSoC 4000T แยกต่างหาก ที่ต้องโปรแกรมคนละรอบกับตัวบอร์ดหลัก · ข้อที่สี่มีเฉพาะ Eva Kit เพราะ Dev Kit ไม่มีการ์ด Audio Player
ข้อที่พลาดบ่อยที่สุดคือชิป CapSense — มันเป็นชิปแยกที่ต้องโปรแกรมต่างหากจากตัวบอร์ดหลัก ทั้งสองบอร์ดเหมือนกัน
ทีมสาธิตการใช้ 5 เมนูพร้อมอธิบายว่าเมนูใดใช้เซนเซอร์ใด + รัน lcd.print() ข้อความของทีมขึ้นจอสำเร็จ
แปลเป็นสิ่งที่ตรวจได้จริง:
<h2> ของชุดบทเรียนนี้09_your_level_rule.py ผ่านครบหกแถว (เขียวหมด)ไม่มีข้อไหนต้องใช้โค้ดเกินสามสิบบรรทัด — ชุดบทเรียนนี้วัดความเข้าใจ ไม่ใช่ปริมาณ
| อาการ | สาเหตุที่แท้จริง | วิธีแก้ |
|---|---|---|
| อยู่หน้า Playground แล้ว แต่พื้นที่แสดงผลว่าง มีจุดแดงเล็ก ๆ ที่ปุ่มไอคอนมุมขวาล่าง | หน้านี้เปิดมาที่โหมด UI ข้อความ lcd ถูกพักไว้ |
แตะปุ่มไอคอนสีเขียวมุมขวาล่าง เพื่อสลับเป็นโหมดข้อความ |
สร้าง ui.Label แล้วจอนิ่งไปราวสองวินาที |
ยังไม่ได้เคาะ ui.poll() |
เติม ui.poll() หนึ่งครั้งหลังสร้าง/แก้ widget |
ป้ายบนจอขึ้นคำว่า Label ที่เราไม่ได้พิมพ์ |
สร้าง ui.Label ด้วยข้อความว่าง |
ตั้งข้อความเริ่มต้นให้มันเสมอ |
| ส่งโค้ดแล้วเงียบสนิท ไม่มีแม้แต่จุดแดง | โค้ดยังไม่ถึงบอร์ด หรือสคริปต์ error ก่อนถึงบรรทัด lcd |
ดู error ที่คอนโซล IDE แล้วส่งใหม่ |
| ข้อความไปโผล่ที่คอนโซลคอมแทน | ใช้ print() แทน lcd.print() |
เปลี่ยนเป็น lcd.print() |
| ตัวอักษรโตผิดปกติเฉพาะบรรทัดนั้น | ลืมปิดแท็ก </h2> |
ตรวจว่าแท็กเปิด-ปิดครบคู่ |
| ข้อความยาวถูกตัดหาย แถวถัดไปต่อท้ายมาเลย | เกิน 127 ไบต์/ครั้ง (ไทย ≈ 42 ตัวอักษร) — ตัดแล้ว \n หายด้วย |
แบ่งเป็นหลาย lcd.print() หรือใช้ท่าของไฟล์ 06 |
เรียก seg.value(12) แล้วได้ 12 ไม่ใช่ 12.0 |
.value() ส่งได้แต่จำนวนเต็ม |
ใช้ seg.text("12.0") |
| หน้า Audio Player ว่างเปล่า (Eva Kit) | บอร์ดไม่ได้เสียบ SD card | ไม่ใช่ความผิดพลาด ข้ามไปเมนูอื่น |
| หาการ์ด Controls / Audio Player / TESAIoT Connect ไม่เจอ | ถือ Dev Kit อยู่ — build ของคอร์สไม่มีสามการ์ดนี้ | ไม่ใช่ความผิดพลาด เกณฑ์ผ่านใช้เฉพาะเมนูที่มีทั้งสองบอร์ด |
| แตะการ์ดแล้วจอค้างแวบหนึ่ง | บางหน้าใช้เวลาสร้างครั้งแรก | รอสองวินาที อย่ารัวแตะซ้ำ |
เกือบทุกข้อในตารางนี้ ไม่ใช่ความผิดของโค้ด แต่เป็นความไม่รู้ลำดับขั้นตอน
เปิด s01_hello_lcd.py มีช่องว่างให้เติม 7 จุด (ท่าที่ 4 แยกเป็นสองบรรทัดเพราะเรื่อง 127 ไบต์)
# เติม: lcd.clear()
pass
# เติม: lcd.console("<h2>AIoT in Action - ชุด 1</h2>")
pass
for i in range(len(MEMBERS)):
# เติม: lcd.print("สมาชิกคนที่", i + 1, ":", MEMBERS[i])
pass
# เติม: time.sleep_ms(800)
pass
ทำสามขั้น: หนึ่ง แก้ข้อมูลทีมสามบรรทัดบนสุด สอง เติมทีละจุดแล้วส่งขึ้นบอร์ดทุกครั้ง สาม ครบแล้วลองเพิ่มบรรทัดของตัวเอง
อย่าเติมครบเจ็ดจุดแล้วค่อยรันทีเดียว — เติมทีละจุดแล้วรัน จะรู้ทันทีว่าจุดไหนพัง
s01_hello_lcd.py — ส่วนที่หนึ่งอ่านให้เข้าใจ แล้วพิมพ์เอง อย่าคัดลอกวาง การพิมพ์เองคือตอนที่มือกับสมองจำโครงสร้างได้
# s01_hello_lcd.py - ข้อความแรกของทีม ขึ้นจอบอร์ด
import lcd
import time
import ui
TEAM_NAME = "BentoBuilders"
MEMBERS = ["สมชาย", "สมหญิง", "สมศรี"]
MOTTO = "เล่นของจริงก่อน แล้วค่อยแกะ"
import lcd ต้องมาก่อนใช้งานเสมอ ส่วน import time เอาไว้ใช้ sleep_ms() ในท่าที่ 3 และ import ui เอาไว้วางป้ายลงหน้าจอในท่าที่ 5
การประกาศข้อมูลทีมไว้บนสุดแยกจากโค้ดข้างล่าง ทำให้คนที่มาอ่านทีหลังแก้ข้อมูลได้โดยไม่ต้องเข้าใจตรรกะทั้งไฟล์
การวางค่าที่ต้องแก้บ่อยไว้บนสุด เป็นมารยาทที่ดีต่อคนอ่านคนถัดไป (ซึ่งมักคือตัวเราเองในอีกสองสัปดาห์)
lcd.clear()
lcd.console("<h2>AIoT in Action - ชุด 1</h2>")
lcd.console("<span class=muted>ทดสอบจอครั้งแรกของทีม " + TEAM_NAME + "</span>")
lcd.print("สวัสดีจากทีม", TEAM_NAME)
lcd.print("คำขวัญของเรา:", MOTTO)
print("ส่งข้อความทักทายขึ้นจอบอร์ดแล้ว ดูที่จอ ไม่ใช่ที่หน้าคอม")
สังเกตความต่างสองแบบของการประกอบข้อความ: บรรทัด <span class=muted> ใช้ + เพราะต้องแทรกชื่อทีม ไว้กลางแท็ก ส่วน lcd.print("สวัสดีจากทีม", TEAM_NAME) ใช้จุลภาคเพราะไม่มีแท็กมาเกี่ยว
ถ้าใช้จุลภาคกับแท็ก จะได้ <span class=muted> ทีม </span> ที่มีช่องว่างเกินติดขอบแท็ก
ทำไมต้อง lcd.clear() ก่อนเสมอ — ลิ้นชักอาจมีข้อความจากโปรแกรมที่รันก่อนหน้าค้างอยู่ การเริ่มจากสถานะที่เรารู้แน่นอน เป็นนิสัยของงาน embedded จริง ไม่ใช่แค่ความเรียบร้อย
เลือกวิธีต่อสตริงตามว่า "มีแท็กมาเกี่ยวไหม" ไม่ใช่ตามความเคยชิน
for i in range(len(MEMBERS)):
lcd.print("สมาชิกคนที่", i + 1, ":", MEMBERS[i])
time.sleep_ms(800)
TAIL = "ทีม " + TEAM_NAME + " พร้อมลุยชุดต่อไป"
lcd.print("<span class=ok>ขึ้นจอสำเร็จ</span>")
lcd.print("<span class=ok>" + TAIL + "</span>")
range(len(MEMBERS)) ให้ตัวเลข 0, 1, 2 ตามจำนวนสมาชิกจริง — ถ้าทีมมีสองคน ลูปจะวนสองรอบเอง ไม่ต้องแก้อะไร ข้อมูลเป็นตัวขับการแสดงผล
การหน่วง 800 ms อยู่ ในลูป ไม่ใช่นอกลูป ถ้าย้ายออกไปข้างนอก ชื่อทุกคนจะขึ้นพร้อมกันแล้วค่อยหน่วงครั้งเดียว — ลองย้ายดูแล้วสังเกตความต่าง จะเข้าใจเรื่อง indent ในภาษา Python ทันที
บรรทัดปิดท้ายแยกเป็นสอง lcd.print() ตั้งแต่ต้น เพราะรวมกันแล้วเสี่ยงเกิน 127 ไบต์ถ้าชื่อทีมยาว ประโยคปิดท้ายถูกยกออกมาเก็บไว้ในตัวแปร TAIL เพราะท่าที่ 5 ต้องเอาความยาวของมันไปวัด
ใน Python การเยื้องบรรทัดคือความหมาย ไม่ใช่แค่ความสวยงาม
lcd ทำแทนไม่ได้ui.screen()
time.sleep_ms(200)
COL_TEXT, COL_DIM = 0xE8EAED, 0x9AA3AF
COL_CARD, COL_OK, COL_RUN = 0x171B22, 0x30A46C, 0x4A9EFF
BYTE_LIMIT = 127
ui.Panel(x=16, y=8, w=760, h=372, color=COL_CARD, min=COL_DIM, max=12, value=1)
ui.Label("ป้ายประจำทีม", x=32, y=16, color=COL_DIM, value=20)
ui.Label(TEAM_NAME, x=32, y=40, color=COL_TEXT, value=28)
ui.Label(MOTTO, x=32, y=84, color=COL_DIM, value=20)
tbl = ui.Table(x=32, y=116, w=340, h=252, cols=2)
tbl.col_width(0, 100)
tbl.col_width(1, 230)
tbl.add_row("ลำดับ", "ชื่อสมาชิก")
ui.Label("สถานะการเขียนตาราง", x=400, y=116, color=COL_DIM, value=20)
led_run = ui.Led(x=408, y=144, w=48, h=48, color=COL_RUN, value=1)
ui.Label("กำลังเขียน", x=452, y=148, color=COL_DIM, value=20)
led_done = ui.Led(x=408, y=188, w=48, h=48, color=COL_OK, value=0)
ui.Label("เขียนครบแล้ว", x=452, y=192, color=COL_DIM, value=20)
for i in range(len(MEMBERS)):
tbl.add_row(str(i + 1), MEMBERS[i])
ui.poll()
time.sleep_ms(500)
led_run.value(0)
led_done.value(1)
ลูปนี้เดินรายชื่อ ชุดเดียวกัน กับท่าที่ 3 แต่ปลายทางคนละที่ — ท่าที่ 3 พิมพ์เข้าลิ้นชัก ท่านี้เขียนลงตารางบนจอ ข้อมูลชุดเดียวไปได้สองที่พร้อมกัน และนั่นคือสิ่งที่ชุดบทเรียนนี้อยากให้เห็น · ui.Table จัดคอลัมน์ให้เอง ถ้าเรียง ui.Label เองต้องนับพิกเซลทุกแถว พอชื่อยาวไม่เท่ากันคอลัมน์ที่สองจะเยื้องจนอ่านไม่ออก แถวหนึ่งสูงราว 62 พิกเซล หัวตารางบวกสมาชิกสามคนจึงต้องการ h=252
ไฟสองดวงบอกสถานะแทนการเปลี่ยนสีตัวอักษร เหตุผลอยู่ที่ การทดสอบขาวดำ — ถ่ายรูปจอแล้วแปลงเป็นเกรย์สเกล ไฟที่ติดกับไฟที่หรี่ยังแยกออกด้วยความสว่าง ส่วนตัวหนังสือสีเขียวกับสีเทากลายเป็นสีเดียวกัน · led_run.value(0) ทำให้ไฟ หรี่ ไม่ใช่หาย โดยตั้งใจ ไฟแผงควบคุมที่หายไปตอนดับ ทำให้คนดูแยกไม่ออกว่าดับจริงหรือจอเสีย
used = len(TAIL.encode())
ui.Label("ความยาวบรรทัดปิดท้าย จากเพดาน 127", x=400, y=240, color=COL_DIM, value=20)
ui.Bar(x=408, y=272, w=332, h=16, color=COL_OK, min=0, max=BYTE_LIMIT, value=used)
ui.Scale(x=408, y=288, w=332, h=44, color=COL_TEXT, min=0, max=BYTE_LIMIT)
ui.Label(str(used) + " ไบต์", x=408, y=336, color=COL_TEXT, value=20)
ui.poll()
เลข 72 ลอย ๆ ไม่บอกอะไรเลย เลข 72 ที่มีไม้บรรทัด 0–127 อยู่ใต้มันบอกทันทีว่าเหลือที่อีกเกินครึ่ง นี่คือกฎเดียวกับที่หน้าจอโรงงานใช้ — ค่าที่วัดได้ต้องมาพร้อมพิสัยหรือเกณฑ์ของมัน
ui.Scale ไม่รับ .value() มันคือไม้บรรทัด ตัวที่ขยับคือ ui.Bar ที่เราวางทับไว้ข้างบน (แบบวงกลมมีเข็มจริงผ่าน prop — บทเรียน 3.1–3.3 สอน) ลองเรียก .value(50) ใส่ Scale ดูก็ได้ แล้วจะเห็นว่าไม่มีอะไรเกิดขึ้น
ภาษาไทยตัวละ 3 ไบต์ บรรทัดที่ดูสั้นบนจอคอมจึงกินโควตาเร็วกว่าที่ตาประเมิน — มาตรวัดนี้ทำให้เรื่องนั้นมองเห็นได้แทนที่จะต้องจำ
ท่า 1 ล้างจอ + หัวเรื่อง มาก่อน เพราะต้องพิสูจน์ให้ได้ก่อนว่า "ช่องทางสื่อสารกับจอใช้ได้จริง" ถ้าท่านี้ไม่ขึ้น ท่าที่เหลือไม่มีประโยชน์ที่จะเขียนต่อ
ท่า 2 ข้อความคงที่ มาก่อนลูป เพราะการพิมพ์ค่าตายตัวง่ายกว่า และแยกได้ว่าปัญหาอยู่ที่ lcd หรืออยู่ที่ตรรกะของเรา
ท่า 3 ลูป มาหลังจากพิสูจน์สองข้อบนแล้ว ตอนนี้ถ้าพัง เรารู้แน่ว่าพังที่ลูป ไม่ใช่ที่จอ
ท่า 4 สถานะปิดท้าย มาก่อนป้าย เพราะมันคือ "สัญญาณว่าทุกอย่างข้างบนผ่านหมดแล้ว" โปรแกรมที่ดีต้องบอกให้รู้ว่า มันจบแล้ว และจบแบบสำเร็จ ไม่ใช่เงียบหายไปเฉย ๆ
ท่า 5 ป้ายบนหน้าจอ มาสุดท้าย เพราะมันคือของที่เหลือไว้ให้คนอื่นอ่าน หลังโปรแกรมจบและหลังลิ้นชักถูกปิดไปแล้ว สี่ท่าแรกคุยกับคนที่นั่งดูตอนรัน ท่านี้คุยกับคนที่เดินผ่านโต๊ะทีหลัง
นี่คือวิธีคิดแบบ ไล่จากง่ายไปยาก แล้วให้แต่ละขั้นยืนยันขั้นก่อนหน้า ซึ่งเป็นวิธีดีบักงาน embedded มาตรฐาน
ถ้าเขียนรวดเดียวสี่สิบบรรทัดแล้วรัน พอมันเงียบ ผู้เรียนจะไม่รู้เลยว่าต้องเริ่มหาจากตรงไหน
ฝั่งระบบสมองกลฝังตัว
สถาปัตยกรรมหลายคอร์และการแบ่งงานตามความถนัด · การสื่อสารระหว่างคอร์ผ่าน IPC · แนวคิดว่าเฟิร์มแวร์คือชั้นที่ซ่อนความยุ่งยากของฮาร์ดแวร์ไว้ให้เรา
ฝั่ง Python และวิทยาการคอมพิวเตอร์
import โมดูล · ตัวแปร list และ tuple · ลูป for กับ range() · การเขียนฟังก์ชันด้วย def · การเข้ารหัสข้อความเป็นไบต์ · นาฬิกาที่วนกลับกับ ticks_diff()
ฝั่งการออกแบบระบบ
การเริ่มจากสถานะที่รู้แน่ · การรายงานสถานะเมื่อจบงาน · การแยกข้อมูลออกจากตรรกะ · การแบ่งหน้าที่ว่าจอตอบ "ตอนนี้" ลิ้นชักตอบ "ที่ผ่านมา"
สามบรรทัดสุดท้ายคือของที่จะติดตัวไปใช้ได้แม้เปลี่ยนภาษาและเปลี่ยนบอร์ด
วันนี้เราได้:
เล่นบอร์ดครบทุกเมนูหลักและรู้ว่าแต่ละเมนูกินข้อมูลจากเซนเซอร์ตัวไหน · รู้จักสมองสองก้อนและเส้นทางที่ข้อความเดินทางไปถึงจอ · ใช้ lcd ui และ time ประกอบเป็นจอสถานะหนึ่งใบได้ · เขียนกฎตัดระดับเองแล้วให้บอร์ดตรวจจนผ่าน
การบ้านของทีม: เลือกทำ 1 ข้อจากสี่ข้อในสไลด์ "ต่อยอด" จดลงบันทึกการเรียน
ชุดบทเรียนถัดไป: เราจะพาบอร์ดออกอินเทอร์เน็ต ด้วยโค้ดของเราเอง ไม่ใช่กดผ่านเมนู — wifi.connect() ให้ค่าอะไรกลับมา wifi.ip() คืออะไร แล้วทำไม "ต่อติดแล้ว" กับ "ยังต่ออยู่" ถึงเป็นคนละคำถาม · แล้วเลขที่วันนี้จบอยู่บนจอบอร์ด จะออกไปโผล่บนหน้าเว็บ (สไลด์ถัดไป)
เก็บโค้ดของวันนี้ไว้ให้ดี บทเรียนต่อ ๆ ไปเราจะต่อยอดจากไฟล์เดิมเรื่อย ๆ — โดยเฉพาะโครงของไฟล์ 08
วันนี้ตัวเลขทุกตัวจบที่จอบอร์ด 12_every_sense_at_once.py อ่านลูกบิด แผ่นสัมผัส และ IMU ได้ในคำสั่งเดียว แต่คนที่เห็นมีแค่คนที่ยืนอยู่หน้าบอร์ด
ชุดบทเรียนถัดไปเราเอาเลขชุดเดียวกันนี้ส่งออกไปที่ broker สาธารณะ broker.hivemq.com แล้วเปิดหน้าเว็บ my_first_reader.html บนโน้ตบุ๊กของเราเองอ่านกลับมา ใช้แค่เบราว์เซอร์ ไม่ต้องติดตั้งอะไรเพิ่ม
ของที่ติดมือไปชุดบทเรียนถัดไป: sensors.snapshot() จากไฟล์ 12 คือแหล่งตัวเลข · โครงจอสถานะของไฟล์ 08 คือหน้าตาของบันได WiFi → broker → ส่ง ที่ต้องเห็นบนจอทีละขั้น · ชื่อทีม team01 ถึง team19 ที่ผู้สอนแจก ให้จดลงบันทึกการเรียน
Emulator ใน ide.tesaiot.dev มีโมดูล
mqttที่ต่อ broker สาธารณะตัวจริงผ่าน WebSocket ได้ เลขจาก Emulator จึงขึ้นหน้าเว็บได้เหมือนเลขจากบอร์ด
คำถามคิดต่อ: เมนูไหนที่เล่นวันนี้ ที่อยากสร้างเองมากที่สุด · ถ้าจะสร้างมัน ต้องรู้อะไรเพิ่มบ้าง · ข้อมูลจากเซนเซอร์ตัวไหนที่น่าจะมีประโยชน์กับงานที่ทีมทำอยู่จริง
| บทเรียน | เรื่อง | จบบทเรียนแล้วทำอะไรได้ |
|---|---|---|
| 3 | ควบคุมฮาร์ดแวร์ — LED ปุ่ม จอ | สั่งไฟติดดับ อ่านปุ่มโดยไม่โดนสัญญาณเด้งหลอก |
| 4 | สร้าง Touch UI คุมฮาร์ดแวร์ | แตะปุ่มบนจอแล้วไฟบนบอร์ดติดจริง |
| 5 | อนาล็อก + สัมผัส + กรองสัญญาณ | หมุนลูกบิดคุมค่า และทำให้เลขที่สั่นนิ่งลงได้ |
| 6 | IMU กับมุมเอียง | ทำเครื่องวัดระดับดิจิทัลที่เอียงตามบอร์ดจริง |
| 7 | กราฟเรียลไทม์หลายเส้น | วาดสัญญาณที่วิ่งอยู่ และรู้ว่าสุ่มช้าไปแล้วภาพหลอกยังไง |
| 8 | Mini-HMI ประกอบทุกอย่าง | หน้าจอเดียวที่รวมทุกเซนเซอร์ และไม่ตายเมื่อตัวใดตัวหนึ่งเงียบ |
| 9 | WiFi และเครือข่าย | จอสถานะเครือข่ายที่บอกได้ว่าหลุดตอนไหน และกลับมาเมื่อไร |
| 10 | MQTT — ส่งค่าและรับคำสั่ง | ค่าจากโต๊ะเราขึ้นจอคนอื่น และคำสั่งจากคนอื่นสั่งบอร์ดเราได้ |
| 11 | MQTTs เข้ารหัส สู่แพลตฟอร์ม | ส่งข้อมูลแบบที่คนกลางดักอ่านไม่ได้ ขึ้นแพลตฟอร์มจริง |
| 12 | Capstone — สร้างของจริงของทีม | ผลิตภัณฑ์ AIoT ย่อมหนึ่งชิ้นที่ทีมออกแบบเอง ตั้งแต่เซนเซอร์ถึงหน้าจอถึงคลาวด์ |
เส้นเรื่องคือเส้นเดียว — บทเรียน 2.1–3.9 ทำให้บอร์ดรับรู้และแสดงผลได้ครบ · บทเรียน 4.1–4.9 พาออกไปหาโลก · บทเรียน 5.1–5.3 คือวันที่ทีมเอาทุกชิ้นมาประกอบเป็นของตัวเอง
รายละเอียดเต็ม พร้อมภาพหน้าจอของแต่ละบทเรียน อยู่ที่ หน้าหลักสูตร (README.md) — เปิดดูล่วงหน้าได้เลย
ทั้งหมดนี้เป็นการบ้านแบบสมัครใจ ไม่ต้องเปิดในบทเรียน เนื้อหาวันนี้เข้าใจได้ครบโดยไม่ต้องดู
ไมโครโฟน MEMS ดิจิทัลหน้าตาเป็นอย่างไร
InvenSense (TDK) · 2 นาที 16 วินาที · อังกฤษ
บอร์ดเรามีไมโครโฟนแบบนี้ (Eva Kit มีสองตัว · Dev Kit ดูที่บอร์ดของทีม) คลิปนี้เปิดให้เห็นว่าข้างในมีอะไรและมันส่งอะไรออกมา — บทเรียน 3.7–3.9 เราจะอ่านค่าจากมันด้วยโมดูล mic
ข้างในเซนเซอร์วัดการเคลื่อนไหวมีอะไรอยู่จริง ๆ
Breaking Taps · ความยาว: ยังไม่ยืนยัน · อังกฤษ
แกะฝาชิป IMU แล้วส่องด้วยกล้องจุลทรรศน์อิเล็กตรอน เห็นมวลกับซี่หวีที่ขยับได้จริง — ตอบข้อสงสัยที่เกือบทุกคนมีว่า "มันวัดการเอียงได้ยังไงในเมื่อไม่มีอะไรหมุน"
BMI270 ตัวเดียวกับที่อยู่บนบอร์ดเรา
SparkFun Electronics · ความยาว: ยังไม่ยืนยัน · อังกฤษ
เบอร์ชิปตรงกับ U5 ในตารางเมื่อครู่เป๊ะ ๆ คลิปนี้ต่อสายจริงแล้วอ่านค่าออกมา — เห็นว่าสิ่งที่แถว IMU บนหน้า Home แสดงอยู่ มาจากชิ้นส่วนที่ซื้อแยกได้ ไม่ใช่ของวิเศษเฉพาะบอร์ดนี้
อ่านต่อสำหรับคนอยากรู้ลึก
คลิปพวกนี้ไม่ได้อยู่ในเกณฑ์ผ่าน แต่คนที่ดูจะเข้าใจบทเรียนหลัง ๆ ได้เร็วกว่าเพื่อน
ข้อ 1 · จอต้อนรับของทีม
ทำหน้าจอต้อนรับที่มีหัวเรื่อง ชื่อทีม คำขวัญ และรายชื่อสมาชิกพร้อม "หน้าที่ในทีม" ของแต่ละคน ใช้ระดับสีให้ตรงความหมาย ไม่ใช่เลือกตามชอบ
ข้อ 2 · นับถอยหลัง
ดัดแปลง 05_clear_and_refresh.py ให้นับถอยหลังจากเวลาที่ทีมตั้งเอง แล้วจบด้วยข้อความสีเขียว ลองปรับ TICK_MS แล้วสังเกตความรู้สึกที่ต่างกัน
ข้อ 3 · สำรวจกับดัก 127 ไบต์
จงใจพิมพ์ข้อความไทยยาวเกิน 42 ตัวอักษรในครั้งเดียว วัดดูว่าตัดที่ตัวอักษรที่เท่าไร แล้วอธิบายว่าทำไมภาษาไทยกับภาษาอังกฤษได้จำนวนตัวอักษรไม่เท่ากัน
ข้อ 4 · แผนที่เมนู
ทำตารางในสมุดว่าเมนูทั้งหมดที่เล่นวันนี้ ใช้เซนเซอร์อะไร แสดงผลแบบไหน และถ้าเป็นทีมเรา จะเพิ่มเมนูที่หกเป็นอะไรเพื่อแก้ปัญหาในงานจริงของเรา
เขียนคำตอบลงบันทึกการเรียน แล้วเอามาเล่าให้เพื่อนฟังต้นชุดบทเรียนถัดไป




.name() คือ "USER Button 1") · 12 คำสั่งเดียว ได้ทุกเซนเซอร์พร้อมกัน

เอกสารของผู้ผลิต
งานวิจัยที่กำหนดรูปร่างของชุดบทเรียนนี้
08_status_screen.py ได้พื้นที่สองสไลด์หมายเหตุเรื่องภาพ
ไดอะแกรม SVG ทุกภาพในเด็คนี้วาดขึ้นใหม่สำหรับหลักสูตรนี้ โดยอ้างอิงตำแหน่งอุปกรณ์และหมายเลขขาจากคู่มือบอร์ดข้างต้น
ภาพถ่ายและภาพเคลื่อนไหวที่นำมาประกอบ มาจาก Wikimedia Commons และหน่วยงานรัฐ ภายใต้สัญญาอนุญาต CC0 · CC BY · CC BY-SA หรือสาธารณสมบัติ ระบุผู้สร้างและสัญญาอนุญาตไว้ใต้ภาพทุกภาพ
ภาพหน้าจอในเด็คนี้มาจากสามแหล่ง และคำบรรยายใต้ภาพระบุไว้ทุกใบว่าใบไหนมาจากไหน — ภาพถ่ายจากบอร์ด Eva Kit จริง บันทึกโดยผู้สอน · ภาพจาก BENTO Emulator ที่ 800×480 เท่าจอของทั้งสองบอร์ด · และ ภาพจากตัวจำลอง bento_sim ซึ่งเรนเดอร์ด้วยโค้ด CM55 ชุดเดียวกับที่รันบนบอร์ด แต่ค่าจากเซนเซอร์ WiFi และไมโครโฟนเป็นค่าแทนบนเครื่องโฮสต์ — ภาพจากตัวจำลองแสดงหน้าจอที่ตัวอย่างสร้าง ไม่ใช่ผลการวัดของบอร์ด
ข้อเท็จจริงเกี่ยวกับพฤติกรรมของ lcd ui เมนู และเฟิร์มแวร์ ตรวจสอบจากซอร์สโค้ดของโปรเจกต์ KIT_PSE84_EVAL_EPC2-MicroPython-BentoClaw (Eva Kit) TESAIoT_KIT_PSE84_AI-Micropython-BentoClaw (Dev Kit) และ BENTO-TESAIoT-libraries โดยตรง
ทุกตัวเลขบนสไลด์นี้สืบกลับไปที่เอกสารต้นทางหรือซอร์สโค้ดได้ ถ้าเจอที่ไม่ตรง บอกผู้สอนได้เลย
หัวใจของ AIoT คือ ตัดสินใจใกล้จุดเกิดเหตุ ส่งขึ้นคลาวด์เฉพาะสิ่งที่มีความหมาย
สีทั้งห้าตัวบนสุดคือจานสีของหลักสูตร บทบาทละหนึ่งค่า — ห้ามหยิบสีสถานะมาแต่งจอ
ผู้สอน: ท่าที่ 5 นี้ในไฟล์ฝึกเขียนมาให้ครบแล้ว ไม่มีช่องว่าง ให้ทีมอ่านให้จบก่อนรัน แล้วเทียบว่าของที่ ui วางกับของที่ lcd พิมพ์ไปคนละที่กันอย่างไร