Using HLK LD2451 radar for speed measurment

I could not find anyone using the same module as I am and since im a beginner myself i thought i would post my progress here and maybe it will help someone in the same position as me.

Im trying to make a "SpeedSign" that shows passing cars their current speed. Commercial products pricing usually start at about $1500-2000 and thats not an option for recreational use :slight_smile:

Anyway, i made some code to read the radars serial output and display the raw data. I fount the protocol in a Chinese pdfdocument and used goolge translate to translate it to english. http://h.hlktech.com/download/HLK-LD2451-24G/1/LD2451%20%E4%B8%B2%E5%8F%A3%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE%20V1.03.pdf

And here is my experimental code to read the data from the radar module. Perhaps someone could make it nicer and more efficient or have a better way to find the start of the dataframe.

/*
 * 
 * Frame header: 4 bytes - 0xF4 0xF3 0xF2 0xF1 
 * Data length in frame: 2 bytes
 * In-frame data
 *  Target quantity: 1 byte
 *  Alarm information: 1 byte (target aproacing = 01)
 *  Angle in degrees = reported value - 0x80: 1 byte
 *  Distance in meters: 1 byte
 *  Speed direction (01 = approach, 00 = away): 1 byte
 *  Speed (in km/h, max 120): 1 byte
 *  Signal to noise ratio: 0-255: 1 byte
 *  
 *  In-frame data is sent for each target (max 5)
 *  
 *  End frame: 4 bytes - 0xF8 0xF7 0xF6 0xF5
 * 
*/

#include<SoftwareSerial.h>
SoftwareSerial Serial1(2,3);
int j=0;


void setup()
{
  Serial.begin(115200);
  delay(100);
  Serial.println("RadarTest");
  Serial1.begin(115200);
  Serial.println("Started dataread");
}

void loop()
{
  byte response[] = {0xF4, 0xF3, 0xF2, 0xF1 }; //Expected response from radar.
  if(Serial1.available()) {
      int temp = Serial1.read();
      if(temp!=response[j]) { //Check if read data matches with expected response
        Serial.print("Read fail Data = "); //Debug //We did not get the response we expected in the order that we expected
        Serial.println(temp, HEX); //Debug
        Serial.print("J = "); //Debug
        Serial.println(j);  //Debug
        j=0; //Start over, looking for correct byte 0
        return(0);
      }
      else { 
        j++;
        Serial.print("Read ok, Data = "); //Debug
        Serial.println(temp, HEX); //Debug
        Serial.print("J = "); //Debug
        Serial.println(j); //Debug
      }
      if(j>3) {  //Now we have the 4 message startbytes.
          readData(); //Read dataframe
          j=0; //Start over looking for the 4 startbytes.
      }
  }    
}

void readData() {
  int messageSize=0, i=0;
  byte dataSize[2];
  if(Serial1.available()) {
     Serial1.readBytes(dataSize, 2); //The next 2 bytes tells the size in bytes of the dataframe thata follows
  }
  Serial.print("Messagesize 1:"); //Debug
  Serial.print(dataSize[0]); //Debug
  Serial.print(" Messagesize 2:"); //Debug
  Serial.println(dataSize[1]); //Debug
  messageSize = word(dataSize[1], dataSize[0]);
  Serial.print("messageSize = "); //Debug
  Serial.println(messageSize); //Debug
  messageSize = messageSize+4; //Add the 4 "end of message" bytes to the total length
  byte data[messageSize];
  if(Serial1.available()) {
     Serial1.readBytes(data, messageSize); //Read all the data and the 4 endbytes
  }
  while((messagesize)>0) {  //Display all the data in hex format
      Serial.print((String)"Data["+i+"] = ");
      Serial.println(data[i], HEX); 
      i++;
      messagesize--;
  }
}

A web search for "HLK LD2451 Arduino" turns up some interesting results, such as this Arduino library, with an example, and this human tracking project.

You might find some helpful information in those links.

Yeah, i looked at that one too. Unfortunately its not the same protocol and im not confident enough in C programming to modify the libraryfiles.

Which link are you referring too?

The library should work without modification and the code could hardly be simpler. Why do you think you need to do modify it?

Both of them are for the ld2450. And that module uses a completely different protocol to communicate then the ld2451 so i dont see how the library could work?

Which you have not adequately documented. Please post your English translations of the Chinese data sheets.

Both protocols are clearly UART serial. and from a glance at the library and the linked Chinese data sheet, very simple. I agree that the library will need a few mods, though.

Here is a more application focused manual: https://www.laskakit.cz/user/related_files/hlk-ld2451_user_manual_v1-0.pdf

Protocol and tech details, Android and iOS app: HLK-LD2451-24G - Sensor module - Millimeter wave radar Module - LD2451|24G后方来车状态提醒雷达模组 - Hi_Link - Shenzhen Hilink Electronics

https://forum.allaboutcircuits.com/attachments/hlk-ld2451-user-manual-v1-0-pdf.331067/?hash=29a5ba50270672c45a622d80e5d02710

New users can't attach files. That's why I included a link to the Chinese original. Just run it through google translate and you're set.

If i was to cut and paste the Chinese translation all the formatting would be lost. And the structure of the dataframe is documented in my code.

I've attached an English translation of the HLK-LD2451 serial protocol. It looks straightforward.

HLK-LD2451_serial_protocol.pdf (787.9 KB)

As for finding the header of the return response, I would read the input stream byte by byte, looking for the 0xF4 byte, then check that the next is 0xF3, etc. until all four are found, similar to what you are doing but without the intermediate printing. Then input the rest of the stream into a short buffer and interpret.

The library for the HLK-LD2450 reads in an entire record, checks the header and the terminator at the same time, and if those are correct, gets the data out of the middle. The protocol is different from the HLK-LD2451 in only minor details.

Software Serial is totally unreliable at 115200, if it works at all. For this project, you really need to use an Arduino with at least two hardware serial ports (or hardware serial plus serial USB).

I hear you. Im only using software serial for debugging purposes. In the final project only one serialport is used.

Hey, good work.

I'm working with this radar too. Do you know if it's possible to disable the Bluetooth functionality? In my application, the radar will be read with a microcontroller, but I'm afraid someone could restart or changing the parameters through the app.

I have not found a way to disable the bluetooth interface. However i think the module is cheap enough to try and desolder the bluetooth chip and see if it still works as expected.

As always, I'm amazed to find someone else has the same idea and has done a lot of the hard work for me. :slight_smile:

If anyone wants the Android app from a non-sketchy website, it appears to be available now from the Google Play store.

I also wanted to share the OEM's Google Drive folder which contains documentation (in English) on many of their radar module products.
https://drive.google.com/drive/folders/16h1POBPM-CN3x7FaBTZa6IErEnPA2w4d

I attempted to purchase the HLK-LD2415H, which is marketed specifically for speed measurement, but it is much more expensive and also my order has not shipped. It is also marked as "discontinued" from some sources. I am wondering if the 2451 is a more recent replacement.

I contacted the manufacturer, who replied that there is a way to disable the Bluetooth feature via UART.

It's the same command used in the LD2410B protocol.

Hi, the app works, however from the serial seems that too few data is received. Does anyone have had success ?

I have no problem with missing data. What baudrate are you using and do you have a hardware serialport or are you using softserial?

Hi, I'm using softserial for monitoring @9600 while radar is on hardware port @115200. I' m using an esp8266. Is a weird behaivour

Also tried on arduino UNO, looks like that no data is sent between header and tail.

I've tried this:

#include <SoftwareSerial.h>
SoftwareSerial Serial1(2, 3);
int j = 0;

void setup() {
Serial.begin(115200);
delay(100);
Serial.println("RadarTest");
Serial1.begin(115200);
Serial.println("Started dataread");
}

void loop() {
byte response[] = {0xF4, 0xF3, 0xF2, 0xF1}; // Expected response from radar.
if (Serial1.available()) {
int temp = Serial1.read();
if (temp != response[j]) { // Check if read data matches with expected response
Serial.print("Read fail Data = "); // Debug
Serial.println(temp, HEX); // Debug
Serial.print("J = "); // Debug
Serial.println(j); // Debug
j = 0; // Start over, looking for correct byte 0
return;
}
else {
j++;
Serial.print("Read ok, Data = "); // Debug
Serial.print(temp, HEX); // Debug
Serial.print(" J = "); // Debug
Serial.println(j); // Debug
}
if (j > 3) { // Now we have the 4 message startbytes.
readData(); // Read dataframe
j = 0; // Start over looking for the 4 startbytes.
}
}
}

void readData() {
int messageSize = 0, i = 0;
byte dataSize[2];
if (Serial1.available()) {
Serial1.readBytes(dataSize, 2); // The next 2 bytes tell the size in bytes of the dataframe that follows
}
messageSize = word(dataSize[1], dataSize[0]);
messageSize = messageSize + 4; // Add the 4 "end of message" bytes to the total length
byte data[messageSize];
Serial.print(" messagesize ");
Serial.println(messageSize);

// Read the data between the start and end sequences
if (Serial1.available()) {
Serial1.readBytes(data, messageSize); // Read all the data and the 4 endbytes
}

// Display only the data between the start (0xF4 0xF3 0xF2 0xF1) and end (0xF8 0xF7 0xF6 0xF5) sequences
bool inFrame = false;
Serial.print(">>>> "); // Start sequence

for (int i = 4; i < messageSize - 4; i++) {
// Look for the end frame sequence

if (i + 3 < messageSize && data[i] == 0xF8 && data[i+1] == 0xF7 && data[i+2] == 0xF6 && data[i+3] == 0xF5) {

  Serial.print(" end ");      
  break; // Stop when we find the end sequence
}

// Display data between the start and end sequences
Serial.print(data[i], HEX);
Serial.print(" ");

}

Serial.println(" <<<< "); // End sequence

Serial.println(" ");
byte response[] = {0xF8, 0xF7, 0xF6, 0xF5}; // Expected response from radar.

for (int x=messageSize-4; x < messageSize ; x++){
if (data[x] != response[x]) { // Check if read data matches with expected response
Serial.print("Read fail Data = "); // Debug
Serial.println(data[x], HEX); // Debug
Serial.print("x = "); // Debug
Serial.println(x); // Debug
x = 0; // Start over, looking for correct byte 0
return;
}
else {
j++;
Serial.print("Read ok, Data = "); // Debug
Serial.print(data[x], HEX); // Debug
Serial.print(" x = "); // Debug
Serial.println(x); // Debug
}
}

}

But I can only get either nothingh or too little data between head and tail:
Read ok, Data = F8 x = 0
Read ok, Data = F7 x = 1
Read ok, Data = F6 x = 2
Read ok, Data = F5 x = 3
Read ok, Data = F4 J = 1
Read ok, Data = F3 J = 2
Read ok, Data = F2 J = 3
Read ok, Data = F1 J = 4
messagesize 4

<<<<