ui.Chart: กราฟหลาย series และคาบเวลาของลูปจริง
โมดูล 3 — แสดงผลเซนเซอร์บน HMI · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร
สร้าง ui.Chart สามเส้นให้ถูกตั้งแต่ series 0 ที่มาฟรี เลือกช่วงแกน Y และสีเส้นเอง ทำปุ่มหยุดบันทึกเป็น flag ที่ลูปยังหมุน แล้ววัดคาบเวลาของลูปจริงด้วย ticks_diff() เพื่อรู้ว่ากราฟของเราเชื่อได้แค่ไหน
เป้าหมาย
หัวข้อที่มีชื่อว่า “เป้าหมาย”เมื่อจบบทเรียนนี้ คุณจะ:
- สร้าง ui.Chart สามเส้นได้ถูกต้อง: ใช้ series 0 ที่ได้จาก color= ตอนสร้าง เก็บเลขที่ add_series() คืนมา (1, 2, 3) ไว้ในตัวแปร และบอกได้ว่า set_next() ที่ส่ง idx ผิดถูกทิ้งเงียบ ส่วนค่าทศนิยมได้ TypeError
- เลือกช่วงแกน Y ให้เหมาะกับความเร่งบนบอร์ด (วางนิ่ง Z ราว 9.8 m/s² เขย่าแรง 15–20 จึงใช้ −20 ถึง +20) และเลือกสีเส้นจากจานสีเส้นข้อมูลแทนสีสถานะ พร้อมเหตุผล
- เขียนปุ่มเริ่มกับปุ่มหยุดบันทึกเป็นสองปุ่มที่ควบคุม flag running ซึ่งประกาศนอกลูป โดยให้ ui.poll() ถูกเรียกทุกรอบนอก if running และให้ ui.Led เป็นตัวบอกสถานะ
- วัดคาบลูปจริงด้วย time.ticks_ms() กับ time.ticks_diff() แล้วแสดงบนจอ อธิบายว่าทำไมไม่ลบ now − last_ms เอง และอ่านค่าได้ (บน Eva Kit ราว 205–215 ms คือปกติ ถ้าถึง 300 ms อัตราสุ่มตกเหลือ 3.3 Hz)
ก่อนเริ่ม
หัวข้อที่มีชื่อว่า “ก่อนเริ่ม”ต่อจากบทเรียน 3.4: ต้องจำได้ว่า ui.Chart รับแต่จำนวนเต็ม เป็น ring buffer 50 ช่องที่ลูป 200 ms เห็นย้อนหลัง 10 วินาที
และลูปที่มีแต่ set_next() จะวาดช้า เพราะไม่ปลุกโหมดเร่งของฝั่งจอ
เปิดไฟล์ฝึก s07_accel_chart.py ของบทเรียน 3.6 ไว้ข้าง ๆ สไลด์ “แกะโค้ดจริง” ไล่ตามโครงนั้นทีละท่า
- อุปกรณ์: บอร์ด Eva Kit หรือ TESAIoT Dev Kit ที่ลงเฟิร์มแวร์ MicroPython ของ BENTO แล้ว หรือ BENTO Emulator ใน BENTO IDE
- เรียนมาก่อน: บทเรียน 3.4 — สุ่มสัญญาณให้ถูก: Nyquist aliasing และ ring buffer
ui.Chart มีกฎสี่ข้อที่ต้องจำ ข้อแรก ตอนสร้างมันมี series 0 มาให้เลยด้วยสีจาก color= เส้นแรกจึงไม่ต้อง add_series
ถ้าเผลอเพิ่มให้แกน X อีกจะได้สี่เส้น และ series 0 ว่างตลอดกาล ข้อสอง .add_series(สี) คืนเลข 1 แล้ว 2 แล้ว 3 ตามลำดับที่เรียก
ต้องเก็บใส่ตัวแปรเสมอ และอย่าพิมพ์เลข 1 กับ 2 ลงไปเอง สลับลำดับการสร้างเมื่อไร เลขที่พิมพ์เองจะชี้ผิดเส้น
เรียกครั้งที่สี่ได้ RuntimeError เพราะเพดานคือ 4 series ต่อกราฟ ข้อสาม min= กับ max= ตั้งครั้งเดียวตอนสร้าง ไม่มี autoscale
ข้อสี่ set_next() เป็นคำสั่งยิงแล้วลืม ส่ง idx ที่ไม่มีอยู่จริงไม่มี error ข้อมูลหายไปเฉย ๆ ต่างจากค่าทศนิยมที่ได้ TypeError ตั้งแต่ฝั่ง Python
ช่วงแกน Y กับสีเส้นเป็นงานที่ไม่มีใครทำแทนเรา ค่าที่เกินช่วงถูกกดติดขอบ ดูเผิน ๆ เหมือนสัญญาณอิ่มตัว
บนบอร์ดนี้ วางนิ่ง Z ราว 9.8 m/s² เขย่าแรงพุ่ง 15–20 กระแทกโต๊ะทะลุ 30 ช่วง ±2 ทำให้ Z ติดขอบบนตลอด ช่วง ±100 ไม่มีอะไรตกขอบแต่เส้นแบน
±20 จึงสมดุลที่สุด และ clamp ก่อนส่ง (max(-20, min(20, ax))) ทำให้เรารู้ตัวว่ากำลังตัดข้อมูล สามเส้นใช้จานสีเส้นข้อมูล
X ฟ้า 0x4A9EFF · Y ม่วง 0x8E7BFF · Z เขียวน้ำทะเล 0x2FB6A8 ไม่ใช่แดง/เขียว/น้ำเงิน เพราะจอนี้มีไฟสถานะอยู่ด้วย
เส้นสีแดงที่แปลแค่ว่า “แกน X” จะแย่งความหมายของแดงที่แปลว่า “ต้องรีบดู” ไปหมด ถ้าคนดูต้องถามว่าเส้นไหนคือแกนอะไร กราฟยังไม่เสร็จ
หยุดข้อมูล ไม่ใช่หยุดลูป ถ้าลูปหยุด ui.poll() ก็หยุดตาม แล้วจอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มก็หายไปด้วย กลายเป็นหยุดถาวร
ปุ่มหยุดจึงแค่ตั้ง running = False แล้วเฉพาะ set_next() อยู่ใต้ if running: ส่วน ui.poll() และ sleep_ms อยู่นอกเสมอ
running = True ต้องประกาศนอกลูป ถ้าอยู่ในลูปมันถูกตั้งใหม่ทุกรอบ กดหยุดเท่าไรก็ไม่หยุด ทั้งที่โค้ดดูถูกทุกบรรทัด
ปุ่มเริ่มกับปุ่มหยุดแยกกันคนละใบ แต่ละใบมีหน้าที่เดียว เพราะปุ่ม PAUSE ใบเดียวบอกได้แค่ว่ากดแล้วจะเกิดอะไร ไม่บอกว่าตอนนี้อยู่สถานะไหน
ตัวที่บอกสถานะคือ ui.Led กับป้ายข้าง ๆ และ .value(0) ทำให้ไฟหรี่ ไม่ใช่หาย โดยตั้งใจ
วัดคาบลูปจริง เพราะ sleep_ms ไม่ใช่ความจริงทั้งหมด T_loop = T_sleep + T_work ยังมีเวลาอ่านเซนเซอร์ ส่งข้าม IPC และอัปเดตป้าย
แพตเทิร์นคือ now = time.ticks_ms() · dt = time.ticks_diff(now, last_ms) · last_ms = now โดยตั้ง last_ms ไว้ก่อนเข้าลูป
ต้องใช้ ticks_diff เพราะ ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะที่มันวนพอดีจะได้ค่าติดลบมหาศาล
บน Eva Kit ค่าที่ควรอ่านได้คือราว 205–215 ms (fs ราว 4.8 Hz) บน Dev Kit ยังไม่ได้วัด ให้จดของทีมเอง
ถ้าพุ่งถึง 300 ms อัตราสุ่มตกเหลือ 3.3 Hz โดยที่โค้ดไม่บอกสักคำ ให้ลดจำนวนป้ายที่อัปเดตทุกรอบ แต่อย่าลดจนเหลือศูนย์ ไม่งั้นโหมดเร่งหลุดแล้วกราฟกระตุกแทน
โค้ดที่แกะในสไลด์คือโครงของแล็บบทเรียน 3.6 ห้าท่า:
- เตรียม อ่าน
motion()ทิ้งหนึ่งครั้งในtryก่อนสร้างกราฟ ไม่ให้ค่าชุดแรกที่ยังไม่นิ่งค้างในบัฟเฟอร์กราฟนาน 10 วินาที แล้วui.clear()และจำไว้ว่าการใช้ui.*ครั้งแรกจะหยุด sensor auto-task เราต้องอ่านเซนเซอร์เองในลูป - กราฟกับตาราง กราฟตอบ “เมื่อกี้เป็นยังไง” ส่วน
ui.Tableตอบ “ที่ผ่านมาแรงสุดเท่าไร” ซึ่งกราฟจำไม่ได้value=ของ Table คือขนาดฟอนต์ในช่อง และคอลัมน์ที่แคบกว่าข้อความจะตัดบรรทัด ทุกแถวสูงเป็นสองเท่า แล้วแถว Z หายใต้ขอบโดยไม่มี error - ปุ่มกับ flag ปุ่มสูง 88 px เก็บ
.id()ไว้เทียบกับev.get('handle')และปุ่มส่ง event ชนิด'clicked'เท่านั้น - อ่านแล้วป้อน ส่ง
int(ax)เข้ากราฟ แต่ส่งaxตัวเต็มให้note()จำค่าสุดขีด ซึ่งตั้งต้นด้วยNoneแปลว่า “ยังไม่เคยวัด” - นาฬิกาจับตัวเอง เส้นกราฟเดินทุกรอบ ส่วนตัวเลขในตารางเขียนด้วย
.cell()ไม่เกินวินาทีละครั้ง
ทุกจุดบนกราฟเดินผ่านห้าด่าน: BMI270 → Python บน CM33 (int() + set_next()) → คิว IPC 64 ช่องที่ล้นแล้วทิ้งเงียบ
→ CM55 ที่ระบาย 80 หรือ 3,200 คำสั่งต่อวินาทีลงบัฟเฟอร์ 50 จุด → จอ 4.3 นิ้ว กราฟกระตุกหรือจุดหาย ให้สงสัยด่านที่สามกับสี่ก่อนโทษเซนเซอร์
ตัวอย่างสมบูรณ์
หัวข้อที่มีชื่อว่า “ตัวอย่างสมบูรณ์”อุ่นเครื่องด้วยเครื่องกำเนิดสัญญาณ (ราว 10 นาที ไม่ต้องใช้เซนเซอร์) พิมพ์โค้ดสิบบรรทัดจากสไลด์ “อุ่นเครื่องก่อนจับเซนเซอร์” ลง BENTO IDE สัญญาณที่เรารู้คำตอบล่วงหน้าช่วยแยกได้ว่าถ้าเพี้ยน มันเพี้ยนที่กราฟหรือที่เซนเซอร์
- ทำนาย รูปคลื่นก่อนสลับบรรทัดที่คอมเมนต์ไว้ทีละแบบ: ไซน์ สี่เหลี่ยม ฟันเลื่อย แล้ว รัน ดูว่าตรงกับที่คิดไหม
- ดัดแปลง เปลี่ยน
0.15เป็น0.6ไซน์จะเริ่มไม่เหมือนไซน์ เพราะสุ่มไม่ทันแล้ว นั่นคือ aliasing ในสิบบรรทัด - สำรวจ ลบบรรทัด
lbl.text(...)แล้วรันใหม่ กราฟจะเดินช้าลงอย่างเห็นได้ชัดทั้งที่sleep_msเท่าเดิม
02_fft64_two_tones.py (ราว 10 นาที ส่วนเสริมของสไลด์ “เกร็ด” เรื่องโดเมนความถี่) ไฟล์นี้ป้อนสัญญาณห้าแบบ แล้วแสดงทั้งกราฟตามเวลา
และสเปกตรัม 16 bin บน ui.DotMatrix ทำนาย ก่อนกดเดินหน้าว่าขั้นผสมสองโทน 3 + 10 จะได้กี่แท่ง และแท่งที่สองสูงแค่ไหน
(ไฟล์ใส่โทนที่สองขนาดครึ่งเดียว) แล้วสังเกตกับดักสองข้อ: bin ไม่ใช่ Hz ต้องคูณ fs/N เอง และครึ่งบนของสเปกตรัมเป็นเงาของครึ่งล่าง จึงพล็อตแค่ถึง N/2
ส่วนงานจริงมี dsp.fft_mag(ชุด, n=256) ในตัวแล้วบนเฟิร์มแวร์ 2026-08-20 ขึ้นไป ไฟล์นี้เขียนเองเพื่อให้เห็นข้างใน
| ไฟล์ | ไฟล์นี้สอน |
|---|---|
| examples/02_fft64_two_tones.py | FFT radix-2 เขียนเองทั้งตัว 64 จุด |
สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นด้วย:
- m01-ui-application/l03-inside-the-box/examples/14_the_board_hears_you.py — พูดใส่บอร์ด แล้วดูมันขยับตาม
- m01-ui-application/l03-inside-the-box/examples/15_one_number_many_faces.py — ตัวเลขตัวเดียว กับสิบวิธีที่จอเล่ามันออกมา
- m02-ui-to-hardware/l06-touch-panel-lab/examples/07_find_move_hide_delete.py — จัดการ widget ที่สร้างไปแล้ว
- m02-ui-to-hardware/l06-touch-panel-lab/examples/08_dropdown_textarea.py — อีกสามชนิดที่รับอินพุตได้ และค่าที่ถามกลับได้จริง
- m03-sensor-hmi/l06-accel-chart-lab/practice/s07_accel_chart.py — กราฟความเร่งสามแกนแบบสด + ตารางสรุปสามแกน (ฉบับฝึกเติมโค้ด)
- m03-sensor-hmi/l06-accel-chart-lab/solution/s07_accel_chart.py — กราฟความเร่งสามแกนแบบสด + ตารางสรุปสามแกน
- m03-sensor-hmi/l09-dashboard-lab/examples/05_door_open_switch.py — สวิตช์แม่เหล็กบอกว่าประตูเปิดหรือปิด
ภาพจอจาก BENTO Emulator ของตัวอย่างในบทนี้ (คลิกชื่อไฟล์เพื่อเปิดโค้ด)

02_fft64_two_tones.py FFT radix-2 เขียนเองทั้งตัว 64 จุดเช็กความเข้าใจ
หัวข้อที่มีชื่อว่า “เช็กความเข้าใจ”คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ
-
ข้อใดถูกเกี่ยวกับ ui.Chart เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 1)
- ก) ตอนสร้าง Chart มี series 0 มาให้เลยด้วยสีจาก color= จึงไม่ต้อง add_series ให้เส้นแรก
- ข) add_series() คืนเลข 1, 2, 3 ตามลำดับที่เรียก ต้องเก็บไว้ในตัวแปร แทนการพิมพ์เลขลงไปเอง
- ค) มีแค่สามเส้นแล้วเรียก set_next(3, v) ข้อมูลนั้นหายไปเฉย ๆ โดยไม่มี error
- ง) set_next(0, 9.78) ใช้ได้ Chart จะปัดเศษให้เอง
- จ) Chart ปรับช่วงแกน Y ตามข้อมูลให้อัตโนมัติ
เฉลย
ก, ข, ค — set_next() เป็นคำสั่งยิงแล้วลืม idx ผิดถูกทิ้งเงียบ แต่ค่าทศนิยมได้ TypeError ตั้งแต่ฝั่ง Python และ min=/max= ตั้งครั้งเดียวตอนสร้าง ไม่มี autoscale
-
กราฟความเร่งสามแกนบนบอร์ดนี้ (วางนิ่ง Z ราว 9.8 m/s² เขย่าแรงพุ่ง 15–20) ควรตั้งช่วงแกน Y เท่าไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)
- ก) −20 ถึง +20 เห็นทั้งแรงโน้มถ่วงและการเขย่า
- ข) −2 ถึง +2 เพื่อให้เห็นการสั่นเล็ก ๆ ชัดที่สุด
- ค) −100 ถึง +100 เพื่อไม่ให้มีอะไรตกขอบเลย
- ง) ไม่ต้องตั้ง เพราะ Chart ปรับสเกลให้เอง
เฉลย
ก — ช่วง ±2 ทำให้ Z ติดขอบบนตลอด ช่วง ±100 ไม่มีอะไรตกขอบแต่เส้นแบนติดกลางจอ และ Chart ไม่มี autoscale ค่าที่เกินช่วงถูกกดติดขอบจนดูเหมือนสัญญาณอิ่มตัว
-
ถ้าย้าย for ev in ui.poll() เข้าไปอยู่ใต้ if running: แล้วกดปุ่มหยุดบันทึก จะเกิดอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)
- ก) ไม่มีใครเรียก ui.poll() อีก จอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มหายไปด้วย กลายเป็นหยุดถาวรที่กู้ไม่ได้
- ข) กราฟหยุดตามต้องการ และกดเริ่มบันทึกเพื่อเดินต่อได้ตามปกติ
- ค) โปรแกรมขึ้น error ทันทีว่า poll ต้องอยู่นอก if
- ง) กราฟยังวิ่งต่อ เพราะ set_next() ไม่ขึ้นกับ poll
เฉลย
ก — หยุดข้อมูล ไม่ใช่หยุดลูป running คุมแค่ set_next() ส่วน ui.poll() ต้องถูกเรียกทุกรอบไม่ว่าจะหยุดหรือไม่ เพราะลูปที่ยังหมุนและยังรับ event คือสิ่งเดียวที่ทำให้จอยังมีชีวิต
-
ทำไมวัดคาบลูปด้วย time.ticks_diff(now, last_ms) แทน now - last_ms (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)
- ก) ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะนั้นจะได้ค่าติดลบมหาศาล ส่วน ticks_diff รู้เรื่องการวนนี้
- ข) ticks_diff คืนหน่วยวินาที ส่วนการลบคืนมิลลิวินาที
- ค) ticks_diff เร็วกว่าการลบเพราะเขียนด้วย C
- ง) ไม่ต่างกัน ใช้แบบไหนก็ได้
เฉลย
ก — ตัวนับ ticks_ms() มีเพดานแล้ววนกลับ การลบตรง ๆ ในจังหวะที่มันวนพอดีจะได้ค่าติดลบมหาศาลแบบไม่มีปี่มีขลุ่ย ส่วน ticks_diff คืนผลต่างที่ถูกต้องเสมอ
-
ลูปสั่ง sleep_ms(200) แต่ป้ายคาบลูปบน Eva Kit อ่านได้ 300 ms หมายความว่าอะไร และควรทำอย่างไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)
- ก) งานในลูปหนักกว่าที่คิด อัตราสุ่มตกเหลือราว 3.3 Hz ให้ลดจำนวนป้ายที่อัปเดตทุกรอบ แต่ไม่ลดจนไม่เหลือ .text() เลย
- ข) ปกติดี เพราะ sleep_ms ไม่แม่นอยู่แล้ว
- ค) ลบป้ายทุกใบออกจากลูป กราฟจะได้เร็วที่สุด
- ง) เซนเซอร์เสีย ต้องเรียก sensors.init() ใหม่
เฉลย
ก — T_loop = T_sleep + T_work บน Eva Kit ค่าปกติราว 205–215 ms ถ้าถึง 300 ms คือ fs ตกจาก 5 Hz เหลือ 3.3 Hz โดยที่โค้ดไม่บอก แต่ถ้าตัด .text() ออกหมด โหมดเร่งจะหลุดแล้วกราฟกระตุกแทน
บทเรียน 3.6 คือแล็บ: เติมช่องว่างหกจุดใน s07_accel_chart.py ตามห้าท่าที่เพิ่งแกะ แล้วตรวจกับ MVP checkpoint ของชุดบทเรียน 3.4–3.6
ตอนรันให้แตะการ์ด BENTO Playground ค้างไว้ เติมจากบนลงล่างทีละจุด และถ้าเพิ่งรีเซ็ตบอร์ด การอ่านครั้งแรกบน Eva รอได้ถึง 16 วินาที
บทเรียนถัดไป: บทเรียน 3.6 — ลงมือทำ: กราฟความเร่งสามแกน
สะท้อนคิด
หัวข้อที่มีชื่อว่า “สะท้อนคิด”- ถ้ากดหยุดบันทึกแล้วเขย่าบอร์ด กราฟยังวิ่ง คุณจะกลับไปดูบรรทัดไหนก่อน
- ตัวเลขคาบลูปบนจอช่วยตอบคำถามอะไรที่การอ่านโค้ดตอบไม่ได้
- ในงานของคุณเอง ห้าเรื่องที่ไลบรารีตัดสินใจแทนไม่ได้ (สุ่มถี่แค่ไหน แกน Y เท่าไร สีอะไร หยุดดูได้ไหม ลูปยังทันไหม) คุณเลือกอะไร
คำถามทบทวน
ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย
-
ข้อใดถูกเกี่ยวกับ ui.Chart เลือกทุกข้อที่ถูก (เป้าหมายข้อ 1)
- ตอนสร้าง Chart มี series 0 มาให้เลยด้วยสีจาก color= จึงไม่ต้อง add_series ให้เส้นแรก
- add_series() คืนเลข 1, 2, 3 ตามลำดับที่เรียก ต้องเก็บไว้ในตัวแปร แทนการพิมพ์เลขลงไปเอง
- มีแค่สามเส้นแล้วเรียก set_next(3, v) ข้อมูลนั้นหายไปเฉย ๆ โดยไม่มี error
- set_next(0, 9.78) ใช้ได้ Chart จะปัดเศษให้เอง
- Chart ปรับช่วงแกน Y ตามข้อมูลให้อัตโนมัติ
ดูเฉลย
คำตอบ: A. ตอนสร้าง Chart มี series 0 มาให้เลยด้วยสีจาก color= จึงไม่ต้อง add_series ให้เส้นแรก · B. add_series() คืนเลข 1, 2, 3 ตามลำดับที่เรียก ต้องเก็บไว้ในตัวแปร แทนการพิมพ์เลขลงไปเอง · C. มีแค่สามเส้นแล้วเรียก set_next(3, v) ข้อมูลนั้นหายไปเฉย ๆ โดยไม่มี error
set_next() เป็นคำสั่งยิงแล้วลืม idx ผิดถูกทิ้งเงียบ แต่ค่าทศนิยมได้ TypeError ตั้งแต่ฝั่ง Python และ min=/max= ตั้งครั้งเดียวตอนสร้าง ไม่มี autoscale
-
กราฟความเร่งสามแกนบนบอร์ดนี้ (วางนิ่ง Z ราว 9.8 m/s² เขย่าแรงพุ่ง 15–20) ควรตั้งช่วงแกน Y เท่าไร (เป้าหมายข้อ 2)
- −20 ถึง +20 เห็นทั้งแรงโน้มถ่วงและการเขย่า
- −2 ถึง +2 เพื่อให้เห็นการสั่นเล็ก ๆ ชัดที่สุด
- −100 ถึง +100 เพื่อไม่ให้มีอะไรตกขอบเลย
- ไม่ต้องตั้ง เพราะ Chart ปรับสเกลให้เอง
ดูเฉลย
คำตอบ: A. −20 ถึง +20 เห็นทั้งแรงโน้มถ่วงและการเขย่า
ช่วง ±2 ทำให้ Z ติดขอบบนตลอด ช่วง ±100 ไม่มีอะไรตกขอบแต่เส้นแบนติดกลางจอ และ Chart ไม่มี autoscale ค่าที่เกินช่วงถูกกดติดขอบจนดูเหมือนสัญญาณอิ่มตัว
-
ถ้าย้าย for ev in ui.poll() เข้าไปอยู่ใต้ if running: แล้วกดปุ่มหยุดบันทึก จะเกิดอะไร (เป้าหมายข้อ 3)
- ไม่มีใครเรียก ui.poll() อีก จอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มหายไปด้วย กลายเป็นหยุดถาวรที่กู้ไม่ได้
- กราฟหยุดตามต้องการ และกดเริ่มบันทึกเพื่อเดินต่อได้ตามปกติ
- โปรแกรมขึ้น error ทันทีว่า poll ต้องอยู่นอก if
- กราฟยังวิ่งต่อ เพราะ set_next() ไม่ขึ้นกับ poll
ดูเฉลย
คำตอบ: A. ไม่มีใครเรียก ui.poll() อีก จอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มหายไปด้วย กลายเป็นหยุดถาวรที่กู้ไม่ได้
หยุดข้อมูล ไม่ใช่หยุดลูป running คุมแค่ set_next() ส่วน ui.poll() ต้องถูกเรียกทุกรอบไม่ว่าจะหยุดหรือไม่ เพราะลูปที่ยังหมุนและยังรับ event คือสิ่งเดียวที่ทำให้จอยังมีชีวิต
-
ทำไมวัดคาบลูปด้วย time.ticks_diff(now, last_ms) แทน now - last_ms (เป้าหมายข้อ 4)
- ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะนั้นจะได้ค่าติดลบมหาศาล ส่วน ticks_diff รู้เรื่องการวนนี้
- ticks_diff คืนหน่วยวินาที ส่วนการลบคืนมิลลิวินาที
- ticks_diff เร็วกว่าการลบเพราะเขียนด้วย C
- ไม่ต่างกัน ใช้แบบไหนก็ได้
ดูเฉลย
คำตอบ: A. ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะนั้นจะได้ค่าติดลบมหาศาล ส่วน ticks_diff รู้เรื่องการวนนี้
ตัวนับ ticks_ms() มีเพดานแล้ววนกลับ การลบตรง ๆ ในจังหวะที่มันวนพอดีจะได้ค่าติดลบมหาศาลแบบไม่มีปี่มีขลุ่ย ส่วน ticks_diff คืนผลต่างที่ถูกต้องเสมอ
-
ลูปสั่ง sleep_ms(200) แต่ป้ายคาบลูปบน Eva Kit อ่านได้ 300 ms หมายความว่าอะไร และควรทำอย่างไร (เป้าหมายข้อ 4)
- งานในลูปหนักกว่าที่คิด อัตราสุ่มตกเหลือราว 3.3 Hz ให้ลดจำนวนป้ายที่อัปเดตทุกรอบ แต่ไม่ลดจนไม่เหลือ .text() เลย
- ปกติดี เพราะ sleep_ms ไม่แม่นอยู่แล้ว
- ลบป้ายทุกใบออกจากลูป กราฟจะได้เร็วที่สุด
- เซนเซอร์เสีย ต้องเรียก sensors.init() ใหม่
ดูเฉลย
คำตอบ: A. งานในลูปหนักกว่าที่คิด อัตราสุ่มตกเหลือราว 3.3 Hz ให้ลดจำนวนป้ายที่อัปเดตทุกรอบ แต่ไม่ลดจนไม่เหลือ .text() เลย
T_loop = T_sleep + T_work บน Eva Kit ค่าปกติราว 205–215 ms ถ้าถึง 300 ms คือ fs ตกจาก 5 Hz เหลือ 3.3 Hz โดยที่โค้ดไม่บอก แต่ถ้าตัด .text() ออกหมด โหมดเร่งจะหลุดแล้วกราฟกระตุกแทน
อ้างอิงบทเรียนนี้
ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน
"ui.Chart: กราฟหลาย series และคาบเวลาของลูปจริง" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0
ข้อความอ้างอิงภาษาอังกฤษ: "ui.Chart: multi-series plots and the real loop period" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0
ลิงก์บทเรียน: https://tesaiot.github.io/tesa-qualification-program/courses/aiot-micropython/m03-sensor-hmi/l05-realtime-chart/
บทเรียนนี้ดัดแปลงจากต้นฉบับด้านล่าง เมื่ออ้างอิงให้คงเครดิตต้นฉบับไว้ด้วย
https://github.com/Advance-Innovation-Centre-AIC/embedded-systems-for-aiot-developer/blob/a80bbe88a34bcb9bb8d991f42f9252b77cdab079/session-07.html (slides 15–32)
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0
เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA