ข้ามไปยังเนื้อหา

ui.Chart: กราฟหลาย series และคาบเวลาของลูปจริง

โมดูล 3 — แสดงผลเซนเซอร์บน HMI · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร

สร้าง ui.Chart สามเส้นให้ถูกตั้งแต่ series 0 ที่มาฟรี เลือกช่วงแกน Y และสีเส้นเอง ทำปุ่มหยุดบันทึกเป็น flag ที่ลูปยังหมุน แล้ววัดคาบเวลาของลูปจริงด้วย ticks_diff() เพื่อรู้ว่ากราฟของเราเชื่อได้แค่ไหน

เมื่อจบบทเรียนนี้ คุณจะ:

  1. สร้าง ui.Chart สามเส้นได้ถูกต้อง: ใช้ series 0 ที่ได้จาก color= ตอนสร้าง เก็บเลขที่ add_series() คืนมา (1, 2, 3) ไว้ในตัวแปร และบอกได้ว่า set_next() ที่ส่ง idx ผิดถูกทิ้งเงียบ ส่วนค่าทศนิยมได้ TypeError
  2. เลือกช่วงแกน Y ให้เหมาะกับความเร่งบนบอร์ด (วางนิ่ง Z ราว 9.8 m/s² เขย่าแรง 15–20 จึงใช้ −20 ถึง +20) และเลือกสีเส้นจากจานสีเส้นข้อมูลแทนสีสถานะ พร้อมเหตุผล
  3. เขียนปุ่มเริ่มกับปุ่มหยุดบันทึกเป็นสองปุ่มที่ควบคุม flag running ซึ่งประกาศนอกลูป โดยให้ ui.poll() ถูกเรียกทุกรอบนอก if running และให้ ui.Led เป็นตัวบอกสถานะ
  4. วัดคาบลูปจริงด้วย 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 ไว้ข้าง ๆ สไลด์ “แกะโค้ดจริง” ไล่ตามโครงนั้นทีละท่า

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 ห้าท่า:

  1. เตรียม อ่าน motion() ทิ้งหนึ่งครั้งใน try ก่อนสร้างกราฟ ไม่ให้ค่าชุดแรกที่ยังไม่นิ่งค้างในบัฟเฟอร์กราฟนาน 10 วินาที แล้ว ui.clear() และจำไว้ว่าการใช้ ui.* ครั้งแรกจะหยุด sensor auto-task เราต้องอ่านเซนเซอร์เองในลูป
  2. กราฟกับตาราง กราฟตอบ “เมื่อกี้เป็นยังไง” ส่วน ui.Table ตอบ “ที่ผ่านมาแรงสุดเท่าไร” ซึ่งกราฟจำไม่ได้ value= ของ Table คือขนาดฟอนต์ในช่อง และคอลัมน์ที่แคบกว่าข้อความจะตัดบรรทัด ทุกแถวสูงเป็นสองเท่า แล้วแถว Z หายใต้ขอบโดยไม่มี error
  3. ปุ่มกับ flag ปุ่มสูง 88 px เก็บ .id() ไว้เทียบกับ ev.get('handle') และปุ่มส่ง event ชนิด 'clicked' เท่านั้น
  4. อ่านแล้วป้อน ส่ง int(ax) เข้ากราฟ แต่ส่ง ax ตัวเต็มให้ note() จำค่าสุดขีด ซึ่งตั้งต้นด้วย None แปลว่า “ยังไม่เคยวัด”
  5. นาฬิกาจับตัวเอง เส้นกราฟเดินทุกรอบ ส่วนตัวเลขในตารางเขียนด้วย .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 จุด

สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นด้วย:

ภาพจอจาก BENTO Emulator ของตัวอย่างในบทนี้ (คลิกชื่อไฟล์เพื่อเปิดโค้ด)

จอของ examples/02_fft64_two_tones.py ขณะรันใน BENTO Emulator: FFT radix-2 เขียนเองทั้งตัว 64 จุด
02_fft64_two_tones.py FFT radix-2 เขียนเองทั้งตัว 64 จุด

คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ

  1. ข้อใดถูกเกี่ยวกับ 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

  2. กราฟความเร่งสามแกนบนบอร์ดนี้ (วางนิ่ง Z ราว 9.8 m/s² เขย่าแรงพุ่ง 15–20) ควรตั้งช่วงแกน Y เท่าไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)

    • ก) −20 ถึง +20 เห็นทั้งแรงโน้มถ่วงและการเขย่า
    • ข) −2 ถึง +2 เพื่อให้เห็นการสั่นเล็ก ๆ ชัดที่สุด
    • ค) −100 ถึง +100 เพื่อไม่ให้มีอะไรตกขอบเลย
    • ง) ไม่ต้องตั้ง เพราะ Chart ปรับสเกลให้เอง
    เฉลย

    ก — ช่วง ±2 ทำให้ Z ติดขอบบนตลอด ช่วง ±100 ไม่มีอะไรตกขอบแต่เส้นแบนติดกลางจอ และ Chart ไม่มี autoscale ค่าที่เกินช่วงถูกกดติดขอบจนดูเหมือนสัญญาณอิ่มตัว

  3. ถ้าย้าย for ev in ui.poll() เข้าไปอยู่ใต้ if running: แล้วกดปุ่มหยุดบันทึก จะเกิดอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)

    • ก) ไม่มีใครเรียก ui.poll() อีก จอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มหายไปด้วย กลายเป็นหยุดถาวรที่กู้ไม่ได้
    • ข) กราฟหยุดตามต้องการ และกดเริ่มบันทึกเพื่อเดินต่อได้ตามปกติ
    • ค) โปรแกรมขึ้น error ทันทีว่า poll ต้องอยู่นอก if
    • ง) กราฟยังวิ่งต่อ เพราะ set_next() ไม่ขึ้นกับ poll
    เฉลย

    ก — หยุดข้อมูล ไม่ใช่หยุดลูป running คุมแค่ set_next() ส่วน ui.poll() ต้องถูกเรียกทุกรอบไม่ว่าจะหยุดหรือไม่ เพราะลูปที่ยังหมุนและยังรับ event คือสิ่งเดียวที่ทำให้จอยังมีชีวิต

  4. ทำไมวัดคาบลูปด้วย time.ticks_diff(now, last_ms) แทน now - last_ms (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)

    • ก) ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะนั้นจะได้ค่าติดลบมหาศาล ส่วน ticks_diff รู้เรื่องการวนนี้
    • ข) ticks_diff คืนหน่วยวินาที ส่วนการลบคืนมิลลิวินาที
    • ค) ticks_diff เร็วกว่าการลบเพราะเขียนด้วย C
    • ง) ไม่ต่างกัน ใช้แบบไหนก็ได้
    เฉลย

    ก — ตัวนับ ticks_ms() มีเพดานแล้ววนกลับ การลบตรง ๆ ในจังหวะที่มันวนพอดีจะได้ค่าติดลบมหาศาลแบบไม่มีปี่มีขลุ่ย ส่วน ticks_diff คืนผลต่างที่ถูกต้องเสมอ

  5. ลูปสั่ง 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 เท่าไร สีอะไร หยุดดูได้ไหม ลูปยังทันไหม) คุณเลือกอะไร

คำถามทบทวน

ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย

  1. ข้อใดถูกเกี่ยวกับ ui.Chart เลือกทุกข้อที่ถูก (เป้าหมายข้อ 1)

    1. ตอนสร้าง Chart มี series 0 มาให้เลยด้วยสีจาก color= จึงไม่ต้อง add_series ให้เส้นแรก
    2. add_series() คืนเลข 1, 2, 3 ตามลำดับที่เรียก ต้องเก็บไว้ในตัวแปร แทนการพิมพ์เลขลงไปเอง
    3. มีแค่สามเส้นแล้วเรียก set_next(3, v) ข้อมูลนั้นหายไปเฉย ๆ โดยไม่มี error
    4. set_next(0, 9.78) ใช้ได้ Chart จะปัดเศษให้เอง
    5. 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

  2. กราฟความเร่งสามแกนบนบอร์ดนี้ (วางนิ่ง Z ราว 9.8 m/s² เขย่าแรงพุ่ง 15–20) ควรตั้งช่วงแกน Y เท่าไร (เป้าหมายข้อ 2)

    1. −20 ถึง +20 เห็นทั้งแรงโน้มถ่วงและการเขย่า
    2. −2 ถึง +2 เพื่อให้เห็นการสั่นเล็ก ๆ ชัดที่สุด
    3. −100 ถึง +100 เพื่อไม่ให้มีอะไรตกขอบเลย
    4. ไม่ต้องตั้ง เพราะ Chart ปรับสเกลให้เอง
    ดูเฉลย

    คำตอบ: A. −20 ถึง +20 เห็นทั้งแรงโน้มถ่วงและการเขย่า

    ช่วง ±2 ทำให้ Z ติดขอบบนตลอด ช่วง ±100 ไม่มีอะไรตกขอบแต่เส้นแบนติดกลางจอ และ Chart ไม่มี autoscale ค่าที่เกินช่วงถูกกดติดขอบจนดูเหมือนสัญญาณอิ่มตัว

  3. ถ้าย้าย for ev in ui.poll() เข้าไปอยู่ใต้ if running: แล้วกดปุ่มหยุดบันทึก จะเกิดอะไร (เป้าหมายข้อ 3)

    1. ไม่มีใครเรียก ui.poll() อีก จอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มหายไปด้วย กลายเป็นหยุดถาวรที่กู้ไม่ได้
    2. กราฟหยุดตามต้องการ และกดเริ่มบันทึกเพื่อเดินต่อได้ตามปกติ
    3. โปรแกรมขึ้น error ทันทีว่า poll ต้องอยู่นอก if
    4. กราฟยังวิ่งต่อ เพราะ set_next() ไม่ขึ้นกับ poll
    ดูเฉลย

    คำตอบ: A. ไม่มีใครเรียก ui.poll() อีก จอซ่อน widget ภายในราวสองวินาที ปุ่มเริ่มหายไปด้วย กลายเป็นหยุดถาวรที่กู้ไม่ได้

    หยุดข้อมูล ไม่ใช่หยุดลูป running คุมแค่ set_next() ส่วน ui.poll() ต้องถูกเรียกทุกรอบไม่ว่าจะหยุดหรือไม่ เพราะลูปที่ยังหมุนและยังรับ event คือสิ่งเดียวที่ทำให้จอยังมีชีวิต

  4. ทำไมวัดคาบลูปด้วย time.ticks_diff(now, last_ms) แทน now - last_ms (เป้าหมายข้อ 4)

    1. ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะนั้นจะได้ค่าติดลบมหาศาล ส่วน ticks_diff รู้เรื่องการวนนี้
    2. ticks_diff คืนหน่วยวินาที ส่วนการลบคืนมิลลิวินาที
    3. ticks_diff เร็วกว่าการลบเพราะเขียนด้วย C
    4. ไม่ต่างกัน ใช้แบบไหนก็ได้
    ดูเฉลย

    คำตอบ: A. ticks_ms() วนกลับไปเริ่มใหม่เมื่อชนเพดาน ลบเองในจังหวะนั้นจะได้ค่าติดลบมหาศาล ส่วน ticks_diff รู้เรื่องการวนนี้

    ตัวนับ ticks_ms() มีเพดานแล้ววนกลับ การลบตรง ๆ ในจังหวะที่มันวนพอดีจะได้ค่าติดลบมหาศาลแบบไม่มีปี่มีขลุ่ย ส่วน ticks_diff คืนผลต่างที่ถูกต้องเสมอ

  5. ลูปสั่ง sleep_ms(200) แต่ป้ายคาบลูปบน Eva Kit อ่านได้ 300 ms หมายความว่าอะไร และควรทำอย่างไร (เป้าหมายข้อ 4)

    1. งานในลูปหนักกว่าที่คิด อัตราสุ่มตกเหลือราว 3.3 Hz ให้ลดจำนวนป้ายที่อัปเดตทุกรอบ แต่ไม่ลดจนไม่เหลือ .text() เลย
    2. ปกติดี เพราะ sleep_ms ไม่แม่นอยู่แล้ว
    3. ลบป้ายทุกใบออกจากลูป กราฟจะได้เร็วที่สุด
    4. เซนเซอร์เสีย ต้องเรียก 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 ฉบับเต็ม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA