ESP32 CSI 与 WiFi 感知:单板、双板、数据字段与实验设计
作者 Wu Jun · 更新于 2026-11-02 · 约 6 分钟
ESP32 是最便宜的 CSI 入口之一。Espressif 官方说明所有 ESP32 系列都支持 CSI,包括 ESP32、S2、C3、S3、C5、C6 与 C61 [1]。但“能拿到 CSI”和“能稳定做实验”之间, 还隔着发送端、包速率、LTF 解析、信道与评测协议。
本文按官方 esp-csi 示例和 ESP-IDF 文档,把几条路线、数据格式和边界讲清楚。
1. 三条常见采集路线
| 路线 | 硬件 | 原理与适合场景 |
|---|---|---|
| 单板 + 路由器 | 1 块 ESP32 + AP | ESP32 ping 路由器并接收 CSI;成本最低,但依赖 AP 位置 |
| 双板 + 路由器 | 2 块 ESP32 + AP | 一块发包、另一块接收;适合研究设备间链路 |
| 专用发送/接收 | 至少 2 块开发板 | 发送板持续发包、多块接收;采样可控、部署灵活 |
官方仓库同时提供 csi_recv_router、csi_recv 与 csi_send。单板路线并不是“ESP32 自己向空气发射雷达波”,
而是必须有另一端发送数据包,ESP32 才能从收到的包估计 CSI。
2. 路线一:单 ESP32 + 路由器
这是最省硬件的起点。ESP32 连接路由器后 ping 网关,接收路由器回包并打印 CSI。
git clone https://github.com/espressif/esp-csi.git
cd esp-csi/examples/get-started/csi_recv_router
idf.py set-target esp32s3 # 替换为你自己的芯片
idf.py menuconfig # 配置 Wi-Fi/以太网
idf.py -p /dev/ttyUSB0 flash monitor
macOS 串口通常是 /dev/cu.usbserial-* 或 /dev/cu.SLAB_USBtoUART,不要照抄 Linux 的 /dev/ttyUSB0。
先确认四个基础事实:
- 串口出现
CSI_DATA; len与本文预期格式相符;- RSSI 正常且持续更新;
- 停止 ping 或没有数据流量后,CSI 帧率明显下降。
如果串口只有启动日志没有 CSI,先查 Wi-Fi 是否连上、是否持续发包、CSI 是否启用,而不是直接怀疑解析器。
3. 路线二:两块 ESP32 互发
官方 get-started 示例需要两块开发板:一块烧 csi_send,一块烧 csi_recv。当前 README 建议优先使用
ESP32-C5/C6,并说明两天线距离应大于 1 米;但这不表示旧款 ESP32 不能做 CSI。
# 发送端
cd esp-csi/examples/get-started/csi_send
idf.py set-target esp32c3
idf.py -p /dev/ttyUSB0 flash -b 921600 monitor
# 接收端
cd esp-csi/examples/get-started/csi_recv
idf.py set-target esp32c3
idf.py -p /dev/ttyUSB1 flash -b 921600
# 接收端可视化工具
cd esp-csi/examples/get-started/tools
python -m pip install -r requirements.txt
python csi_data_read_parse.py -p /dev/ttyUSB1
两块板必须使用与芯片匹配的 target。把 esp32c3 当成所有开发板通用参数,是最常见的构建错误。
4. 子载波数不是固定 30–64
ESP-IDF 的 CSI 数据由最多三类 LTF 字段组成:
- LLTF(legacy long training field);
- HT-LTF;
- STBC-HT-LTF。
实际字节数取决于包类型、20/40MHz、STBC、secondary channel 与启用了哪些 LTF。ESP32-S3 官方表中,
len 可以是 128、256、384、380、612 等不同字节数;不能把 len / 2 不加解释地当成独立子载波数,
因为缓冲区可能包含多个 LTF 段 [2]。
解析时必须保留这些元数据:
| 字段 | 作用 |
|---|---|
len |
本帧 CSI 字节数 |
sig_mode / mcs |
包类型与调制 |
bandwidth / secondary_channel |
20/40MHz 与扩展信道 |
stbc |
是否包含 STBC LTF |
first_word_invalid |
某些 ESP32-S3 帧的前 4 字节无效 |
local_timestamp |
估计实际包间隔 |
rssi / noise_floor |
链路质量 |
每个复数样本是 int8 imaginary, int8 real,即官方接口中的两字节有符号值。不要把路由器 CSI 的 int16 I/Q 格式直接套到 ESP32 数据上。
5. 两种 CSV 文本格式
旧款 ESP32 示例通常输出:
type,id,mac,rssi,rate,sig_mode,mcs,bandwidth,...,len,first_word,data
CSI_DATA,0,... ,128,1,"[imag0,real0,imag1,real1,...]"
ESP32-C5/C6 的新示例可能输出:
type,seq,mac,rssi,rate,noise_floor,fft_gain,agc_gain,channel,
local_timestamp,sig_len,rx_state,len,first_word,data
列顺序不同,解析器不能只按固定列号读取。最稳妥的方法是:
- 保存官方一行原始 CSV 作为格式样本;
- 明确检测 header 或
type/seq列; - 对
len和data长度做一致性检查; - 保留原始文本,不要只保存清洗后的幅值。
6. 包速率就是采样率的上限
ESP32 CSI 由收到的包触发,因此没有“固定 100Hz”这种保证。实际独立采样率由发送端速率、信道竞争、 RSSI、包长、省电和串口带宽共同决定。
第一次实验不要先做机器学习。先测:
packets_total
有效 CSI 帧数
首尾 local_timestamp 的持续时间
有效帧数 / 持续时间
包间隔 p50 / p95 / max
RSSI min / mean / max
len 的分布
如果串口绘图导致缓冲跟不上,官方 README 也提示可能出现元素数量不一致或数据混乱。先提高串口速率、 关闭高 CPU 绘图或直接落盘,再判断 CSI 本身是否异常。
7. 一套最小可复现实验
建议从两类场景开始,而不是直接呼吸/心率:
| 场景 | 时长 | 目的 |
|---|---|---|
| 空房基线 | 5 分钟 | 估计环境周期和误报 |
| 静止受试者 | 5 分钟 | 检查微小变化是否存在 |
| 受试者行走 | 5 次,每次 30 秒 | 验证运动包络 |
| 无人/有人交替 | 10 轮 | 计算存在检测误报与漏报 |
每次记录:
- 发送端与接收端 target、固件 commit、ESP-IDF 版本;
- 信道、带宽、TX power、RSSI、noise floor;
- 两块板的距离、朝向和高度;
- 每秒有效帧、最大包间隔、串口丢行;
- 原始 CSV 或二进制流与采集脚本版本。
训练/测试要按 session 或日期切分,不能把连续重叠窗口随机分到两边。
8. 什么能做什么不能做
适合:
- 学习 CSI 幅度/相位与包速率;
- 低成本存在/运动检测;
- ESPHome/Home Assistant 集成验证;
- 采集小规模数据集验证算法。
不要默认声称:
- 任意房间都能测呼吸或心率;
- 完整步行微多普勒;
- 高精度距离、角度或人体成像;
- 一张开发板就能替代专用雷达。
ESPectre 等项目提供了运动感知的工程参考 [3],但其宣传和实际准确率仍必须在自己的场景中验证。
9. ESP32 与 GL-MT6000 的真正差别
| 维度 | ESP32 示例 | GL-MT6000 + mt76 CSI |
|---|---|---|
| 典型带宽 | 20MHz,部分支持 40MHz | 80MHz |
| 频率信息 | 依 LTF/包类型,字节数可变 | 256 子载波/链 |
| 空间链 | 通常单接收天线 | 2 Tx × 4 Rx |
| 发送端 | 需要另一块板或路由器流量 | 独立 AP + 客户端 |
| 采样率 | 由包速率决定 | 本项目约 12.68 个闭合测量组/秒(异常过滤后 12.64) |
| 部署 | 低成本、灵活、单点 | 7×24、覆盖更广、刷机复杂 |
| 适合 | 入门、IoT、短周期实验 | 长期全屋采集与高频率分辨率 |
路由器方案并不是 ESP32 的放大版:二进制格式、链数、CSI 提取方式和采样机制都不同。算法可以共享思路, 但输入维度、时间轴和校准不能直接复用。
10. 从零到第一条曲线
建议顺序:
- 单板 + 路由器跑通
CSI_DATA; - 把一行 CSV 原样保存,确认
len与data元素数; - 计算实际包率与最大间隔;
- 采空房和有人行走各 5 分钟;
- 绘制 RSSI、CSI 幅度和运动包络;
- 最后再尝试呼吸、存在或深度学习。
如果使用多平台 Python 工具,CSIKit 支持 ESP32 等格式;先验证它的版本与列定义是否匹配你的固件。 更多论文与工具见 Awesome Wi-Fi CSI Sensing [4]。
11. 结论
- 所有 ESP32 系列都支持 CSI,但具体 target、包格式和硬件推荐不同;
- 单板路线依赖路由器发包,双板路线需要明确发送端与接收端;
len不是固定子载波数,LLTF/HT-LTF/STBC 会改变字节数;- 采样率由包速率决定,必须从时间戳和有效帧计算;
- ESP32 适合低成本入门和 IoT,不适合直接宣称完整雷达或医疗级体征功能。
参考与数据来源
本文的每条外部结论都标注来源与证据等级(分级标准);标注 E 级的是本项目可复现的实测数据。
- C 级 · 官方资料
espressif/esp-csi — Applications based on Wi-Fi CSI
Espressif Systems
github.com/espressif/esp-csi · 核实: GitHub API 2026-10-29 (stars 1,723; README confirms the complete ESP32 series list and three sender/receiver routes) · 官方 README 原文:“All ESP32 series support CSI, including ESP32 / ESP32-S2 / ESP32-C3 / ESP32-S3 / ESP32-C5 / ESP32-C6 / ESP32-C61.” - C 级 · 官方资料
ESP-IDF — Wi-Fi Channel State Information (ESP32-S3)
Espressif Systems
docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-guides/wifi-driver/wifi-vendor-features.html#wi-fi-channel-state-information · 核实: official docs fetched 2026-10-29 (ESP32-S3 CSI section: LTF/byte-count table and the first_word_invalid note) - C 级 · 官方资料
francescopace/espectre — Wi-Fi CSI motion sensing for ESP32 (ESPHome)
F. Pace
github.com/francescopace/espectre · 核实: GitHub API and official README fetched 2026-10-29 (stars 9,700; GPLv3; ESPHome source path, Direct API port 62587 and supported chips documented) · 官方项目提供 ESPHome、Native MQTT、Matter 与浏览器烧录路线;同一块 ESP32 覆盖一个区域,不识别身份或人数。 - C 级 · 官方资料
NTUMARS/Awesome-WiFi-CSI-Sensing — curated papers and resources
NTU MARS Lab
github.com/NTUMARS/Awesome-WiFi-CSI-Sensing · 核实: GitHub API 2026-10-11 (stars 1129, MIT, last push 2025-07-19) - C 级 · 官方资料
StevenMHernandez/ESP32-CSI-Tool — active/passive CSI extraction for ESP32
S. M. Hernandez
github.com/StevenMHernandez/ESP32-CSI-Tool · 核实: GitHub API 2026-10-11 (stars 571, MIT, last push 2024-07-16)