บทความ › ไมโครคอนโทรลเลอร์และโค้ด

ใช้ Wi-Fi เป็นเซนเซอร์ จับการเคลื่อนไหว ด้วย CSI บน ESP32

Channel State Information คือข้อมูลละเอียดของคลื่น Wi-Fi ที่เปลี่ยนเมื่อมีคนขยับ ใช้ esp-radar กับ esp_wifi_sensing ทำเซนเซอร์จับคนโดยไม่ใช้กล้อง และเรื่องความเป็นส่วนตัว

ขั้นสูง อ่าน 7 นาที 23 ตุลาคม 2569 ของใหม่ที่ช่างควรลอง 2026 · บทที่ 10/20

อ่านจบแล้วจะรู้
  • CSI บอกแอมพลิจูดและเฟสของคลื่นแยกทีละ subcarrier ละเอียดกว่า RSSI ที่เป็นตัวเลขตัวเดียว คนเดินผ่านทำให้ค่าเหล่านี้แกว่ง
  • esp-radar แปลง CSI เป็นค่า waveform_jitter (การเคลื่อนไหว) กับ waveform_wander (การมีคนอยู่) ส่วน esp_wifi_sensing ทำ state ACTIVE/INACTIVE พร้อม debounce ให้
  • ต้องเทรนตอนห้องว่างและนิ่งหนึ่งครั้งต่อจุดติดตั้ง ย้ายบอร์ด ย้ายเราเตอร์ หรือย้ายเฟอร์นิเจอร์ใหญ่ ต้องเทรนใหม่
  • แม้ไม่มีกล้อง ก็ยังเป็นการตรวจจับคน บอกคนในบ้าน และห้ามใช้ส่องพื้นที่ของคนอื่น

Wi-Fi ไม่ได้มีไว้แค่ส่งข้อมูล ทุกแพ็กเก็ตที่ ESP32 รับ ชิปรู้ด้วยว่าคลื่นเดินทางมาแล้วอ่อนลงและเฟสเลื่อนไปเท่าไรในแต่ละความถี่ย่อย ข้อมูลชุดนี้เรียกว่า Channel State Information (CSI) เมื่อมีคนเดินในห้อง ร่างกายสะท้อนและดูดซับคลื่น ค่า CSI จึงแกว่ง เราใช้การแกว่งนี้เป็นเซนเซอร์จับการเคลื่อนไหวได้โดยไม่ต้องมีกล้องหรือ PIR

บทนี้เป็นระดับขั้นสูง ใช้ ESP-IDF (ไม่ใช่ Arduino) และคอมโพเนนต์ของ Espressif สองตัว คือ esp-radar กับ esp_wifi_sensing ทั้งหมดใช้ไฟจาก USB 5 V เท่านั้น ถ้ากำลังเลือกชิป Espressif จัดอันดับคุณภาพ CSI ให้ ESP32-C5 ดีที่สุดในตระกูล

CSI ต่างจาก RSSI ยังไง

RSSICSI
คืออะไรความแรงสัญญาณรวม 1 ค่าแอมพลิจูดและเฟส แยกทีละ subcarrier
ต่อแพ็กเก็ต (20 MHz, LLTF)1 ตัวเลข64 subcarrier = 128 ไบต์
ไวต่อการขยับน้อยมาก
ใช้ทำอะไรได้ดูว่าใกล้ไกลคร่าว ๆจับการเคลื่อนไหว การมีคนอยู่

เอกสาร ESP-IDF บอกว่าแต่ละ subcarrier เก็บเป็น 2 ไบต์แบบมีเครื่องหมาย ไบต์แรกเป็นส่วนจินตภาพ ไบต์ที่สองเป็นส่วนจริง สำหรับช่อง 20 MHz แบบ non-HT ส่วน LLTF มี subcarrier ลำดับ 031 และ -32-1 รวม 128 ไบต์ ถ้าแพ็กเก็ตเป็น HT (802.11n) จะมี HT-LTF เพิ่มอีกชุด รวม 256 ไบต์

ตัวอย่าง: CSI มากแค่ไหนต่อวินาที

CSI จะมาเฉพาะตอนมีแพ็กเก็ตเข้ามา จึงต้องสร้างทราฟฟิกเอง วิธีง่ายสุดคือให้ ESP32 ping เราเตอร์ถี่ ๆ แล้วอ่าน CSI จากแพ็กเก็ตตอบกลับ ตัวอย่าง console_test ใน esp-csi ตั้งค่า ping ทุก 10 ms เป็นค่าเริ่มต้น

  1. ping ทุก 10 ms = 1,000 ÷ 10 = 100 ครั้งต่อวินาที
  2. แพ็กเก็ตตอบกลับแบบ non-HT ได้ CSI 128 ไบต์: 100 × 128 = 12,800 ไบต์ต่อวินาที
  3. ถ้าเป็น HT ได้ 256 ไบต์: 100 × 256 = 25,600 ไบต์ต่อวินาที
  4. ในหนึ่งวินาทีมีค่าเชิงซ้อน 100 × 64 = 6,400 ค่าให้ประมวลผล (เฉพาะ LLTF)

ตัวเลขนี้ ESP32 รับไหว แต่ห้ามทำงานหนักใน callback เอกสารเตือนว่า callback ของ CSI รันใน Wi-Fi task ให้ส่งข้อมูลเข้า queue แล้วไปคำนวณใน task ที่ priority ต่ำกว่า ถ้าใช้ esp-radar มันจัดการส่วนนี้ให้

สามวิธีวางอุปกรณ์

จาก README ของ esp-csi

วิธีอุปกรณ์ข้อดีข้อเสีย
Router CSIESP32 1 ตัว + เราเตอร์ง่ายสุดผลขึ้นกับตำแหน่งเราเตอร์และโปรโตคอลที่เราเตอร์ใช้
ESP32 คุยกันเองESP32 หลายตัวพึ่งตำแหน่งเราเตอร์น้อยลงยังขึ้นกับเราเตอร์และสิ่งแวดล้อม
ตัวส่งเฉพาะตัวส่ง broadcast + ESP32 รับหลายตัวแม่นและนิ่งสุดในสามแบบต้องมีอุปกรณ์เพิ่ม

สำหรับของเล่นชิ้นแรก เริ่มจาก Router CSI พื้นที่ที่จับได้คือช่องว่างระหว่างบอร์ดกับเราเตอร์ วางให้ทางเดินที่อยากจับอยู่ตรงกลางระหว่างสองจุด README ยังบอกว่าเสาอากาศภายนอกแบบ IPEX ให้ผลดีกว่าเสาบนแผ่น PCB ที่มีทิศทาง

ping เราเตอร์ทุก 10 msให้มีแพ็กเก็ตไหลตลอดได้ CSI 128 ไบต์ต่อแพ็กเก็ตesp-radar คำนวณjitter และ wanderสถานะ ACTIVEมีคนขยับเปิดไฟ LED
จากแพ็กเก็ต Wi-Fi สู่สถานะมีคนขยับ

esp-radar กับ esp_wifi_sensing ทำงานยังไง

  • esp-radar รับ CSI แล้วคำนวณค่าคุณลักษณะสองตัว waveform_jitter ใช้ดูการเคลื่อนไหว และ waveform_wander ใช้ดูว่ามีคนอยู่
  • esp_wifi_sensing อยู่ชั้นบน รับค่าจาก esp-radar แล้วทำเป็น state machine สามสถานะ INACTIVE, DEBOUNCE, ACTIVE มี debounce เส้นฐานที่ปรับตามสภาพแวดล้อม callback เมื่อเปลี่ยนสถานะ และสั่ง ping เราเตอร์ให้เอง

ค่าที่ปรับได้ต่อช่อง: sensitivity ช่วง (0, 1] ยิ่งมากยิ่งไว (เปลี่ยนแล้วระบบจะเรียนเส้นฐานใหม่) presence_sensitivity ช่วง [0, 1] และ active_filter_ms เวลาค้างสถานะ ACTIVE ขั้นต่ำ ช่วยไม่ให้ไฟกะพริบถี่

ลองจากตัวอย่างของ Espressif

ต้องมี ESP-IDF 5.4 ขึ้นไป รันบนคอมที่ติดตั้ง ESP-IDF แล้ว

idf.py create-project-from-example "espressif/esp-radar=*:console_test"
cd console_test
idf.py set-target esp32c5
idf.py flash monitor

ถ้าใช้ชิปอื่น เปลี่ยน esp32c5 เป็นรุ่นของบอร์ด ตัวอย่างนี้เปิด CSI ไว้ใน sdkconfig.defaults แล้ว ถ้าเขียนโปรเจกต์เอง ต้องเปิดใน idf.py menuconfig ที่ Components config > Wi-Fi > Wi-Fi CSI (Channel State Information)

ตัวอย่าง wifi_sensing_demo ใน esp-csi ไปไกลกว่านั้น ต่อ Wi-Fi แล้วเริ่ม state machine ไฟ LED ติดเต็มเมื่อสถานะเป็น ACTIVE และหรี่ลงเมื่อกลับเป็น INACTIVE มีหน้าเว็บ Web Serial ให้ดูกราฟและปรับค่าจากเบราว์เซอร์ตระกูล Chromium

เทรนให้รู้จักห้องว่าง

ลำดับตามเอกสาร esp_wifi_sensing

  1. สร้าง FSM และเพิ่มช่อง (เช่นช่องของเราเตอร์)
  2. ให้ทุกคนออกจากห้อง ปิดพัดลมที่ส่าย แล้วเรียก esp_wifi_sensing_fsm_train_start()
  3. รอเก็บตัวอย่างพื้นหลัง แล้วเรียก esp_wifi_sensing_fsm_train_stop() จะได้ threshold ของ wander และ jitter ในช่วง 0 ถึง 1 ค่ายิ่งน้อยแปลว่าห้องยิ่งนิ่ง
  4. เริ่มตรวจจับด้วยคำสั่ง start

เทรนตอนห้องว่างและนิ่งจริง ถ้ามีคนนั่งอยู่ตอนเทรน ระบบจะเรียนว่าคนนั้นคือ “ห้องว่าง”

ความเป็นส่วนตัว

CSI ไม่ถ่ายภาพ แต่ยังเป็นการรู้ว่ามีคนอยู่และขยับเมื่อไร esp-csi ยังพูดถึงการใช้ CSI รับรู้การกระทำเล็ก ๆ อย่างการหายใจด้วย จึงควรปฏิบัติแบบเดียวกับกล้อง

  • บอกทุกคนในบ้านว่ามีเซนเซอร์นี้ และจับห้องไหน
  • ไม่วางให้จับพื้นที่ของเพื่อนบ้านหรือห้องเช่าของคนอื่น
  • เก็บผลไว้ในเครื่องหรือในเครือข่ายบ้าน ถ้าส่งขึ้นคลาวด์ ส่งเฉพาะสถานะ ไม่ต้องส่ง CSI ดิบ
  • เปิดปิดได้ง่าย เช่นมีสวิตช์หรือไฟบอกสถานะที่มองเห็น

ข้อผิดพลาดที่เจอบ่อย

  • ไม่มีทราฟฟิก บอร์ดต่อ Wi-Fi แล้วแต่ไม่มี CSI เข้า เพราะไม่มีแพ็กเก็ต ต้อง ping เราเตอร์หรือมีตัวส่ง
  • ทำงานหนักใน CSI callback ทำให้ Wi-Fi สะดุด ส่งเข้า queue แล้วประมวลผลที่อื่น
  • ลืมเปิด Wi-Fi CSI ใน menuconfig ตอนเขียนโปรเจกต์เอง (ตัวอย่างของ Espressif เปิดไว้ให้แล้ว)
  • เทรนตอนมีคนอยู่ หรือพัดลมส่าย ได้ threshold ที่ผิด
  • ย้ายบอร์ดหรือเราเตอร์แล้วไม่เทรนใหม่ สภาพคลื่นเปลี่ยน ผลเพี้ยน
  • ทดสอบตอนคนอื่นเดินไปมา README ของ esp-csi แนะนำให้ทดสอบในที่ที่ไม่มีคนอื่นเคลื่อนไหว

เซนเซอร์ CSI ดีเท่ากับการเทรนของมัน ทุกครั้งที่ห้องเปลี่ยน ให้เทรนใหม่ก่อนสงสัยโค้ด

แหล่งข้อมูล

คำถามที่พบบ่อย

ใช้ ESP32 รุ่นไหนได้บ้าง

esp-radar และ esp_wifi_sensing รองรับ ESP32, S2, S3, C3, C5, C6 และ C61 ต้องใช้ ESP-IDF 5.4 ขึ้นไป Espressif จัดอันดับคุณภาพ CSI ไว้ว่า C5 ดีสุด ตามด้วย C6 แล้วจึง C3 กับ S3 ส่วน ESP32 รุ่นแรกอยู่ท้าย

แทน PIR ได้ไหม

ทำงานต่างกัน PIR จับความร้อนที่ขยับในมุมมองของมัน CSI จับการเปลี่ยนแปลงของคลื่นในพื้นที่ระหว่างตัวส่งกับตัวรับ ไม่ต้องหันหน้าหาคน แต่ต้องเทรนและไวต่อสิ่งแวดล้อมมากกว่า เริ่มจาก PIR ถ้าต้องการของง่ายและนิ่ง

บอกได้ไหมว่าใครเดินผ่าน

ไลบรารีของ Espressif ที่ใช้ในบทนี้ให้แค่ว่ามีการเคลื่อนไหวหรือมีคนอยู่ ไม่ได้ระบุตัวบุคคล

วงจรและโค้ดในบทความทดสอบกับบอร์ดตัวอย่าง บอร์ดต่างรุ่นอาจใช้ขาต่างกัน ตรวจ pinout ของบอร์ดที่ใช้ก่อนต่อไฟเสมอ

อ่านต่อ

#โค้ดกลาง

รีโมตของเล่นด้วย ESP-NOW บอร์ดคุยกันตรง ไม่ต้องมี เราเตอร์

ใช้ ESP-NOW ส่งคำสั่งจาก ESP32 ตัวหนึ่งไปอีกตัวโดยไม่ผ่าน Wi-Fi บ้าน ข้อความไม่เกิน 250 ไบต์ โค้ด MicroPython ตัวส่งตัวรับ ระบบหยุดเมื่อสัญญาณหาย และโหมด long range

อ่าน 8 นาที
#โค้ดเริ่มต้น

ESP32-C5 ชิป ESP32 ตัวแรกที่ต่อ Wi-Fi 5 GHz ได้ ของเล่นเราได้อะไร

ESP32-C5 ผลิตจริงตั้งแต่ เม.ย. 2025 เป็นชิปแรกของ Espressif ที่มี Wi-Fi 6 ทั้ง 2.4 และ 5 GHz พร้อม BLE และ Thread/Zigbee เมื่อไหร่ 5 GHz ช่วยของเล่น เมื่อไหร่ไม่ช่วย

อ่าน 6 นาที
#โค้ดเริ่มต้น

ต่อปุ่มกดกับ ESP32 ให้นิ่ง pull-up และ debounce ด้วย millis()

ทำไมขาอินพุตลอยแล้วอ่านค่ามั่ว pull-up กับ pull-down ต่างกันยังไง ปุ่มเด้งกี่มิลลิวินาที โค้ด debounce ด้วย millis() และขา strapping ที่ไม่ควรต่อปุ่ม

อ่าน 8 นาที