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

ลงมือทำ: เครื่องวัดระดับดิจิทัล

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

เติมช่องว่างหกจุดในไฟล์ฝึกให้ค่าจาก IMU ไหลเข้าหน้าปัดที่สร้างไว้แล้ว จนได้เครื่องวัดระดับสองแกนที่วางราบอ่านราว 0° เอียงแล้วแถบวิ่งถูกแกน และไฟบอกได้ว่าเกินเกณฑ์หรือยัง

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

  1. เติมช่องว่างหกจุดใน s06_digital_level.py ทีละจุดและรันทุกครั้ง จนวางบอร์ดราบแล้วกดตั้งศูนย์ ทั้งสองแกนอ่านได้ในช่วง −1.0° ถึง +1.0° และยกขอบที่ทำให้ roll เพิ่มแล้วแถบ ROLL ขยับโดยเครื่องหมายไม่กลับด้าน
  2. อธิบายลำดับในลูปหลักของเฉลยได้: อ่านและแปลงใน try/except OSError, กรองด้วย EMA ก่อนหักค่าศูนย์, ตอนกดตั้งศูนย์เก็บ roll_f ที่กรองแล้ว และวาดจอกับเรียก ui.poll() นอก if ok_read
  3. จับคู่อาการที่ไม่มี error อย่างน้อยสามอาการจากตารางกับดัก (เช่น แถบนิ่งสนิททั้งที่ตัวเลขเปลี่ยน ช่องเกณฑ์ขึ้น 0005 เอียงซ้าย-ขวาแล้วแถบ PITCH วิ่ง) กับสาเหตุและวิธีแก้ได้ถูกต้อง
  4. อธิบายจากตัวอย่าง 01_imu_step_counter.py และ 02_imu_fall_detection.py ได้ว่าทำไมต้องกรองก่อนนับและต้องมีเวลาห้ามนับซ้ำ 300 ms และทำไมการล้มต้องดูลำดับสามขั้น (ตกอิสระ กระแทกภายใน 800 ms แล้วนิ่ง 1500 ms) ไม่ใช่แรงกระแทกอย่างเดียว

ต่อจากบทเรียน 3.2: ต้องจำหกท่าของโค้ดเครื่องวัดระดับได้ และจำว่า dsp.tilt() คืน (roll, pitch) roll มาก่อนเสมอ ถ้ายังไม่รู้ว่าขอบไหนของบอร์ดทีมทำให้ roll เพิ่ม ให้เปิดบันทึกการเรียนจากบทเรียน 3.1 ทีม Dev Kit ต้องหาเองและจดไว้แล้ว แตะการ์ด BENTO Playground บนจอบอร์ดค้างไว้ แล้ววางบอร์ดราบกับโต๊ะ บน Eva Kit ที่เพิ่งรีเซ็ต การอ่านครั้งแรกนิ่งได้ถึง 16 วินาที นั่นคือการรอ ไม่ใช่การค้าง

ผ่านชุดบทเรียน 3.1–3.3 เมื่อเครื่องวัดระดับวางราบอ่านราว 0° เอียงแล้วแถบทั้งสองแกนวิ่งถูกทิศ และไฟบอกได้ว่าเกินเกณฑ์หรือยัง หน้าจอทั้ง 25 ชิ้นในไฟล์ฝึกเขียนไว้ให้ครบแล้ว ทั้งไม้บรรทัด ช่องเกณฑ์ ปุ่มเพิ่ม/ลด ไฟสองดวง และบรรทัดคุณภาพของค่า งานของเราคือทำให้ค่าไหลเข้าไปในนั้นผ่านช่องว่างหกจุด ซึ่งตรงกับหกท่าที่แกะในบทเรียน 3.2 เติมทีละจุดแล้วรัน จะรู้ทันทีว่าพังที่จุดไหน เติมครบหกจุดแล้วรันทีเดียวคือการเดา

ลำดับในลูปหลักของเฉลยคือเหตุผลทั้งหมดของบทเรียนนี้:

  • อ่าน motion() แล้วแปลงด้วย dsp.tilt() ใน try/except OSError รอบที่อ่านพลาดตั้ง ok_read = False แล้วใช้ค่าเดิมไปก่อน
  • กรองด้วย ema_roll.update(roll) ก่อน แล้วค่อยหัก roll_zero ตอนกดตั้งศูนย์เก็บ roll_f ที่กรองแล้ว ไม่ใช่ roll ดิบที่อาจกำลังสั่นอยู่พอดี
  • การแสดงผลทั้งหมดอยู่นอก if ok_read รอบที่อ่านไม่ได้ก็ยังวาดจอด้วยค่าเดิม แล้วบรรทัดคุณภาพขึ้นว่า “ค่าค้าง” ด้วยสีเตือน ถ้าการวาดอยู่ใน if จอจะแช่ภาพเดิมโดยไม่มีอะไรบอกคนดู และ for ev in ui.poll() ก็อยู่นอก if ok_read โดยตั้งใจ เซนเซอร์ตายไม่ได้แปลว่าทั้งเครื่องต้องตายตาม
  • in_tol ใช้ค่าที่กรองแล้วและหักศูนย์แล้ว ไม่ใช่ค่าดิบ ไม่งั้นไฟจะกระพริบสลับดวงตอนค่าคาบเกี่ยวเกณฑ์ (alarm chattering)

หน้าปัดนี้ออกแบบให้อ่านได้แม้ถ่ายเป็นขาวดำ แกนบอกด้วยคำ (ROLL, PITCH) ไม่ใช่สีแดงกับเขียว เพราะสองสีนี้จองไว้แล้วสำหรับเสียกับปกติ ผ่านหรือเกินบอกด้วยไฟสองดวงที่ติดทีละดวงเท่านั้น และ ui.Led ที่สั่ง .value(0) จะหรี่ ไม่ใช่หายไป เพื่อให้แยกออกว่าดับหรือจอเสีย แถบกับไฟขยับทุกรอบ (5 ครั้งต่อวินาที) เพราะตาอ่านตำแหน่งได้ทันที ส่วน Seg7 เขียนใหม่วินาทีละครั้ง ท้ายลูปยังส่ง lbl_health.text(health) ซ้ำทุกรอบโดยตั้งใจ เพราะ .value() ของแถบกับไฟไม่ปลุกโหมดเร็วของฝั่งจอ ลูปที่อัปเดตแค่แถบกับไฟจะเงียบเกินครึ่งวินาทีแล้วภาพกระตุก ข้อความที่ไม่เปลี่ยนไม่ถูกวาดซ้ำ เราจึงจ่ายแค่ค่าส่งข้ามคอร์

ตารางกับดักสองหน้าในสไลด์คือเครื่องมือหลักของแล็บนี้ อาการส่วนใหญ่ไม่มี error ให้เห็น มันแค่ให้คำตอบผิดอย่างเงียบ ๆ เช่น แถบนิ่งสนิทเพราะ ui.Bar ไม่ได้ตั้ง min=-90, max=90 · ui.Scale ไม่ขยับเพราะมันคือไม้บรรทัด ไม่รับ .value() · ช่องเกณฑ์ขึ้น 0005 เพราะ spinbox ตั้งต้นที่สี่หลัก ต้อง sp_tol.digits(2, 0) · widget หายทั้งจอเพราะลืม ui.poll() ในลูป

ทำสามไฟล์นี้ในบทเรียนให้จบตามลำดับ ทั้งชุดราว 35 นาที

  1. 03_tilt_from_gravity.py (ราว 10 นาที) ทำนาย ก่อนรันว่าคอลัมน์ dsp.tilt() กับคอลัมน์ที่คำนวณเองด้วย atan2 จะต่างกันไหม · รัน แล้วเอียงบอร์ด สองคอลัมน์ขวาต้องเท่ากันตลอด · สำรวจ แถวล่างสุด ซึ่งแสดงว่าค่าเดียวกันถ้าแกะสลับลำดับจะอ่านได้เป็นอะไร
  2. 01_imu_step_counter.py (ราว 10 นาที) เดินถือบอร์ดสิบก้าวแล้วเทียบเลขที่นับได้กับที่เดินจริง ดูป้าย “รอพ้นเวลาห้ามนับซ้ำ” ว่าบอกเหตุผลที่ยอดคลื่นบางลูกไม่ถูกนับ แล้ว ดัดแปลง ตามที่ไฟล์ท้าไว้: ตั้ง REFRACT_MS = 0 แล้วเดินเท่าเดิม ตัวเลขจะพุ่งเกินจริง
  3. 02_imu_fall_detection.py (ราว 15 นาที) วางบอร์ดลงโต๊ะแรง ๆ ให้มันเข้าใจผิดว่าล้ม แล้วดูว่าขั้นไหนในสามขั้นไม่สว่าง การล้มคือลำดับของเหตุการณ์ ขนาดความเร่งต่ำกว่า 3.0 m/s² (ตกอิสระ) แล้วเกิน 25.0 m/s² ภายใน 800 ms (กระแทก) แล้วนิ่งต่อ 1500 ms

ถ้าติด: เลือก alpha ของ dsp.EMA ไม่ถูก เปิด 06_ema_time_constant.py จากบทเรียน 2.8 ซึ่งแปลง alpha เป็น tau เป็นวินาที · วางนิ่งแล้วแถบยังกระตุกทั้งที่ใส่ตัวกรองแล้ว เปิด 07_median_beats_mean.py จากบทเรียน 2.9 ส่วนเข็มทิศกับ dsp.Madgwick อยู่ในตัวอย่างของบทเรียน 3.2 นอกเกณฑ์ผ่านของชุดบทเรียนนี้

ไฟล์ ไฟล์นี้สอน
examples/01_imu_step_counter.py นับก้าวจากความเร่ง
examples/02_imu_fall_detection.py ตรวจการล้มด้วยลำดับสองเหตุการณ์
examples/03_tilt_from_gravity.py dsp.tilt() ทำอะไรกับสามตัวเลข และทำไมลำดับถึงสำคัญ

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

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

จอของ examples/01_imu_step_counter.py ขณะรันใน BENTO Emulator: นับก้าวจากความเร่ง
01_imu_step_counter.py นับก้าวจากความเร่ง
จอของ examples/02_imu_fall_detection.py ขณะรันใน BENTO Emulator: ตรวจการล้มด้วยลำดับสองเหตุการณ์
02_imu_fall_detection.py ตรวจการล้มด้วยลำดับสองเหตุการณ์
จอของ examples/03_tilt_from_gravity.py ขณะรันใน BENTO Emulator: dsp.tilt() ทำอะไรกับสามตัวเลข และทำไมลำดับถึงสำคัญ
03_tilt_from_gravity.py dsp.tilt() ทำอะไรกับสามตัวเลข และทำไมลำดับถึงสำคัญ

ไฟล์ฝึกมีช่องว่าง 6 จุด แต่ละจุดมีคำตอบเขียนไว้ในบรรทัด # เติม: แล้ว ลบ pass ใต้บรรทัดนั้นแล้วใส่โค้ดแทน เติมทีละจุดตามลำดับ และกด Program to Device ทุกครั้ง

  1. จุดที่ 1 (ท่าที่ 1): sensors.bmi270.motion() หนึ่งครั้งในบล็อก try เพื่ออุ่นเครื่อง ห้ามใส่ sensors.init()
  2. จุดที่ 2–3 (ท่าที่ 3): ax, ay, az, gx, gy, gz = sensors.bmi270.motion() แล้ว roll, pitch = dsp.tilt(ax, ay, az) ตอนนี้แถบ PITCH กับตัวเลขของมันควรขยับแล้ว เพราะบรรทัดกรองและบรรทัดส่งค่าของ pitch เขียนไว้ให้ ส่วน ROLL ยังนิ่งที่ 0
  3. จุดที่ 4 (ท่าที่ 4): roll_f = ema_roll.update(roll) ตัวเลข Seg7 ของ ROLL ควรเริ่มเปลี่ยน แต่แถบ ROLL ยังนิ่ง
  4. จุดที่ 5 (ท่าที่ 5): roll_zero = roll_f แล้วบรรทัดถัดไป pitch_zero = pitch_f กดตั้งศูนย์แล้วบรรทัด “อ้างอิง” ต้องเปลี่ยน
  5. จุดที่ 6 (ท่าที่ 6): roll_bar.value(int(clamp90(roll_show))) แถบ ROLL ขยับ แล้วตรวจกับ MVP checkpoint ทีละข้อ

ถ้าเอียงซ้าย-ขวาแล้วแถบ PITCH วิ่งแทน ให้ดูจุดที่ 3 ว่าแกะเป็น roll, pitch หรือยัง

ไฟล์ฝึก เรื่อง
practice/s06_digital_level.py เครื่องวัดระดับดิจิทัลสองแกน (ฉบับฝึกเติมโค้ด)

เปิดเฉลยหลังจากลองเองแล้วอย่างน้อยหนึ่งรอบ แล้วอ่าน วิธีใช้เฉลย ก่อน

เฉลย คู่กับ
solution/s06_digital_level.py practice/s06_digital_level.py

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

  1. จุดที่ 1 ของไฟล์ฝึก (ท่าที่ 1 ก่อนสร้างหน้าปัด) ควรเติมอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) sensors.bmi270.motion() หนึ่งครั้งในบล็อก try เพื่ออุ่นเครื่อง ให้การรอครั้งแรกเกิดก่อนสร้างหน้าปัด
    • ข) sensors.init() เพื่อปลุก IMU ก่อนอ่าน
    • ค) time.sleep_ms(16000) รอให้เซนเซอร์พร้อมทุกครั้งที่รัน
    • ง) ไม่ต้องเติมอะไร เพราะลูปหลักอ่านเซนเซอร์อยู่แล้ว
    เฉลย

    ก — บน Eva Kit sensors.init() ถูกปฏิเสธด้วย OSError และบน Dev Kit ก็ไม่จำเป็น ส่วนการอ่านครั้งแรกหลังรีเซ็ตบน Eva นิ่งได้ถึง 16 วินาที อุ่นเครื่องหนึ่งครั้งตรงนี้ให้การรอไปเกิดก่อนสร้างหน้าปัด ไม่ใช่ตอนแถบควรจะขยับแล้ว

  2. ข้อที่แปดของ MVP checkpoint ให้วางบอร์ดนิ่ง 30 วินาทีแล้วดูว่าตัวเลขไม่ไหลหนีไปทางเดียว ทำไมเครื่องวัดระดับของเราจึงผ่านข้อนี้ได้ (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) เราไม่ได้อินทิเกรตอะไรเลย มุมมาจาก dsp.tilt() ของ accelerometer ล้วน ๆ จึงไม่มี drift
    • ข) เพราะ dsp.EMA ลบ bias ของ gyro ออกให้เอง
    • ค) เพราะปุ่มตั้งศูนย์รีเซ็ตค่าให้ทุก 30 วินาที
    • ง) เพราะ motion() บน Eva Kit ชดเชย drift ให้จากโรงงาน
    เฉลย

    ก — drift เกิดจากการบวกสะสม ω·Δt ของ gyro เครื่องวัดระดับนี้ไม่ได้ใช้ gyro เลย ใช้แค่เงาของแรงโน้มถ่วงผ่าน dsp.tilt() แล้วกรองด้วย EMA ข้อที่แปดจึงเป็นข้อที่พิสูจน์ว่าเราไม่มีปัญหา drift

  3. ข้อใดถูกเกี่ยวกับลำดับในลูปหลักของเฉลย s06_digital_level.py เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 2)

    • ก) การวาดแถบ ไฟ และตัวเลขอยู่นอก if ok_read เพื่อให้รอบที่อ่านไม่ได้ยังวาดจอด้วยค่าเดิม และบรรทัดคุณภาพบอกว่าค่าค้าง
    • ข) in_tol ใช้ค่าที่กรองแล้วและหักศูนย์แล้ว เพื่อกันไฟกระพริบสลับดวงตอนค่าคาบเกี่ยวเกณฑ์
    • ค) for ev in ui.poll() อยู่นอก if ok_read เพราะเซนเซอร์ตายไม่ได้แปลว่าทั้งเครื่องต้องตายตาม
    • ง) ตอนกดตั้งศูนย์ควรเก็บ roll ดิบ เพราะเป็นค่าที่สดที่สุด
    • จ) ควรหักค่าศูนย์ก่อน แล้วค่อยป้อนเข้า EMA
    เฉลย

    ก, ข, ค — เฉลยกรองก่อนแล้วค่อยหักศูนย์ และตอนตั้งศูนย์เก็บ roll_f ที่กรองแล้ว เพราะจุดอ้างอิงที่มาจากค่าที่ยังสั่นจะทำให้แถบไม่มีวันกลับมาศูนย์จริง ๆ ส่วนการแสดงผลและ ui.poll() อยู่นอก if ok_read เพื่อให้จอบอกความจริงและปุ่มยังใช้ได้แม้รอบนั้นอ่านเซนเซอร์พลาด

  4. ตัวเลข Seg7 ของ ROLL เปลี่ยนตามการเอียง แต่แถบ ROLL นิ่งสนิทที่เดิม ไม่มี error สาเหตุที่น่าจะเป็นที่สุดคืออะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)

    • ก) สร้าง ui.Bar โดยไม่ได้ตั้ง min=-90, max=90 ช่วงปริยาย 0–100 จึงปัดมุมติดลบเป็น 0
    • ข) ลืม dsp.EMA ค่าจึงสั่นจนแถบวาดไม่ทัน
    • ค) แกะ dsp.tilt() สลับเป็น pitch, roll
    • ง) ใส่ sensors.init() ไว้ก่อนลูป
    เฉลย

    ก — โค้ดคำนวณถูก ตัวเลขจึงเปลี่ยน แต่แถบที่ค้างช่วง 0–100 ปัดค่าติดลบเป็น 0 แก้โดยเติม min/max ตอนสร้างแถบ ส่วนการแกะสลับจะทำให้แถบ PITCH วิ่งแทน และ sensors.init() บน Eva Kit จะขึ้น OSError ทันที ไม่ใช่เงียบ

  5. รัน 02_imu_fall_detection.py แล้ววางบอร์ดลงโต๊ะแรง ๆ ขนาดความเร่งพุ่งเกิน 25 m/s² แต่เครื่องไม่แจ้งเตือน เพราะอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)

    • ก) ไม่มีขั้นตกอิสระนำมาก่อน (ขนาดไม่ได้ลงต่ำกว่า 3.0 m/s²) เครื่องจึงยังอยู่สถานะ IDLE และไม่นับการกระแทกนั้น
    • ข) เกณฑ์กระแทกสูงเกินไป ควรลดลงจนการวางของก็นับด้วย
    • ค) เซนเซอร์อ่านพลาด จึงคืนค่า 9.8 แทน
    • ง) ลืมกรองด้วย dsp.EMA ก่อนตัดสิน
    เฉลย

    ก — การล้มคือลำดับสามขั้น ตกอิสระ แล้วกระแทกภายใน 800 ms แล้วนิ่งต่อ 1500 ms การวางของแรง ๆ มีแต่การกระแทก ถ้าตรวจแค่แรงกระแทกอย่างเดียวจะเตือนผิดทุกครั้งที่วางของลงโต๊ะ และระบบที่เตือนผิดบ่อย ผู้ใช้จะถอดทิ้ง

MVP checkpoint ผ่านชุดบทเรียน 3.1–3.3 เมื่อทุกข้อเป็นจริง

  • วางบอร์ดราบบนโต๊ะ กดตั้งศูนย์ แล้วทั้งสองแกนอ่านได้ในช่วง −1.0° ถึง +1.0°
  • ยกขอบด้านที่ทำให้ roll เพิ่มขึ้น (Eva: ขอบซ้าย · Dev Kit: ทีมหาเองแล้วจดว่าขอบไหน) แถบ ROLL ขยับ และเครื่องหมายไม่กลับด้าน
  • ยกขอบด้านที่ตั้งฉากกันขึ้น (Eva: ขอบบน) แถบ PITCH ขยับ ส่วน ROLL แทบไม่ขยับ
  • ตัวเลข Seg7 เปลี่ยนตามแถบ อ่านออกจากระยะห่างหนึ่งช่วงแขน และเปลี่ยนวินาทีละครั้ง ไม่ใช่ห้าครั้งต่อวินาที
  • เอียงเกินเกณฑ์แล้วไฟสลับกันติดทีละดวงเท่านั้น ไม่ติดพร้อมกันสองดวง
  • กดปุ่มเพิ่ม/ลดเกณฑ์ แล้วเลขในช่องเปลี่ยนตาม หยุดเองที่ขอบพิสัย 1 กับ 30 และไฟเปลี่ยนตามเกณฑ์ใหม่โดยบอร์ดไม่ต้องขยับ
  • กดปุ่มตั้งศูนย์ในท่าเอียง แล้วค่ากลับไปเป็นราว 0° ในท่านั้น
  • วางบอร์ดนิ่ง 30 วินาที ตัวเลขไม่ไหลหนีไปทางเดียวเรื่อย ๆ
  • ถ่ายรูปหน้าจอตอนวางราบ และตอนเอียงจนไฟแดงติด แนบในบันทึกการเรียน

ข้อที่แปดคือข้อที่พิสูจน์ว่าเราไม่มีปัญหา drift เพราะเราไม่ได้อินทิเกรตอะไรเลย

ชุดบทเรียน 3.4–3.6 เอาความเร่งสามแกนเดียวกันนี้ไปวาดเป็นกราฟ real-time พร้อมตารางค่าสุดขีดและปุ่มเริ่ม/หยุดบันทึก เริ่มจากบทเรียน 3.4 ว่าต้องสุ่มสัญญาณถี่แค่ไหน ถ้าอยากไปต่อ เลือกหนึ่งข้อจากสไลด์ “ต่อยอด”: โหมดฟองอากาศด้วย ui.Panel กับ .pos(x, y) · เตือนเมื่อเกิน ±3° ด้วยไฟจริงที่เลือกตามชื่อจาก gpio.board_info()["led_names"] · แข่ง dsp.EMA alpha 0.05 กับ 0.5 · พิสูจน์ gyro drift ด้วย gyro_roll = gyro_roll + gx * 0.2 วางนิ่งสามนาที

บทเรียนถัดไป: บทเรียน 3.4 — สุ่มสัญญาณให้ถูก: Nyquist aliasing และ ring buffer

  • อาการไหนในตารางกับดักที่คุณเจอจริง และคุณอ่านมันออกจากอะไรบนจอ ในเมื่อไม่มี error ให้เห็น
  • ถ้าย้ายบรรทัดวาดจอทั้งหมดเข้าไปใน if ok_read คนที่ดูจออยู่จะเข้าใจผิดว่าอะไร
  • งานวางระดับของคุณเองต้องการเกณฑ์กี่องศา และทำไมจึงให้ผู้ใช้ตั้งเกณฑ์เอง แทนการฝังเป็นค่าคงที่ในโค้ด

คำถามทบทวน

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

  1. จุดที่ 1 ของไฟล์ฝึก (ท่าที่ 1 ก่อนสร้างหน้าปัด) ควรเติมอะไร (เป้าหมายข้อ 1)

    1. sensors.bmi270.motion() หนึ่งครั้งในบล็อก try เพื่ออุ่นเครื่อง ให้การรอครั้งแรกเกิดก่อนสร้างหน้าปัด
    2. sensors.init() เพื่อปลุก IMU ก่อนอ่าน
    3. time.sleep_ms(16000) รอให้เซนเซอร์พร้อมทุกครั้งที่รัน
    4. ไม่ต้องเติมอะไร เพราะลูปหลักอ่านเซนเซอร์อยู่แล้ว
    ดูเฉลย

    คำตอบ: A. sensors.bmi270.motion() หนึ่งครั้งในบล็อก try เพื่ออุ่นเครื่อง ให้การรอครั้งแรกเกิดก่อนสร้างหน้าปัด

    บน Eva Kit sensors.init() ถูกปฏิเสธด้วย OSError และบน Dev Kit ก็ไม่จำเป็น ส่วนการอ่านครั้งแรกหลังรีเซ็ตบน Eva นิ่งได้ถึง 16 วินาที อุ่นเครื่องหนึ่งครั้งตรงนี้ให้การรอไปเกิดก่อนสร้างหน้าปัด ไม่ใช่ตอนแถบควรจะขยับแล้ว

  2. ข้อที่แปดของ MVP checkpoint ให้วางบอร์ดนิ่ง 30 วินาทีแล้วดูว่าตัวเลขไม่ไหลหนีไปทางเดียว ทำไมเครื่องวัดระดับของเราจึงผ่านข้อนี้ได้ (เป้าหมายข้อ 1)

    1. เราไม่ได้อินทิเกรตอะไรเลย มุมมาจาก dsp.tilt() ของ accelerometer ล้วน ๆ จึงไม่มี drift
    2. เพราะ dsp.EMA ลบ bias ของ gyro ออกให้เอง
    3. เพราะปุ่มตั้งศูนย์รีเซ็ตค่าให้ทุก 30 วินาที
    4. เพราะ motion() บน Eva Kit ชดเชย drift ให้จากโรงงาน
    ดูเฉลย

    คำตอบ: A. เราไม่ได้อินทิเกรตอะไรเลย มุมมาจาก dsp.tilt() ของ accelerometer ล้วน ๆ จึงไม่มี drift

    drift เกิดจากการบวกสะสม ω·Δt ของ gyro เครื่องวัดระดับนี้ไม่ได้ใช้ gyro เลย ใช้แค่เงาของแรงโน้มถ่วงผ่าน dsp.tilt() แล้วกรองด้วย EMA ข้อที่แปดจึงเป็นข้อที่พิสูจน์ว่าเราไม่มีปัญหา drift

  3. ข้อใดถูกเกี่ยวกับลำดับในลูปหลักของเฉลย s06_digital_level.py เลือกทุกข้อที่ถูก (เป้าหมายข้อ 2)

    1. การวาดแถบ ไฟ และตัวเลขอยู่นอก if ok_read เพื่อให้รอบที่อ่านไม่ได้ยังวาดจอด้วยค่าเดิม และบรรทัดคุณภาพบอกว่าค่าค้าง
    2. in_tol ใช้ค่าที่กรองแล้วและหักศูนย์แล้ว เพื่อกันไฟกระพริบสลับดวงตอนค่าคาบเกี่ยวเกณฑ์
    3. for ev in ui.poll() อยู่นอก if ok_read เพราะเซนเซอร์ตายไม่ได้แปลว่าทั้งเครื่องต้องตายตาม
    4. ตอนกดตั้งศูนย์ควรเก็บ roll ดิบ เพราะเป็นค่าที่สดที่สุด
    5. ควรหักค่าศูนย์ก่อน แล้วค่อยป้อนเข้า EMA
    ดูเฉลย

    คำตอบ: A. การวาดแถบ ไฟ และตัวเลขอยู่นอก if ok_read เพื่อให้รอบที่อ่านไม่ได้ยังวาดจอด้วยค่าเดิม และบรรทัดคุณภาพบอกว่าค่าค้าง · B. in_tol ใช้ค่าที่กรองแล้วและหักศูนย์แล้ว เพื่อกันไฟกระพริบสลับดวงตอนค่าคาบเกี่ยวเกณฑ์ · C. for ev in ui.poll() อยู่นอก if ok_read เพราะเซนเซอร์ตายไม่ได้แปลว่าทั้งเครื่องต้องตายตาม

    เฉลยกรองก่อนแล้วค่อยหักศูนย์ และตอนตั้งศูนย์เก็บ roll_f ที่กรองแล้ว เพราะจุดอ้างอิงที่มาจากค่าที่ยังสั่นจะทำให้แถบไม่มีวันกลับมาศูนย์จริง ๆ ส่วนการแสดงผลและ ui.poll() อยู่นอก if ok_read เพื่อให้จอบอกความจริงและปุ่มยังใช้ได้แม้รอบนั้นอ่านเซนเซอร์พลาด

  4. ตัวเลข Seg7 ของ ROLL เปลี่ยนตามการเอียง แต่แถบ ROLL นิ่งสนิทที่เดิม ไม่มี error สาเหตุที่น่าจะเป็นที่สุดคืออะไร (เป้าหมายข้อ 3)

    1. สร้าง ui.Bar โดยไม่ได้ตั้ง min=-90, max=90 ช่วงปริยาย 0–100 จึงปัดมุมติดลบเป็น 0
    2. ลืม dsp.EMA ค่าจึงสั่นจนแถบวาดไม่ทัน
    3. แกะ dsp.tilt() สลับเป็น pitch, roll
    4. ใส่ sensors.init() ไว้ก่อนลูป
    ดูเฉลย

    คำตอบ: A. สร้าง ui.Bar โดยไม่ได้ตั้ง min=-90, max=90 ช่วงปริยาย 0–100 จึงปัดมุมติดลบเป็น 0

    โค้ดคำนวณถูก ตัวเลขจึงเปลี่ยน แต่แถบที่ค้างช่วง 0–100 ปัดค่าติดลบเป็น 0 แก้โดยเติม min/max ตอนสร้างแถบ ส่วนการแกะสลับจะทำให้แถบ PITCH วิ่งแทน และ sensors.init() บน Eva Kit จะขึ้น OSError ทันที ไม่ใช่เงียบ

  5. รัน 02_imu_fall_detection.py แล้ววางบอร์ดลงโต๊ะแรง ๆ ขนาดความเร่งพุ่งเกิน 25 m/s² แต่เครื่องไม่แจ้งเตือน เพราะอะไร (เป้าหมายข้อ 4)

    1. ไม่มีขั้นตกอิสระนำมาก่อน (ขนาดไม่ได้ลงต่ำกว่า 3.0 m/s²) เครื่องจึงยังอยู่สถานะ IDLE และไม่นับการกระแทกนั้น
    2. เกณฑ์กระแทกสูงเกินไป ควรลดลงจนการวางของก็นับด้วย
    3. เซนเซอร์อ่านพลาด จึงคืนค่า 9.8 แทน
    4. ลืมกรองด้วย dsp.EMA ก่อนตัดสิน
    ดูเฉลย

    คำตอบ: A. ไม่มีขั้นตกอิสระนำมาก่อน (ขนาดไม่ได้ลงต่ำกว่า 3.0 m/s²) เครื่องจึงยังอยู่สถานะ IDLE และไม่นับการกระแทกนั้น

    การล้มคือลำดับสามขั้น ตกอิสระ แล้วกระแทกภายใน 800 ms แล้วนิ่งต่อ 1500 ms การวางของแรง ๆ มีแต่การกระแทก ถ้าตรวจแค่แรงกระแทกอย่างเดียวจะเตือนผิดทุกครั้งที่วางของลงโต๊ะ และระบบที่เตือนผิดบ่อย ผู้ใช้จะถอดทิ้ง

อ้างอิงบทเรียนนี้

ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน

"ลงมือทำ: เครื่องวัดระดับดิจิทัล" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ข้อความอ้างอิงภาษาอังกฤษ: "Hands-on: the digital level" 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/l03-digital-level-lab/

บทเรียนนี้ดัดแปลงจากต้นฉบับด้านล่าง เมื่ออ้างอิงให้คงเครดิตต้นฉบับไว้ด้วย
https://github.com/Advance-Innovation-Centre-AIC/embedded-systems-for-aiot-developer/blob/a80bbe88a34bcb9bb8d991f42f9252b77cdab079/session-06.html (slides 33–46)

วิธีอ้างอิง TESA ฉบับเต็ม

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

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