物联网 毫米波雷达传感器 RCWL-0516:人体存在检测实战
你有没有遇到过这种场景:人坐在书桌前一动不动,传感器就判定”没人”,把灯给关了?
这就是传统 PIR(红外人体热释电)传感器的老毛病——它检测的是人体热量变化,你不动,它就”瞎”。
今天要聊的 RCWL-0516 毫米波雷达传感器,正好解决了这个痛点。它用的是多普勒雷达原理,只要你在,哪怕你只是在打瞌睡、微微呼吸,它都能感知到。
这篇文章,咱们从原理讲到实战,用 Arduino 和 ESP32 搭建一套完整的人体存在检测系统。
RCWL-0516 是什么?
RCWL-0516 是一块基于 3.15 GHz 微波多普勒雷达 的运动检测模块。它通过发射微波信号并接收反射信号,比较两者的频率差(多普勒频移)来判断是否有物体在移动。
跟 PIR 红外传感器相比,毫米波雷达有几个明显优势:
| 特性 | RCWL-0516 雷达 | PIR 红外 |
|---|---|---|
| 检测原理 | 多普勒微波 | 红外热辐射变化 |
| 穿透能力 | 可穿透塑料、木板、薄墙 | 无法穿透,需直视线 |
| 静态检测 | 能检测呼吸等微动 | 静止后很快判定无人 |
| 检测距离 | 5-7 米可调 | 通常 3-5 米 |
| 温度影响 | 不受环境温度影响 | 高温环境灵敏度下降 |
| 隐蔽安装 | 可以藏在天花板/墙内 | 需要露在外面 |
硬件清单
| 器件 | 数量 | 说明 |
|---|---|---|
| RCWL-0516 传感器模块 | 1 | 核心检测模块 |
| ESP32 开发板 | 1 | 主控(也可用 Arduino Uno) |
| 面包板 + 杜邦线 | 若干 | 接线用 |
| LED 模块 | 1 | 状态指示(或直接用板载 LED) |
| 100kΩ 电阻 | 1 | 可选,用于调整检测距离 |
| USB 数据线 | 1 | 供电和烧录程序 |
RCWL-0516 模块上有 5 个引脚:
+---+
| |
| 3V3 ← 3.3V 输出(可给外部供电)
| VIN ← 4-28V 电源输入
| GND ← 地线
| OUT ← 数字输出:检测到目标 = HIGH(3.3V),无目标 = LOW(0V)
| CDS ← 光敏电阻输入:加电阻或光敏元件可白天禁用
+---+
原理解析:多普勒效应怎么工作?
RCWL-0516 的核心原理其实不复杂,一句话概括就是:发射 → 反射 → 频率偏移检测。
- 模块内部的微波振荡器产生 3.15 GHz 的连续波
- 电磁波通过 PCB 天线向外辐射
- 遇到移动物体后,反射波频率发生变化(多普勒频移)
- 内部电路比较发射波和反射波的频率差
- 如果频率差超过阈值,判定为”有运动”,OUT 引脚输出 HIGH
多普勒频移公式:
Δf = 2 × v × f₀ / c
其中 v 是目标速度,f₀ 是发射频率,c 是光速。哪怕人体呼吸时胸口起伏只有几毫米,这个微小的速度变化也会被 3.15 GHz 的电磁波放大,产生可检测的频率差。
这就是为什么 RCWL-0516 能检测到”几乎不动”的人。
接线:RCWL-0516 + ESP32
接线非常简单,就三根线:
RCWL-0516 ESP32
VIN ────▶ 3.3V (或 5V)
GND ────▶ GND
OUT ────▶ GPIO4 (任意数字引脚)
CDS ────▶ 悬空 或 接光敏电阻
注意:RCWL-0516 的 VIN 支持 4-28V 宽电压输入,但用 ESP32 时直接接 3.3V 也能工作(模块内部有稳压电路)。如果接 5V,检测灵敏度会稍微高一些。
实战一:基础检测(Arduino)
最基础的用法:检测到人 → 串口打印信息 + 点亮 LED。
// RCWL-0516 基础人体存在检测
// 硬件:RCWL-0516 + Arduino Uno
const int SENSOR_PIN = 2; // RCWL-0516 OUT 接 Arduino D2
const int LED_PIN = 13; // 板载 LED
void setup() {
Serial.begin(115200);
pinMode(SENSOR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
Serial.println("RCWL-0516 人体存在检测启动...");
Serial.println("等待传感器初始化...");
delay(3000); // 给传感器 3 秒初始化时间
}
void loop() {
int sensorValue = digitalRead(SENSOR_PIN);
if (sensorValue == HIGH) {
digitalWrite(LED_PIN, HIGH);
Serial.println("[存在] 检测到人体活动!");
} else {
digitalWrite(LED_PIN, LOW);
Serial.println("[离开] 无人检测");
}
delay(500); // 500ms 采样间隔
}
这段代码跑起来后,你在传感器前面挥手、走动、甚至只是坐着动一下手指,串口就会打印 [存在]。
实战二:ESP32 + 防误触滤波
RCWL-0516 有一个常见问题:输出信号有时会抖动,短时间内反复 HIGH-LOW 切换。我们通过简单的时间窗口滤波来解决。
// RCWL-0516 ESP32 版:带防误触滤波
const int SENSOR_PIN = 4; // OUT 接 GPIO4
const int LED_PIN = 2; // 板载 LED
const int LED_BUILTIN = 13;
// 滤波参数
const unsigned long PRESENCE_CONFIRM_MS = 2000; // 确认"有人"需持续 2 秒
const unsigned long ABSENCE_CONFIRM_MS = 10000; // 确认"无人"需持续 10 秒
bool currentState = false; // 当前判定的存在状态
unsigned long lastChangeTime = 0; // 上次状态变化时间
void setup() {
Serial.begin(115200);
pinMode(SENSOR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
Serial.println("=== RCWL-0516 ESP32 人体存在检测 ===");
Serial.println("防误触滤波已启用");
delay(3000);
}
void loop() {
bool rawSignal = (digitalRead(SENSOR_PIN) == HIGH);
unsigned long now = millis();
if (rawSignal && !currentState) {
// 从"无人"检测到"有人"信号
if (now - lastChangeTime >= PRESENCE_CONFIRM_MS) {
currentState = true;
Serial.println("[✅ 确认] 检测到人体存在!");
digitalWrite(LED_PIN, HIGH);
digitalWrite(LED_BUILTIN, HIGH);
lastChangeTime = now;
}
}
else if (!rawSignal && currentState) {
// 从"有人"检测到"无人"信号
if (now - lastChangeTime >= ABSENCE_CONFIRM_MS) {
currentState = false;
Serial.println("[❌ 确认] 人体已离开");
digitalWrite(LED_PIN, LOW);
digitalWrite(LED_BUILTIN, LOW);
lastChangeTime = now;
}
}
// 状态持续时重置计时器
if (rawSignal == currentState) {
lastChangeTime = now;
}
delay(100);
}
这段代码的逻辑:
- 必须连续 2 秒检测到 HIGH,才判定”有人”(防止误触发)
- 必须连续 10 秒检测到 LOW,才判定”无人离开”(防止呼吸间隙误判离开)
- 每次信号与当前状态一致时,重置计时器
你可以根据实际环境调整这两个时间阈值。
实战三:ESP32 + MQTT 上报(智能家居集成)
这才是真正有用的——把检测结果发到 MQTT Broker,让 Home Assistant 或其他智能家居平台来处理。
// RCWL-0516 + ESP32 + MQTT → 智能家居人体存在传感器
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi 配置
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// MQTT 配置
const char* mqtt_server = "192.168.1.100"; // 你的 MQTT Broker 地址
const int mqtt_port = 1883;
const char* mqtt_user = "mqtt_user";
const char* mqtt_password = "mqtt_password";
const int SENSOR_PIN = 4;
const char* mqtt_topic_presence = "home/sensor/presence/office";
WiFiClient espClient;
PubSubClient mqttClient(espClient);
// 滤波
bool presenceState = false;
unsigned long stateChangeTime = 0;
const unsigned long ON_DELAY = 2000;
const unsigned long OFF_DELAY = 10000;
void setup() {
Serial.begin(115200);
pinMode(SENSOR_PIN, INPUT);
// 连接 WiFi
WiFi.begin(ssid, password);
Serial.print("连接 WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi 已连接!");
// 配置 MQTT
mqttClient.setServer(mqtt_server, mqtt_port);
mqttClient.setKeepAlive(30);
connectMQTT();
delay(3000); // 传感器初始化
}
void connectMQTT() {
while (!mqttClient.connected()) {
String clientId = "ESP32-Presence-" + String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
Serial.println("MQTT 已连接");
// 发布离线状态
mqttClient.publish(mqtt_topic_presence, "OFFLINE", true); // retain
} else {
Serial.print("MQTT 连接失败, rc=");
Serial.println(mqttClient.state());
delay(3000);
}
}
}
void loop() {
if (!mqttClient.connected()) {
connectMQTT();
}
mqttClient.loop();
bool raw = (digitalRead(SENSOR_PIN) == HIGH);
unsigned long now = millis();
if (raw && !presenceState) {
if (now - stateChangeTime >= ON_DELAY) {
presenceState = true;
mqttClient.publish(mqtt_topic_presence, "ONLINE", true);
Serial.println("[MQTT] 发布: ONLINE (有人)");
stateChangeTime = now;
}
}
else if (!raw && presenceState) {
if (now - stateChangeTime >= OFF_DELAY) {
presenceState = false;
mqttClient.publish(mqtt_topic_presence, "OFFLINE", true);
Serial.println("[MQTT] 发布: OFFLINE (无人)");
stateChangeTime = now;
}
}
if (raw == presenceState) {
stateChangeTime = now;
}
delay(100);
}
在 Home Assistant 中,你可以用 MQTT Discovery 自动发现这个传感器:
# Home Assistant configuration.yaml
binary_sensor:
- platform: mqtt
name: "办公室人体存在"
state_topic: "home/sensor/presence/office"
payload_on: "ONLINE"
payload_off: "OFFLINE"
device_class: occupancy
qos: 1
搞定之后,你的 Home Assistant 就会多一个”办公室人体存在”传感器,比 PIR 灵敏得多,不会动不动就判定”无人”。
进阶:检测距离调整
RCWL-0516 默认检测距离约 5-7 米。如果你想在更小的空间使用(比如卫生间、衣柜),可以调整检测距离。
方法一:加装屏蔽罩
最简单粗暴——用金属箔(铝箔)做一个罩子盖住传感器天线面,只留一个方向开口。这能显著缩小检测范围。
方法二:修改电容
模块上的 C-TM 电容决定了检测灵敏度。原装通常是 1nF:
- 减小电容 → 降低灵敏度 → 缩短检测距离
- 增大电容 → 提高灵敏度 → 增加检测距离
经验值参考:
| C-TM 电容 | 大致检测距离 |
|---|---|
| 0.5nF | ~2-3 米 |
| 1nF (默认) | ~5-7 米 |
| 2nF | ~8-10 米 |
方法三:在 VIN 上加电位器
降低供电电压会降低发射功率,从而缩短检测距离。加一个可调电位器在 VIN 回路中,可以从 4V 调到 9V 来微调。
CDS 引脚:白天自动禁用
RCWL-0516 的 CDS 引脚是用来接光敏电阻的。当环境光足够亮时,传感器自动停止输出 HIGH,避免白天浪费资源。
接法:
CDS 引脚 ──▶ 光敏电阻 ──▶ 5V
│
10kΩ 电阻
│
GND
光线暗时,光敏电阻阻值变大 → CDS 引脚电压低 → 传感器正常工作 光线亮时,光敏电阻阻值变小 → CDS 引脚电压高 → 传感器被禁用
如果你不需要这个功能,让 CDS 引脚悬空就行(默认正常工作)。
常见问题排查
Q1:传感器一直输出 HIGH,从不变 LOW?
可能原因:
- 检测范围内有持续运动物体:风扇转动、窗帘飘动、宠物走动都会触发。建议检查周围环境,或缩短检测距离。
- 传感器故障:用万用表测量 OUT 引脚电压。正常无人时应该接近 0V。
- 供电不足:VIN 电压低于 4V 可能导致工作异常。确保供电在 4-28V 范围内。
Q2:传感器灵敏度太低,检测不到人?
- 检查供电:3.3V 时灵敏度较低,换 5V 试试
- 检查安装方向:雷达波主要从模块正面(元件面)发射,背面灵敏度很低
- 增大 C-TM 电容(见上文”检测距离调整”部分)
Q3:输出信号抖动频繁,状态来回切换?
这是 RCWL-0516 的已知特性。解决方案就是前文实战二中的时间窗口滤波。根据实际环境调整 ON_DELAY 和 OFF_DELAY 的值。
Q4:能穿透墙壁检测隔壁房间的人吗?
理论上可以,但实际效果取决于:
- 墙壁材质(石膏板/木板容易穿透,钢筋混凝土几乎不行)
- 距离(穿透墙壁后有效距离大幅缩短)
- 干扰(隔壁如果有风扇、空调等也会被检测到)
如果你的场景是”检测隔壁是否有人”,建议改用 WiFi 探针或蓝牙 beacon 方案更可靠。
Q5:RCWL-0516 vs LD2410,选哪个?
如果你在做新项目,强烈建议看看 LD2410(24GHz 毫米波雷达)。对比:
| 特性 | RCWL-0516 | LD2410 (24GHz) |
|---|---|---|
| 频率 | 3.15 GHz | 24 GHz |
| 检测精度 | 只能判断有人/无人 | 可区分有人/无人 + 距离信息 |
| 微动检测 | 一般 | 优秀(能检测呼吸心跳) |
| 价格 | ~¥5 | ~¥20 |
| 接口 | 数字 OUT | UART 串口 |
| 推荐场景 | 简单存在检测 | 精细人体存在检测 |
LD2410 是更新一代的方案,适合对精度要求更高的场景。但 RCWL-0516 胜在便宜和简单,入门学习用它足够了。
总结
RCWL-0516 毫米波雷达传感器是入门人体存在检测的最佳选择之一:
- 优点:便宜、接线简单、可穿透障碍物、不受温度影响、能检测微动
- 缺点:信号会抖动、不能提供距离信息、无法区分人和宠物
用本文的三个实战项目,你已经能搭建:
- 基础人体检测(本地指示)
- 带防误触滤波的稳定检测
- MQTT 上报的智能家居集成方案
下一步,你可以把多个传感器部署到不同房间,用 Home Assistant 做全屋人体存在监控;或者结合光照传感器实现”有人且天黑才开灯”的智能照明逻辑。
有问题或想分享你的项目,欢迎在评论区交流!