Introduction
The C4002 is a millimeter-wave radar module based on 24GHz FMCW technology, designed specifically for smart home applications that require precise static human presence detection. The module overcomes the limitation of traditional PIR sensors, which can only detect significant movements, and is capable of simultaneously detecting moving humans as well as stationary/slightly moving humans within an effective detection range of 10×10 meters. It supports motion speed detection, motion direction recognition (approaching/leaving), and ambient light detection. The module features adjustable detection range, intelligently filters environmental interference through noise floor acquisition, and offers flexible and configurable output modes. It serves as an ideal core component for implementing true unattended sensing and control systems in smart home product solutions.
Wide-Range Multi-State Detection with Controllable IO Output
With an effective detection range of 10x10 meters, the C4002 can fully cover an entire room. Whether it detects large movements during walking or subtle motions while stationary, the module is capable of outputting detection signals. Additionally, through the configurable output modes (such as presence, motion, stationary, and micro-motion states) available via the OUT interface, it can directly control external devices, ensuring operation only when "actual human presence is detected," thereby enhancing convenience and energy efficiency.
Intelligent Anti-Interference, Stable & Reliable, No Debugging Needed
The module features built-in background noise collection. In a new environment, it automatically learns and establishes a background noise model, effectively filtering common interferences like swaying curtains, AC operation, or shaking plants. This significantly reduces false alarms and ensures long-term, stable system operation.
Flexibly Adjustable Detection Range for Various Scenarios
You can flexibly adjust the detection range according to your actual application needs. Whether it is overall monitoring in a large living room or targeted sensing in a small bathroom, the detection boundaries can be intelligently adapted to suit various spatial layouts.
Development Ecosystem & Compatibility
The C4002 is fully compatible with mainstream open-source hardware platforms such as Arduino, ESP32, and Raspberry Pi, and can be seamlessly integrated into the Home Assistant smart home system. With its rich resources, it enables rapid functional validation and system integration, significantly shortening the R&D cycle.
Features
High Detection Capability: With a motion detection range of up to 11 meters and a stationary (micro-motion) detection range of up to 10 meters, the detection angle is 120° × 120°, providing extensive coverage.
Intelligent Interference Filtering: Equipped with built-in ambient noise collection and learning functions, it effectively filters out environmental interferences such as curtain sway and air conditioner operation, significantly reducing false alarm rates.
Multi-Dimensional Information Output: In addition to motion and stationary/micro-motion status, it also supports motion speed detection, movement direction recognition (approaching/retreating), and ambient light detection.
Applications
Smart Lighting Control: Achieves precise automated "Lights on when occupied, off when vacant" control.
Constant Temperature & Humidity Control: Automatically adjusts air conditioning and environmental devices in living rooms, studies, etc., based on human presence.
Sleep Management: Monitors stationary state of occupants in bedrooms, automatically switches to sleep mode, and controls devices like night lights and AC.
Security Monitoring: Detects abnormal movement or intrusion, triggering alarms or recording.
Care Systems: Monitors whether a person is stationary or making micro-movements in a room, sending alerts upon detecting abnormalities (e.g., prolonged inactivity).
Specifications
Operating Voltage: 3.6 ~ 5.5V
Detection Capability: Motion, Micro-Motion/Stationary Human Body
Max Detection Distance: Motion 11m, Micro-Motion/Stationary 10m
Detection Angle: 120° x 120°
Output Interface: OUT (Configurable IO), UART
Operating Frequency: 24GHz ~ 24.25GHz
Light Detection: 0 ~ 50 lux
Operating Temperature: -20 ~ 85 ˚C
Product Dimensions: 22mm x 26mm
Pinout
| Pin | Description |
|---|---|
| VIN | DC 3.6V-5.5V Input |
| GND | Ground |
| RX | Sensor Serial Port Receive |
| TX | Sensor Serial Port Transmit |
| OUT | Level Output |
Tutorial
Prepare
Hardware Prepare
- DFRduino Leonardo (SKU:DFR0221) ×1
- C4002 mmWave Motion & Static Presence Module(SKU:SEN0691)×1
Software Prepare
- Download Arduino IDE: Click to download Arduino IDE
- Download the C4002 Library: Click to download DFRobot_C4002
Wire Diagram

Example Code
- Upload the following code and open Serial monitor to check the output
/*!
* @file getAllResults.ino
* @brief This is an example to show how to use the DFRobot_C4002 library to get all the results of the C4002 sensor.
* @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com)
* @license The MIT License (MIT)
* @author JiaLi([email protected])
* @version V1.0
* @date 2025-11-04
* @url https://github.com/DFRobot/DFRobot_C4002
*/
#include "DFRobot_C4002.h"
#if defined(ESP8266) || defined(ARDUINO_AVR_UNO)
SoftwareSerial mySerial(4, 5);
DFRobot_C4002 c4002(&mySerial, 115200);
#elif defined(ESP32)
DFRobot_C4002 c4002(&Serial1, 115200, /*D2*/ D2, /*D3*/ D3);
#else
DFRobot_C4002 c4002(&Serial1, 115200);
#endif
void setup()
{
Serial.begin(115200);
// Initialize the C4002 sensor
while (c4002.begin() != true) {
Serial.println("C4002 begin failed!");
delay(1000);
}
Serial.println("C4002 begin success!");
delay(50);
// Set the run led to off
if (c4002.setRunLedState(eLedOff)) {
Serial.println("Set run led success!");
} else {
Serial.println("Set run led failed!");
}
delay(50);
// Set the out led to off
if (c4002.setOutLedState(eLedOff)) {
Serial.println("Set out led success!");
} else {
Serial.println("Set out led failed!");
}
delay(50);
// Set the Resolution mode to 80cm.
if (c4002.setResolutionMode(eResolution80Cm)) {
Serial.println("Set resolution mode success!");
} else {
Serial.println("Set resolution mode failed!");
}
delay(50);
/**
* Note:
* 1. eResolution80Cm: This indicates that the resolution of the "distance gate" is 80cm.
* With a resolution of 80 cm, it supports up to 15 distance gates, with a maximum distance of 11.6 meters.
* 2. eResolution20Cm: This indicates that the resolution of the "distance gate" is 20cm.
* With a resolution of 20 cm, it supports up to 25 distance gates, with a maximum distance of 4.9 meters
*/
// Set the detect range to 0-1100 cm
uint16_t clostRange = 0;
uint16_t farRange = 1100;
if (c4002.setDetectRange(clostRange, farRange)) { // Max detect range(0-1100cm)
Serial.println("Set detect range success!");
} else {
Serial.println("Set detect range failed!");
}
delay(50);
// Set the light threshold to 0 lux.range: 0-50 lux
if (c4002.setLightThresh(0)) {
Serial.println("Set light threshold success!");
} else {
Serial.println("Set light threshold failed!");
}
delay(50);
uint8_t gateState[15] = { C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE };
// Resolution mode:eResolution20Cm,This means that the number of 'distance gates' we can operate is 25
// uint8_t gateState[25] = {C4002_DISABLE,C4002_DISABLE,C4002_ENABLE,...,C4002_ENABLE,C4002_DISABLE};
if (c4002.configureGate(eMotionDistGate, gateState)) { // Operation motion distance gate
Serial.println("Enable motion distance gate success!");
}
delay(50);
if (c4002.configureGate(ePresenceDistGate, gateState)) { // Operation presence distance gate
Serial.println("Enable presence distance gate success!");
}
delay(50);
// Set the target disappear delay time to 1s,range: 0-65535s
if (c4002.setTargetDisappearDelay(1)) {
Serial.println("Set target disappear delay time success!");
} else {
Serial.println("Set target disappear delay time failed!");
}
delay(50);
// Set the report period to 10 * 0.1s = 1s
if (c4002.setReportPeriod(10)) {
Serial.println("Set report period success!");
} else {
Serial.println("Set report period failed!");
}
/* note: Calibration and obtaining all data must have a set cycle */
}
void loop()
{
// Get all the results of the C4002 sensor,Default loop execution
sRetResult_t retResult = c4002.getNoteInfo();
if (retResult.noteType == eResult) {
Serial.println("------- Get all results --------");
// get the light intensity
float light = c4002.getLightIntensity();
Serial.print("Light: ");
Serial.print(light);
Serial.println(" lux");
// get Target state
eTargetState_t targetState = c4002.getTargetState();
Serial.print("Target state: ");
if (targetState == eNoTarget) {
Serial.println("No Target");
} else if (targetState == ePresence) {
Serial.println("Static Presence");
} else if (targetState == eMotion) {
Serial.println("Motion");
}
// get presence count down
uint16_t presenceGateCount = c4002.getPresenceCountDown();
Serial.print("Presence distance gate count down: ");
Serial.print(presenceGateCount);
Serial.println(" s");
// get Presence distance gate target info
sPresenceTarget_t presenceTarget = c4002.getPresenceTargetInfo();
Serial.print("Presence distance: ");
Serial.print(presenceTarget.distance);
Serial.println(" m");
Serial.print("Presence energy: ");
Serial.println(presenceTarget.energy);
// get motion distance gate index
sMotionTarget_t motionTarget = c4002.getMotionTargetInfo();
Serial.print("Motion distance: ");
Serial.print(motionTarget.distance);
Serial.println(" m");
Serial.print("Motion energy: ");
Serial.println(motionTarget.energy);
Serial.print("Motion speed: ");
Serial.print(motionTarget.speed);
Serial.println(" m/s");
Serial.print("Motion direction: ");
if (motionTarget.direction == eAway) {
Serial.println("Away!");
} else if (motionTarget.direction == eNoDirection) {
Serial.println("No Direction!");
} else if (motionTarget.direction == eApproaching) {
Serial.println("Approaching!");
}
Serial.println("--------------------------------");
}
delay(50);
}
Result

- Upload the following code and open Serial monitor to check the output- After uploading, leave the room within 10s and wait 40s for ambient noise collection- Check the ambient noise threshold via the Serial monitor
/*!
* @file autoEnvCalibration.ino
* @brief This is an example to demonstrate how to use the DFRobot_C4002 library to perform environmental calibration.
* @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com)
* @license The MIT License (MIT)
* @author JiaLi([email protected])
* @version V1.0
* @date 2025-11-04
* @url https://github.com/DFRobot/DFRobot_C4002
*/
#include "DFRobot_C4002.h"
/* ---------------------------------------------------------------------------------------------------------------------
* board | MCU | Leonardo/Mega2560/M0 | UNO | ESP8266 | ESP32 | microbit | m0 |
* VCC | 5V | 5V | 5V | 5V | 5V | X | 5V |
* GND | GND | GND | GND | GND | GND | X | GND |
* RX | TX | Serial1 TX1 | 5 | 5/D6 | 25/D2 | X | tx1 |
* TX | RX | Serial1 RX1 | 4 | 4/D7 | 26/D3 | X | rx1 |
* ----------------------------------------------------------------------------------------------------------------------*/
/* Baud rate can be changed */
#if defined(ESP8266) || defined(ARDUINO_AVR_UNO)
SoftwareSerial mySerial(4, 5);
DFRobot_C4002 c4002(&mySerial, 115200);
#elif defined(ESP32)
DFRobot_C4002 c4002(&Serial1, 115200, /*D2*/ D2, /*D3*/ D3);
#else
DFRobot_C4002 c4002(&Serial1, 115200);
#endif
// printDoorThreshold function
void printDoorThreshold(uint8_t *gateData, uint8_t n)
{
Serial.print("Index:\t");
for (int i = 0; i < n; i++) {
Serial.print(i + 1);
Serial.print('\t');
}
Serial.println();
Serial.print("Value:\t");
for (int i = 0; i < n; i++) {
Serial.print(gateData[i]);
Serial.print('\t');
}
Serial.println();
}
void setup()
{
Serial.begin(115200);
// Initialize the C4002 sensor
while (c4002.begin() != true) {
Serial.println("C4002 begin failed!");
delay(1000);
}
Serial.println("C4002 begin success!");
// Turn on the run led and out led
if (c4002.setRunLedState(eLedOn)) {
Serial.println("Set run led success!");
} else {
Serial.println("Set run led failed!");
}
delay(50);
if (c4002.setOutLedState(eLedOn)) {
Serial.println("Set out led success!");
} else {
Serial.println("Set out led failed!");
}
delay(3000);
// Set the report period to 1s
if (c4002.setReportPeriod(10)) {
Serial.println("Set report period success!");
} else {
Serial.println("Set report period failed!");
}
/* note: Calibration and obtaining all data must have a set cycle */
// Start environmental calibration
// Delay time:10s ,Calibration time:30s( 15-65535 s )
c4002.startEnvCalibration(10, 30);
Serial.println("Start environmental calibration:");
/**
* Note:
* 1. The calibration process takes about 30 seconds, and the delay time is 10 seconds.
* 2. When resetting the development board, please find an open area to calibrate it
* 3. When starting the calibration, there should be no one on either side of the sensor
* directly in front of the transmitter, otherwise it will affect the calibration accuracy
* of the sensor
*/
}
void loop()
{
uint8_t gateData[25] = { 0 };
eResolutionMode_t resolutionMode;
//Obtain the calibration results
sRetResult_t retResult = c4002.getNoteInfo();
if (retResult.noteType == eCalibration) {
Serial.print("Calibration countdown:");
Serial.print(retResult.calibCountdown);
Serial.println(" s");
if (retResult.calibCountdown == 0) {
resolutionMode = c4002.getResolutionMode();
int n = resolutionMode == eResolution80Cm ? 15 : 25;
Serial.println("************Environmental Calibration Complete****************");
if (c4002.getDistanceGateThresh(eMotionDistGate, gateData)) {
Serial.println("Motion distance gate threshold:");
printDoorThreshold(gateData, n);
} else {
Serial.println("Get motion distance failed!");
}
if (c4002.getDistanceGateThresh(ePresenceDistGate, gateData)) {
Serial.println("Presence distance gate threshold:");
printDoorThreshold(gateData, n);
} else {
Serial.println("Get presence distance failed!");
}
Serial.println("**************************************************************");
}
}
}
Result

Home Assistant Tutorial
FAQ
-
Q: Abnormal sensor output after ambient noise collection
-
A: Generally, you can troubleshoot by following these steps:
- Check if the current ambient noise threshold is within the normal range:
If the threshold is higher than 50, it indicates potential interference sources in the environment; a preliminary check of the surroundings is recommended.
If the threshold reaches 99, it indicates strong interference; the sensor will likely fail to function correctly, and the output is prone to abnormalities.
- In case of high threshold values, thoroughly investigate and eliminate environmental interference sources before re-collecting ambient noise to ensure the sensor output returns to normal.
[Get one in DFRobot store]( "Get one in DFRobot store")