ภาพพื้นหลังปกบทเรียน

บทเรียน 3.3 — ลงมือทำ: เครื่องวัดระดับดิจิทัล

IMU กับมุมเอียง · เครื่องวัดระดับดิจิทัล: จากความเร่งดิบ สู่องศาที่คนอ่านรู้เรื่อง

โมดูล 3 — แสดงผลเซนเซอร์บน HMI

ต่อจากบทเรียน 3.2 — gyro ฟิลเตอร์ complementary และโค้ดเครื่องวัดระดับ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

MVP checkpoint — ผ่านชุดบทเรียนนี้เมื่อ

เครื่องวัดระดับ — วางราบอ่าน ~0°, เอียงแล้วแถบทั้งสองแกนวิ่งถูกทิศ และไฟบอกได้ว่าเกินเกณฑ์หรือยัง

แปลเป็นสิ่งที่ตรวจได้จริง:

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

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

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

กับดักที่เจอบ่อย (1/2) — หน้าจอและตัวกรอง

อาการ สาเหตุที่แท้จริง วิธีแก้
เอียงซ้าย-ขวา แต่แถบ PITCH วิ่งแทน เขียน pitch, roll = dsp.tilt(...) สลับลำดับ สลับเป็น roll, pitch = ...
แถบนิ่งสนิททั้งที่ตัวเลขเปลี่ยน ui.Bar ไม่ได้ตั้ง min=-90, max=90 (ค้างที่ 0-100) เติม min/max ตอนสร้างแถบ
ui.Scale ไม่ขยับเลยสักครั้ง แนวนอนคือไม้บรรทัด ไม่รับ .value() ตัวที่ต้องขยับคือ ui.Bar ที่วางทับ · แบบวงกลมใช้ .prop(ui.PROP_SCALE_NEEDLE, ...) (fw 2026-08-20 ขึ้นไป)
ตัวเลขบนไม้บรรทัดเบียดกันจนอ่านไม่ออก ขีดเยอะเกินไปสำหรับความกว้างที่มี .ticks(9, 4) บนความกว้าง 160 พิกเซล — ได้ -90 0 90
ui.Spinbox แตะแล้วค่าไม่เปลี่ยน จอสัมผัสไม่มีลูกบิดหมุน การแตะแค่เลือกตำแหน่งหลัก ต้องมี ui.Button เพิ่ม/ลดข้าง ๆ เสมอ
ช่องเกณฑ์ขึ้น 0005 ทั้งที่ตั้ง 5 ค่าตั้งต้นของ spinbox คือสี่หลัก sp_tol.digits(2, 0)
ไฟดับแล้วยังเห็นเป็นวงจาง ๆ ตั้งใจ .value(0) คือหรี่ ไม่ใช่หาย ไฟที่หายไปทำให้แยกไม่ออกว่าดับหรือจอเสีย
แถบกระตุกเป็นช่วง ๆ อ่านยาก ยังไม่ได้ต่อ EMA หรือ alpha สูงเกินไป ใช้ dsp.EMA(alpha=0.2) แล้วป้อน .update()
แถบตามมือช้ามาก alpha ต่ำเกินไป (เช่น 0.02) ขยับขึ้นเป็น 0.2-0.3 แล้วลองใหม่
วางราบแล้วไม่ได้ 0.0 สักที โต๊ะเอียง + offset ของชิป วางนิ่งแล้วกดปุ่ม ตั้งศูนย์
widget หายทั้งจอหลังรันไปพักหนึ่ง ลืม ui.poll() ในลูป เรียก ui.poll() ทุกรอบเสมอ
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

กับดักที่เจอบ่อย (2/2) — เซนเซอร์ หน่วย และเข็มทิศ

อาการ สาเหตุที่แท้จริง วิธีแก้
ค่าเพี้ยนหนักตอนถือเดินไปมา ความเร่งจากการเคลื่อนที่ปนกับแรงโน้มถ่วง วางนิ่งแล้วเอียงช้า ๆ หรือรอ fusion เต็มรูป
OSError เด้งกลางคัน เซนเซอร์ไม่ตอบทันในรอบนั้น (Eva: คอร์จอยังไม่ตอบ · Dev Kit: บัส I2C ยังไม่ว่าง) ห่อด้วย try / except OSError แล้วข้ามรอบนั้น
OSError ที่บรรทัด sensors.init() บน Eva Kit เฟิร์มแวร์ปฏิเสธคำสั่งนี้ (บน Dev Kit ผ่านเงียบ ๆ แต่ไม่จำเป็น) ลบบรรทัดนั้นทิ้ง ไม่ต้องมี init เลย ทั้งสองบอร์ด
OSError ที่ bmi270.temperature() / chip_id() บน Eva Kit สองค่านี้ไม่อยู่ใน snapshot (Dev Kit ใช้ได้) อย่าพึ่งสองคำสั่งนี้ · IMU ยังมีชีวิตไหม ดู snapshot()['bmi270']['sequence'] เดินขึ้นหรือเปล่า
Madgwick มุมหมุนติ้วจนอ่านไม่ได้ ป้อน gyro เป็น deg/s ทั้งที่มันต้องการ rad/s ครอบด้วย math.radians() ทั้งสามแกน
Madgwick มุมเดินเร็ว/ช้ากว่าความจริง fs= ไม่ตรงกับคาบลูปจริง ลูป 200 ms คือ fs=5.0 ไม่ใช่ค่าตั้งต้น 100
AttributeError: value ตอนเรียก ahrs.value() Madgwick กับ Pedometer ไม่มี .value() ใช้ .quaternion() หรือเก็บค่าที่ .update() คืนมาเอง
Pedometer นับก้าวขึ้นทั้งที่บอร์ดวางนิ่ง ค่าตั้งต้น threshold=1.5 เป็นหน่วย g แต่ป้อน m/s² เข้าไป หารด้วย 9.81 ก่อนป้อน หรือตั้ง threshold=12.0 ให้ตรงหน่วย
dsp.compass() กับ bmm350.heading() ไม่ตรงกัน คนละสูตร — atan2(y,x) กับ atan2(x,y) ไม่ใช่บั๊ก เลือกใช้ตัวใดตัวหนึ่งให้ตลอดทั้งโปรแกรม
เอียงบอร์ดแล้วทิศเปลี่ยนทั้งที่ไม่ได้หมุน dsp.compass() ทิ้ง mz จึงยังไม่ชดเชยการเอียง ถือบอร์ดให้ราบตอนอ่านทิศ
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ลงมือทำ — เติมช่องว่างในไฟล์ฝึก

เปิด s06_digital_level.py มีช่องว่างให้เติม 6 จุด

# เติม: sensors.bmi270.motion()   (ห้ามใส่ sensors.init())
pass

# เติม: ax, ay, az, gx, gy, gz = sensors.bmi270.motion()
pass

# เติม: roll, pitch = dsp.tilt(ax, ay, az)
pass

# เติม: roll_f = ema_roll.update(roll)
pass

# เติม: roll_zero = roll_f  แล้วบรรทัดถัดไป pitch_zero = pitch_f
pass

# เติม: roll_bar.value(int(clamp90(roll_show)))
pass

หน้าจอทั้ง 25 ชิ้นเขียนไว้ให้ครบแล้ว ไม่ต้องแตะ ทั้งไม้บรรทัด ช่องเกณฑ์ ปุ่มเพิ่ม/ลด ไฟสองดวง และบรรทัดคุณภาพของค่า งานของเราคือทำให้ค่าไหลเข้าไปในนั้น

เติมเป็นสามขั้น แล้วรันทุกขั้น ขั้น 1 · จุดที่ 1-3 ตัวเลขวิ่งไหม (กระตุกได้) ขั้น 2 · จุดที่ 4 เทียบก่อน-หลังกรอง ขั้น 3 · จุดที่ 5-6 ทดสอบปุ่มตั้งศูนย์

เติมทีละจุดแล้วรัน จะรู้ทันทีว่าพังที่จุดไหน — เติมครบหกจุดแล้วรันทีเดียวคือการเดา

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ตัวอย่างของบทเรียน 3.1–3.3 — สามไฟล์แรกทำในบทเรียนให้จบ ที่เหลือเปิดตามอาการ

ต้องทำในบทเรียน · เปิดตามลำดับนี้ ทั้งชุดราว 35 นาที

ลำดับ · เรื่อง · เวลา ไฟล์ ลงมือทำอะไร แล้วจะเข้าใจอะไร
1 · ข้างในของ dsp.tilt() · 10 นาที 03_tilt_from_gravity.py เอียงบอร์ดแล้วดูสามคอลัมน์: ค่าดิบ · คำตอบของ dsp.tilt() · คำตอบที่ไฟล์นี้คำนวณเองด้วย atan2 · สองคอลัมน์ขวาตรงกันเสมอ และแถวล่างแสดงให้เห็นว่าถ้าแกะสลับลำดับจะอ่านได้เป็นอะไร
2 · กรองก่อนค่อยตัดสิน · 10 นาที 01_imu_step_counter.py เดินถือบอร์ดสิบก้าวแล้วเทียบเลขที่นับได้กับที่เดินจริง · จะเห็นว่าถ้าไม่กรองก่อนและไม่มีเวลาห้ามนับซ้ำ สั่นครั้งเดียวจะถูกนับหลายก้าว
3 · เหตุการณ์เดียวไม่พอ · 15 นาที 02_imu_fall_detection.py ลองวางบอร์ดลงแรง ๆ ให้มันเข้าใจผิดว่าล้ม แล้วดูว่าขั้นไหนไม่ผ่าน · การล้มคือลำดับของเหตุการณ์ ไม่ใช่ความแรงอย่างเดียว

เปิดตามความสนใจ · นอกเกณฑ์ผ่านของชุดบทเรียนนี้ แต่ปิดช่องว่างของโมดูล

เรื่อง ไฟล์ ทำไมถึงมี
เข็มทิศ และข้อบกพร่องที่ยังค้าง 04_compass_and_magnetometer.py ครบทั้งห้าคำสั่งของ bmm350 และแสดง dsp.compass() เทียบกับ heading() ให้เห็นว่าคนละสูตร
fusion เต็มรูป และตัวนับก้าวสำเร็จรูป 05_madgwick_and_pedometer.py dsp.Madgwick กับ dsp.Pedometer สองคลาสสุดท้ายของโมดูล พร้อมกับดักเรื่องหน่วยทั้งสองข้อ

ติดตรงไหน เปิดอันนี้

อาการที่เจอ ไฟล์ที่ตอบอาการนั้น
กรอกช่อง dsp.EMA(alpha= ในบันทึกการเรียน ไม่ถูก ไม่รู้จะใส่เท่าไร 06_ema_time_constant.py — แปลง alpha เป็นเวลา tau เป็นวินาที เลือกจากตัวเลขได้เลย ไม่ต้องเดา
วางบอร์ดนิ่งแล้วแถบยังกระตุก ทั้งที่ใส่ตัวกรองไปแล้ว 07_median_beats_mean.py — ค่าหลุดค่าเดียวลากค่าเฉลี่ยไปด้วย แต่ทำอะไร median ไม่ได้ เพราะ median เรียงแล้วหยิบตัวกลาง
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เฉลย s06_digital_level.py — ตั้งต้นและหน้าจอ

import ui
ui.screen()
import time
import sensors
import dsp
ui.clear()
time.sleep_ms(200)
COL_TEXT, COL_DIM = 0xE8EAED, 0x9AA3AF
COL_CARD = 0x171B22
COL_OK, COL_WARN, COL_BAD = 0x30A46C, 0xF5A623, 0xE5484D
TOL_MIN, TOL_MAX, TOL_STEP = 1, 30, 1
tol = 5                        # เกณฑ์ยอมรับ หน่วยองศา
...                            # ท่า 1-2 ดูสไลด์ "แกะโค้ดจริง"
ema_roll = dsp.EMA(alpha=0.2)
ema_pitch = dsp.EMA(alpha=0.2)
roll_zero = 0.0
pitch_zero = 0.0
...
last_sec = -1                  # วินาทีที่เพิ่งเขียนตัวเลขลงจอ
def clamp90(v):
    return 90.0 if v > 90.0 else (-90.0 if v < -90.0 else v)
สอง EMA ไม่ใช่หนึ่ง ถูก roll → ema_roll pitch → ema_pitch ผิด roll และ pitch → ema เดียว ค่าปนกัน แถบวิ่งมั่วทั้งคู่
เฉลยรุ่นนี้เลิกใช้ สีบอกแกน (แดง = roll, เขียว = pitch) แล้วใช้ คำบอกแกน แทน — สีแดงกับเขียวในหน้าจอควบคุมจองไว้แล้วสำหรับ เสีย/ปกติ เอาไปบอกแกน วันที่ต้องเตือนจริงจะไม่มีใครแยกออก · แถบใช้สีเน้น 0x4A9EFF ปุ่มรอง 0x3A4150 ปุ่มหลัก 0x30A46C ตามจานสีของหลักสูตร · ตัวกรองสองตัวเพราะสองสัญญาณ ตัวกรองมี ความจำ
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เฉลย — ลูปหลัก และทำไมเรียงหกท่าแบบนี้

running = True
while running:
    ok_read = True
    try:
        ax, ay, az, gx, gy, gz = sensors.bmi270.motion()
        roll, pitch = dsp.tilt(ax, ay, az)
    except OSError:
        ok_read = False
    if ok_read:
        roll_f = ema_roll.update(roll)
        pitch_f = ema_pitch.update(pitch)
    roll_show = roll_f - roll_zero
    pitch_show = pitch_f - pitch_zero
    for ev in ui.poll():
        h = ev['handle']
        if h == zero_id:
            roll_zero = roll_f
            pitch_zero = pitch_f
        elif h == exit_id:
            running = False
        # ปุ่มเพิ่ม/ลด tol - ท่าที่ 5
        ...
    roll_bar.value(int(clamp90(roll_show)))     # แถบ ไฟ ตัวเลข - ท่าที่ 6
    ...
    lbl_health.text(health)
    time.sleep_ms(200)
ลำดับหกท่า ถูกบังคับด้วยตรรกะ 1 เช็กคอร์จอตอบ — ฐานของทุกอย่าง 2 สร้าง UI ครั้งเดียว นอกลูป 3 อ่านและแปลง — ตัวเลขมีความหมาย 4 กรอง — หลังพิสูจน์ว่าค่าดิบถูก 5 ตั้งศูนย์ — ต้องเก็บค่าที่กรองแล้ว 6 แสดงผล — ปลายทาง ไม่ใช่ต้นทาง
การแสดงผลทั้งหมดอยู่นอก if ok_read — รอบที่อ่านไม่ได้ก็ยังต้องวาดจอด้วยค่าเดิม แล้วเขียนบรรทัดคุณภาพ lbl_health ว่า "ค่าค้าง" ด้วยสีเตือน ถ้าปล่อยให้การวาดอยู่ใน if จอจะแช่ภาพเดิมโดยไม่มีอะไรบอกคนดู · in_tol ใช้ค่าที่ กรองแล้วและหักศูนย์แล้ว ไม่ใช่ค่าดิบ ไม่งั้นไฟจะกระพริบสลับดวงตอนค่าคาบเกี่ยวเกณฑ์ (alarm chattering) · for ev in ui.poll() อยู่ นอก if ok_read โดยตั้งใจ — เซนเซอร์ตายไม่ได้แปลว่าทั้งเครื่องต้องตายตาม
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

สรุปบทเรียน · รากฐานที่แตะ · และวันนี้อยู่ตรงไหนของเส้นทาง

ชุดบทเรียนนี้คือจุดที่เราเลิกเป็นผู้อ่านค่า แล้วเริ่มเป็นผู้คำนวณ บทเรียน 2.1–2.9 อ่านค่าดิบจากขา แล้วแปลงหน่วย วันนี้ · บทเรียน 3.1–3.3 สร้างปริมาณใหม่ ที่เซนเซอร์ไม่ได้ให้มา บทเรียน 3.4–3.9 เก็บประวัติเป็นกราฟ รวมเป็นแดชบอร์ด บทเรียน 4.1–5.3 ส่งมุมขึ้นคลาวด์ เฝ้าระวังจากไกล

วันนี้เราได้: เข้าใจว่า accelerometer วัดแรงที่ดันมวลไว้ (proper acceleration) · อ่านหกแกนจากการอ่านครั้งเดียวและรู้ว่าทำไม (Eva: snapshot ชุดเดียว · Dev Kit: lock บัสครั้งเดียว) · แปลงเวกเตอร์แรงโน้มถ่วงเป็นสององศาด้วย dsp.tilt() โดยจำลำดับ (roll, pitch) ได้ · รู้ว่า gyro drift กับ accel jitter คนละปัญหากัน · สร้างเครื่องมือวัดที่มีปุ่มตั้งศูนย์แบบเดียวกับเครื่องมือจริง

รากฐานที่แตะไป: เซนเซอร์ MEMS และความหมายทางฟิสิกส์ของค่าที่คืน · atomic read บนบัสร่วม · ตรีโกณมิติกับ atan2 · low-pass แบบ recursive และแนวคิด time constant · การอินทิเกรตกับการสะสมความผิดพลาด · calibration และ tare · การเลือกช่วงสเกลให้ตรงกับปริมาณจริง

ชุดบทเรียนถัดไป: เอา accel สามแกนเดียวกันนี้ไปวาดเป็น กราฟ real-time พร้อมตารางค่าสุดขีดและปุ่มเริ่ม/หยุดบันทึก

atan2 กับ EMA จะตามผู้เรียนไปทุกงานที่มีเซนเซอร์ ไม่ว่าจะเปลี่ยนภาษา เปลี่ยนบอร์ด หรือเปลี่ยนบริษัท

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ใช้จริงที่ไหน — สี่มุมของการวัดมุมเอียงในสนามจริง

โครงสร้าง · สะพานและปั้นจั่น เซนเซอร์เอียงติดบนตอม่อสะพานและเสาเครน การทรุดตัว 0.1° ที่ค่อย ๆ เพิ่ม คือสัญญาณอันตราย ต้องการ: ค่าไม่ drift เพราะเฝ้าดูกันเป็นปี โรงงาน · ตั้งระดับเครื่องจักร เครื่องกลึงและ CNC ต้องได้ระดับก่อนเดินเครื่อง ช่างใช้ปุ่ม tare เทียบกับฐานอ้างอิงหน้างาน ต้องการ: ปุ่มตั้งศูนย์แบบที่เราทำวันนี้ สุขภาพ · ตรวจจับการล้ม มุมลำตัวเปลี่ยนเร็วผิดปกติ + ความเร่งพุ่งแล้วนิ่ง "นั่งลงเร็ว" กับ "ล้ม" ต่างกันที่มุมหลังพุ่ง ต้องการ: ยืนยันหลายรอบก่อนเตือน แบบบทเรียน 5.1–5.3 ยานพาหนะ · ท่าทางของตัวรถ รถบรรทุกเตือนเสี่ยงพลิกคว่ำจาก roll ขณะเข้าโค้ง โดรนและหุ่นยนต์ป้อนมุมนี้กลับเข้าตัวควบคุม ต้องการ: fusion เต็มรูป เพราะเร่งและเลี้ยวตลอด

สังเกตช่อง "ต้องการ" ของทั้งสี่มุม — โจทย์ต่างกัน จึงเลือกฟิลเตอร์และ cadence ต่างกัน ไม่มีสูตรเดียวใช้ได้หมด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ต่อยอด — คิดต่อเอง (เลือกทำ 1 ข้อ)

ข้อ 1 · โหมดฟองอากาศ
ทำระดับน้ำแบบฟองอากาศด้วย ui.Panel วงเล็กหนึ่งใบ แล้วขยับด้วย .pos(x, y) ตามค่า roll และ pitch ให้เหมือนฟองในหลอดแก้ว วางราบแล้วฟองต้องอยู่กลางวงกลมอ้างอิง

ข้อ 2 · เตือนเมื่อไม่ได้ระดับ
ถ้ามุมแกนใดเกิน ±3° ให้เปลี่ยนสี Seg7 เป็นแดงด้วย .color() และจุดไฟจริงหนึ่งดวงพร้อมกัน — เลือกดวงตามชื่อใน gpio.board_info()["led_names"] (ดู led_named() ใน 01_imu_vibration_monitor.py) ไม่ใช่ gpio.led(0) ตายตัว เพราะเลข 0 เป็นคนละดวง (ชื่อต่างกัน) บนสองบอร์ด · คิดต่อว่าจะกัน "กะพริบถี่" ตอนค่าแกว่งอยู่ที่ขอบพอดีได้อย่างไร

ข้อ 3 · แข่ง alpha
สร้าง dsp.EMA สองตัวด้วย alpha ต่างกัน (0.05 กับ 0.5) ป้อน roll ตัวเดียวกันเข้าทั้งคู่ จับเวลาด้วย time.ticks_ms() ว่าแต่ละตัวใช้กี่มิลลิวินาทีกว่าจะไล่ตามการเอียงทัน แล้วสรุปเป็นตัวเลขว่าแลกอะไรกับอะไร

ข้อ 4 · พิสูจน์ว่า gyro drift จริงไหม
เขียนมุมจาก gyro ล้วน ๆ ด้วย gyro_roll = gyro_roll + gx * 0.2 ทุกรอบ แสดงคู่กับ roll จาก dsp.tilt() วางนิ่งสามนาที บันทึกว่าเส้นไหนหนีกี่องศา

กราฟ Allan deviation ของ gyro ที่แยกชนิดของสัญญาณรบกวนตามช่วงเวลาเฉลี่ย

ภาพ: Rudyk A.V. et al., Sensors 20(17):4841 (2020), CC BY 4.0 — Allan deviation แยกชนิดของ noise ที่ทำให้ gyro หนี · ใช้ประกอบข้อ 4

แผนภาพ 6 องศาอิสระ: เลื่อนตามแกนสามแกนและหมุนรอบแกนสามแกน

ภาพ: GregorDS, Wikimedia Commons, CC BY-SA 4.0 — 6 องศาอิสระ: เลื่อนสามแกน หมุนสามแกน

เขียนคำตอบลงบันทึกการเรียน แล้วเอามาเล่าให้เพื่อนฟังต้นชุดบทเรียนถัดไป

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

หน้าจอของทุกไฟล์ในชุดบทเรียนนี้ (1/2)

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

01 นับก้าวจากความเร่ง · 02 ตรวจการล้มด้วยลำดับสองเหตุการณ์ · 03 dsp.tilt() ทำอะไรกับสามตัวเลข และทำไมลำดับถึงสำคัญ
ภาพจากตัวจำลอง bento_sim ซึ่งเรนเดอร์ด้วยโค้ด CM55 ชุดเดียวกับที่รันบนบอร์ด ที่ 800x480 เท่าจอของ Eva Kit และ Dev Kit — แสดงหน้าจอที่ตัวอย่างสร้าง ค่าจากเซนเซอร์ WiFi และไมค์เป็นค่าแทนบนเครื่องโฮสต์ ไม่ใช่ผลการวัดของบอร์ด
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

หน้าจอของทุกไฟล์ในชุดบทเรียนนี้ (2/2)

หน้าจอของ 04_compass_and_magnetometer.py: เข็มทิศบนบอร์ด และตัวเลขหนึ่งตัวที่ยังไม่มีใครตอบได้ หน้าจอของ 05_madgwick_and_pedometer.py: สองคลาส IMU ที่เหลือใน dsp และหน่วยที่ดักไว้ทั้งคู่

04 เข็มทิศบนบอร์ด และตัวเลขหนึ่งตัวที่ยังไม่มีใครตอบได้ · 05 สองคลาส IMU ที่เหลือใน dsp และหน่วยที่ดักไว้ทั้งคู่
ภาพจากตัวจำลอง bento_sim ซึ่งเรนเดอร์ด้วยโค้ด CM55 ชุดเดียวกับที่รันบนบอร์ด ที่ 800x480 เท่าจอของ Eva Kit และ Dev Kit — แสดงหน้าจอที่ตัวอย่างสร้าง ค่าจากเซนเซอร์ WiFi และไมค์เป็นค่าแทนบนเครื่องโฮสต์ ไม่ใช่ผลการวัดของบอร์ด
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

อ้างอิงและเครดิต

แหล่งปฐมภูมิ

วิดีโอที่ฝังไว้ในชุดบทเรียนนี้ (ตรวจแล้วว่าเปิดได้)

RLQGZl0lpjQ Working principle of an accelerometer — Bosch Sensortec · 1:01 · KuekQ-m9xpw How does an Accelerometer work? — CircuitBread · 6:10 · XRr1kaXKBsU What Everyone Gets Wrong About Gravity — Veritasium · 17:33 (เริ่ม 2:30) · PK05u9c3yWI How do MEMS gyroscopes work? — nanolearning · 13:44 (เริ่ม 4:00) — คำอธิบายว่าดูเพื่ออะไร อยู่ใต้คลิปในสไลด์ที่ฝังไว้แล้ว

เครดิตภาพ — ทุกภาพมาจาก Wikimedia Commons หรือบทความ open-access ใน PMC (CC0 / CC BY / CC BY-SA / สาธารณสมบัติ) รายละเอียดที่ CREDITS.md · ห้ามใช้ บทความไทยที่ติดอันดับสูงสุดเรื่อง gyro/accel เพราะอธิบายผิดหลักการ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

อ้างอิงและเครดิต (ต่อ) — ตัวอย่างโค้ด และสิ่งที่เปลี่ยนจากเฟิร์มแวร์รุ่นก่อน

ตัวอย่างโค้ด — โฟลเดอร์ examples/ ของบทเรียน 3.1–3.3 ห้าไฟล์ · คลังชุดบทเรียนนี้ถูกคัดจากหกไฟล์เหลือสองเมื่อ 14 ส.ค. (ไฟล์ที่ถอดออกเป็นเรื่องบิตกับเรื่องตัวกรอง ซึ่งเป็นของชุดบทเรียนอื่น) แล้ว เพิ่มกลับสามไฟล์เมื่อ 15 ส.ค. เพื่อปิดช่องว่างของ API ที่ชุดบทเรียนนี้เป็นเจ้าของ: 03_tilt_from_gravity.py (dsp.tilt ซึ่งเป็นแกนกลางของชุดบทเรียนและเดิมไม่มีตัวอย่างเลย) · 04_compass_and_magnetometer.py (sensors.bmm350 ทั้งห้าคำสั่ง + dsp.compass) · 05_madgwick_and_pedometer.py (dsp.Madgwick + dsp.Pedometer) · ตัวกรองที่ชุดบทเรียนนี้ยืมมาใช้อยู่ที่ 06_ema_time_constant.py และ 07_median_beats_mean.py ส่วนตระกูลเต็มอยู่ที่ 08_six_filters_one_signal.py · ปลายทางเรื่องการสั่นอยู่ที่ 01_imu_vibration_monitor.py

เปลี่ยนจากเฟิร์มแวร์รุ่นก่อน — บน Eva Kit sensors.init() scan() push() live_push() auto() ถูกปฏิเสธด้วย OSError ทั้งห้าตัว · sensors.bmi270.motion() / .acceleration() / .gyroscope() อ่านผ่าน snapshot ของคอร์จอ ส่วน .temperature() / .chip_id() ใช้ไม่ได้ · sensors.bmm350.* ทั้งห้าคำสั่งอ่านตรงจากชิปได้ เพราะอยู่คนละบัส (I3C) · บน TESAIoT Dev Kit CM33 อ่าน BMI270 ตรงจาก I2C: ห้าตัวข้างต้นไม่ถูกปฏิเสธ (แต่คอร์สนี้ไม่เรียก) และ .temperature() / .chip_id() ใช้ได้ · snapshot() มีทั้งสองบอร์ด dict หน้าตาเดียวกัน · ทิศแกน x/y เทียบขอบฐาน QWA309 ยังไม่ได้วัด · ความเร่งเป็นช่วง +/-8g (4096 LSB/g) และ gyro เป็น +/-2000 dps (16.4 LSB/dps) · ตรวจจากซอร์ส BENTO-TESAIoT-libraries/claw/common/mpy/modsensors.c, modsensors_bmm350.c, sensor_bmm350.c และ moddsp_imu.c โดยตรง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

โน้ตผู้สอน: สิบสองในยี่สิบสามข้อนี้ไม่ทำให้โปรแกรม crash — มันแค่ให้คำตอบผิดอย่างเงียบ ๆ ซึ่งอันตรายกว่า · ห้าข้อล่างสุดเป็นเรื่อง **หน่วย** ล้วน ๆ และหกข้อกลางเป็นเรื่อง **เข้าใจ widget ผิดตัว** ทั้งสามกลุ่มไม่มี error ให้เห็น

โน้ตผู้สอน: เปลี่ยนจากรุ่นก่อน (15 ส.ค.): เดิมสไลด์นี้เขียนว่า "ยังไม่มีไฟล์ตัวอย่างไหนในคลังที่คำนวณ roll/pitch" ซึ่งเป็นจริงจนถึงวันนั้น · ตอนนี้ 03_tilt_from_gravity.py ทำหน้าที่นั้นแล้ว และเปิดให้เห็น atan2 สองบรรทัดที่อยู่ข้างในด้วย — งาน Build ใน s06_digital_level.py ยังเป็นการเขียนเองเหมือนเดิม ไฟล์ตัวอย่างอธิบาย *ทำไม* ไม่ได้ยกคำตอบมาให้

โน้ตผู้สอน: อ่านเสริมนอกเวลา — เรื่องนี้เป็นของบทเรียน 3.4–3.6 ไม่ใช่เกณฑ์ผ่านของวันนี้ แต่เป็นปลายทางที่ IMU ตัวเดียวกันนี้ไปได้ไกลที่สุดในงานอุตสาหกรรม: 01_imu_vibration_monitor.py วางบอร์ดบนของที่สั่นแล้วดูค่า RMS เทียบเส้นฐานที่โปรแกรมเก็บเอง · การสั่นวัดด้วยค่าเฉลี่ยไม่ได้ เพราะบวกลบหักล้างกันจนเหลือศูนย์