HLK-LD2410S

Arduino library for low power human presence sensor module HLK-LD2410S

License: MIT GitHub stars GitHub forks

Platforms Version Arduino Library PlatformIO

πŸ“ πŸ“„ Official Documents & Driver Files


🧭 Module Types


πŸ“š Table of Contents

⚠️ Important Notes

🧷 Pin Description

Pin description

πŸ”— ESP32 Connection Table

πŸ†” No πŸ“Ÿ LD6002 Pin βš™οΈ Function πŸ“² ESP32 Pin
1 3V3 ⚑ Power Input 3V3
2 GND πŸ›‘ Ground GND
3 TX0 πŸ“€ Serial TX GPIO16
4 RX0 πŸ“₯ Serial RX GPIO17
5 OT2 πŸ“₯IO NC

πŸ“Ÿ Serial Protocols

- Baudrate: 115200_8N1

- Switch the module output mode

Switch the module output mode


bool LD2410S::switchToMinimalMode()
{
    sendFrameHead();

    _serial.write(0x08);
    _serial.write(0x00);
    _serial.write(0x7A);
    _serial.write(0x00);

    const uint8_t param[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    _serial.write(param, sizeof(param));

    sendFrameEnd();

    unsigned long start = millis();
    while (millis() - start < 1000)
    {
        if (_serial.available() >= 14)
        {
            uint8_t ack[14];
            _serial.readBytes(ack, sizeof(ack));
            LD2410S_LOG_LINE("Switch to minimal output mode data:");
            for (uint8_t i = 0; i < sizeof(ack); ++i)
            {
                LD2410S_LOG("%02X ", ack[i]);
            }
            LD2410S_LOG_LINE("");
            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA && ack[6] == 0x7A && ack[7] == 0x01)
            {
                LD2410S_LOG_LINE("Change to minimal data output mode success");
                return true;
            }
        }
    }
    return false;
}

- Read the firmware version command

Read the firmware version command


bool LD2410S::readFirmwareVersion(uint16_t &major, uint16_t &minor, uint16_t &patch)
{
    while (_serial.available())
        _serial.read();

    sendFrameHead();
    const uint8_t cmd[] = {0x02, 0x00, 0x00, 0x00};
    _serial.write(cmd, sizeof(cmd));
    sendFrameEnd();
    _serial.flush();

    unsigned long start = millis();
    while (millis() - start < 1000)
    {
        if (_serial.available() >= 24)
        {
            uint8_t ack[24];
            _serial.readBytes(ack, sizeof(ack));
            LD2410S_LOG_LINE("Firmware version data:");
            for (int i = 0; i < 24; i++)
            {
                LD2410S_LOG("%02X ", ack[i]);
            }
            LD2410S_LOG_LINE();

            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA &&
                ack[6] == 0x00 && ack[7] == 0x01)
            {
                major = (static_cast<uint16_t>(ack[15]) << 8) | ack[14];
                minor = (static_cast<uint16_t>(ack[17]) << 8) | ack[16];
                patch = (static_cast<uint16_t>(ack[19]) << 8) | ack[18];
                LD2410S_LOG_LINE("Read firmware version  Ok");
                LD2410S_LOG("\nmajor = %d, minor = %d, patch = %d", major, minor, patch);
                delay(50);
                return true;
            }
        }
    }
    delay(50);
    return false;
}

- Enable configuration command

Enable configuration command

bool LD2410S::enterConfigMode()
{
    sendFrameHead();
    const uint8_t cmd[] = {0x04, 0x00, 0xFF, 0x00, 0x01, 0x00};
    _serial.write(cmd, sizeof(cmd));
    sendFrameEnd();

    unsigned long start = millis();

    while (millis() - start < 500)
    {
        if (_serial.available() >= 18)
        {
            uint8_t ack[18];
            _serial.readBytes(ack, sizeof(ack));
            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA &&
                ack[6] == 0xFF && ack[7] == 0x01 && ack[10] == 0x03 && ack[11] == 0x00)
            {
                LD2410S_LOG_LINE("Enter config mode Ok");
                return true;
            }
        }
    }
    return false;
}

- End configuration command

End configuration command

bool LD2410S::exitConfigMode()
{
    sendFrameHead();
    const uint8_t cmd[] = {0x02, 0x00, 0xFE, 0x00};
    _serial.write(cmd, sizeof(cmd));
    sendFrameEnd();

    unsigned long start = millis();
    while (millis() - start < 500)
    {
        if (_serial.available() >= 14)
        {
            uint8_t ack[14];
            _serial.readBytes(ack, sizeof(ack));
            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA &&
                ack[6] == 0xFE && ack[7] == 0x01)
            {
                LD2410S_LOG_LINE("Exit config mode Ok");
                return true;
            }
        }
    }
    return false;
}

- Write Serial number command

Write Serial number command


- Read serial number command

Read serial number command

bool LD2410S::readSerialNumber(char *buffer, size_t len)
{
    while (_serial.available())
        _serial.read();

    if (len < 9)
        return false;

    delay(100);

    sendFrameHead();
    const uint8_t cmd[] = {0x02, 0x00, 0x11, 0x00};
    _serial.write(cmd, sizeof(cmd));
    sendFrameEnd();
    _serial.flush();

    unsigned long start = millis();
    while (millis() - start < 1000)
    {
        if (_serial.available() >= 24)
        {
            uint8_t ack[24];
            _serial.readBytes(ack, sizeof(ack));

            LD2410S_LOG_LINE("Serial number data: ");
            for (int i = 0; i < 24; ++i)
                LD2410S_LOG("%02X ", ack[i]);
            LD2410S_LOG_LINE();

            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA &&
                ack[6] == 0x11 && ack[7] == 0x01 &&
                ack[8] == 0x00 && ack[9] == 0x00)
            {
                for (uint8_t i = 0; i < 8; i++)
                    buffer[i] = static_cast<char>(ack[12 + i]);
                buffer[8] = '\0';
                delay(50);
                return true;
            }
        }
    }
    delay(50);
    return false;
}

- Write generic parameter commands

Write generic parameter commands


bool LD2410S::writeGenericParametersCommand()
{
    const uint8_t farthest_distance[6] = {0x05, 0x00, 0x01, 0x00, 0x00, 0x00};    // 1m
    const uint8_t nearest_distance[6] = {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00};     // 0.0m
    const uint8_t delay_time[6] = {0x06, 0x00, 0x0A, 0x00, 0x00, 0x00};           // 10s
    const uint8_t freq_status_report[6] = {0x02, 0x00, 0x28, 0x00, 0x00, 0x00};   // 4.0 Hz
    const uint8_t freq_distance_report[6] = {0x0C, 0x00, 0x28, 0x00, 0x00, 0x00}; // 4.0Hz
    const uint8_t response_speed[6] = {0x0B, 0x00, 0x0A, 0x00, 0x00, 0x00};       // response normal

    sendFrameHead();

    const uint8_t cmd[] = {0x26, 0x00, 0x70, 0x00};
    _serial.write(cmd, sizeof(cmd));
    _serial.write(farthest_distance, sizeof(farthest_distance));
    _serial.write(nearest_distance, sizeof(nearest_distance));
    _serial.write(delay_time, sizeof(delay_time));
    _serial.write(freq_status_report, sizeof(freq_status_report));
    _serial.write(freq_distance_report, sizeof(freq_distance_report));
    _serial.write(response_speed, sizeof(response_speed));

    sendFrameEnd();
    _serial.flush();

    unsigned long start = millis();

    while (millis() - start < 1000)
    {
        if (_serial.available() >= 14)
        {
            uint8_t ack[14];
            _serial.readBytes(ack, sizeof(ack));
            LD2410S_LOG_LINE("Generic parameters data: ");
            for (int i = 0; i < 14; i++)
            {
                LD2410S_LOG("%02X ", ack[i]);
            }
            LD2410S_LOG_LINE("");
            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA &&
                ack[6] == 0x70 && ack[7] == 0x01)
            {
                LD2410S_LOG_LINE("Write generic parameters Ok");
                return true;
            }
        }
    }
    return false;
}

- Read common parameter commands

Read common parameter commands


bool LD2410S::readCommonParametersCommand(uint32_t &farthest_distance, uint32_t &nearest_distance, uint32_t &delay_time, uint32_t &freq_status, uint32_t &freq_distance, uint32_t &respond_speed)
{
    sendFrameHead();

    const uint8_t cmd[] = {
        0x0E, 0x00, 0x71, 0x00,
        0x05, 0x00, 0x0A, 0x00,
        0x06, 0x00, 0x02, 0x00,
        0x0C, 0x00, 0x0B, 0x00};
    _serial.write(cmd, sizeof(cmd));
    sendFrameEnd();

    unsigned long start = millis();

    while (millis() - start < 1000)
    {
        if (_serial.available() >= 38)
        {
            uint8_t ack[38];
            _serial.readBytes(ack, sizeof(ack));

            LD2410S_LOG_LINE("Commond parameters data: ");
            for (int i = 0; i < 38; i++)
            {
                LD2410S_LOG("%02X ", ack[i]);
            }

            if (ack[0] == 0xFD && ack[1] == 0xFC && ack[2] == 0xFB && ack[3] == 0xFA &&
                ack[6] == 0x71 && ack[7] == 0x01 && ack[8] == 0x00 && ack[9] == 0x00)
            {
                farthest_distance = parseLEUint32(&ack[10]);
                nearest_distance = parseLEUint32(&ack[14]);
                delay_time = parseLEUint32(&ack[18]);
                freq_status = parseLEUint32(&ack[22]);
                freq_distance = parseLEUint32(&ack[26]);
                respond_speed = parseLEUint32(&ack[30]);

                LD2410S_LOG("\nfarthest_distance = %d", farthest_distance);
                LD2410S_LOG("\nnearest_distance = %d", nearest_distance);
                LD2410S_LOG("\ndelay_time = %d", delay_time);
                LD2410S_LOG("\nfreq_status = %d", freq_status);
                LD2410S_LOG("\nfreq_distance = %d", freq_distance);
                LD2410S_LOG("\nrespond_speed = %d\n", respond_speed);

                return true;
            }
        }
    }
    return false;
}

πŸ“¦ Example Code (ESP32)


#include <Arduino.h>
#include "LD2410S.h"

// Pin definitions
constexpr int RX_PIN = 16;
constexpr int TX_PIN = 17;
constexpr size_t SERIAL_NUMBER_BUFFER_SIZE = 16;

// Sensor object
LD2410S ld2410s(Serial1, RX_PIN, TX_PIN);

// Firmware version variables
uint16_t firmwareMajor = 0;
uint16_t firmwareMinor = 0;
uint16_t firmwarePatch = 0;

// Serial number buffer
char serialNumberBuffer[SERIAL_NUMBER_BUFFER_SIZE];

// Common parameters
uint32_t farDistance = 0;
uint32_t nearDistance = 0;
uint32_t delayTime = 0;
uint32_t freqStatus = 0;
uint32_t freqDistance = 0;
uint32_t responseTime = 0;

// Timing variables
unsigned long lastStatusMillis = 0;

void setup() {
  Serial.begin(115200);
  ld2410s.begin();
  delay(1000);

  Serial.println("Starting");

  // Read firmware version
  if (ld2410s.readFirmwareVersion(firmwareMajor, firmwareMinor, firmwarePatch)) {
    Serial.printf("Firmware Version: %d.%d.%d\n", firmwareMajor, firmwareMinor, firmwarePatch);
  } else {
    Serial.println("Failed to read firmware version");
  }

  // Read serial number
  if (ld2410s.readSerialNumber(serialNumberBuffer, sizeof(serialNumberBuffer))) {
    Serial.printf("Serial Number: %s\n", serialNumberBuffer);
  } else {
    Serial.println("Failed to read serial number.");
  }

  // Read common parameters
  if (ld2410s.readCommonParametersCommand(farDistance, nearDistance, delayTime, freqStatus, freqDistance, responseTime)) {
    Serial.println("Read common parameters success");
  } else {
    Serial.println("Failed to read common parameters");
  }

  lastStatusMillis = millis();
}

void loop() {
  ld2410s.loop();

  // Print status every second
  if (millis() - lastStatusMillis >= 1000) {
    Serial.printf("Target Distance: %d cm\n", ld2410s.getDistance());
    Serial.println(ld2410s.isMotionDetected() ? "Motion" : "Static");
    lastStatusMillis = millis();
  }
}
βœ… Result:
Starting
Firmware Version: 1.1.1
Serial Number: 12345678
Read common parameters success
Target Distance: 0 cm
Static
Target Distance: 0 cm
Static
Target Distance: 0 cm
Static
Target Distance: 35 cm
Motion
Target Distance: 35 cm
Motion
Target Distance: 35 cm
Motion
Target Distance: 35 cm
Motion
Target Distance: 35 cm
Motion
Target Distance: 35 cm
Motion