4907

A reliable human presence sensing with a 24GHz Radar module

The reliable detection of human presence is not easy to achieve. But there is an interesting very small sensor HLK-LD2410(B) for this purpose.. It uses 24GHz FMCW (frequency-modulated continuous wave)  radar technology.
 Unlike infrared or ultrasonic based presence detection modules, this module is able to detect moving targets (people) as well as non-moving, standing people.
 It can be used standalone after setting some parameters via a serial interface. Then it can simply indicate the presence of a person by a connected LED. There is a windows tool for configuration and visualization.
 
 But even more interesting is that the sensor can be a serial connected peripheral hardware to an  ESP32 .  For fast prototyping I used Annex32, a BASIC-Interpreter for ESP32 based SoCs.. Find its helpful documentation  HERE.

I wrote a first test code to visualize the obtained data in a browser window.
The module knows a very conversational "engineering mode" where it displays the reflected energy of different distance ranges.
Very interesting and impressive to see how even a non moving person is detected very accurately by the reflection of the 24GHz radio signal on the breathing body.

Next things to do:
- set the detection sensitivity on the different distance range gates
- use the Neopixel-LEDs of the ATOM matrix to visualize the detected radar signal
- enable a Telegram Bot based messaging if a person is detected in selectable range
- The module is Bluetooth/BLE capable. This could be investigated as an alternative link to the ESP32.

I gathered some more information  about this project HERE
 
My BASIC-script code: 
' HLK-LD2410 RADAR module from Hi-Link connected to an ESP32
' for very reliable detection of moving or non-moving persons

' - Connected via serial2 to an ESP32 (e.g. M5Stack ATOM matrix ESP32pico with 5x5 neopixel matrix)
' - Switches the radar unit to engineering mode to report more details.
' - Selects the data indicating a moving person (= moving target).
' - Selects the data indicating a non-moving but breathing person (= static target)

' - Creates a Webpage to ..
' -- Visualize the energy of the moving targets in 9 distance ranges by bar graphs
' -- Visualize the energy of the static targets in 7 distance ranges by bar graphs
' -- Visualize the internal detection for a moving target by a LED symbol
' -- Visualize the internal detection for a static target by a LED symbol
'
' Find ANNEX32 at  https://flasher.cicciocb.com/dist/index.html

Version$ = "1.0" ' DB9JG 2023/03/

RX_pin       = 21   'pin for serial2 input comming from LD2410 TX-pin
TX_pin       = 25   'pin for serial2 output going to LD2410 RX-pin
toggle       = 0
t$           = ""
RADAR$       = ""
RADAR_X$     = ""
Target_state$= ""
count        = 0
moving_LED   = 1 'green
static_LED   = 1 'green

TState       = 0
MTDis1       = 0
MTDis2       = 0
ETE_val      = 0
STDIS_val1   = 0
STDis_val2   = 0
STE_val      = 0
DetDis1      = 0
DetDis2      = 0
MMD_gate     = 0
MSD_gate     = 0

static_range0=0  : moving_range0=0
static_range1=0  : moving_range1=0
static_range2=0  : moving_range2=0
static_range3=0  : moving_range3=0
static_range4=0  : moving_range4=0
static_range5=0  : moving_range5=0
static_range6=0  : moving_range6=0
static_range7=0  : moving_range7=0
static_range8=0  : moving_range8=0

gosub        SETUP_LD2410_RADAR

gosub        webpage
onhtmlreload webpage
onhtmlchange webpage

onserial2    SER2RX
timer0 1000, TICK

wait
end

'#########################
SER2RX:
'#########################
count=count+1
toggle=1-toggle
'pause 1
serial2.read_iobuff(toggle)
size = iobuff.len(toggle)
' use only  each second incomming frame (toggle =0),
' but only the engineering frames with size=45
if (toggle=0) and (size = 45) then
  TState       =iobuff.read(0,8)
  MT_Dis1      =iobuff.read(0,9)
  MT_Dis2      =iobuff.read(0,10)
  ETE_val      =iobuff.read(0,11)
  STDIS_val1   =iobuff.read(0,12)
  STDis_val2   =iobuff.read(0,13)
  STE_val      =iobuff.read(0,14)
  Det_Dis1     =iobuff.read(0,15)
  Det_Dis2     =iobuff.read(0,16)
  MMD_gate     =iobuff.read(0,17)
  MSD_gate     =iobuff.read(0,18)
  
  moving_range0=iobuff.read(0,19)
  moving_range1=iobuff.read(0,20)
  moving_range2=iobuff.read(0,21)
  moving_range3=iobuff.read(0,22)
  moving_range4=iobuff.read(0,23)
  moving_range5=iobuff.read(0,24)
  moving_range6=iobuff.read(0,25)
  moving_range7=iobuff.read(0,26)
  moving_range8=iobuff.read(0,27)
  
  static_range0=iobuff.read(0,28)
  static_range1=iobuff.read(0,29)
  static_range2=iobuff.read(0,30)
  static_range3=iobuff.read(0,31)
  static_range4=iobuff.read(0,32)
  static_range5=iobuff.read(0,33)
  static_range6=iobuff.read(0,34)
  static_range7=iobuff.read(0,35)
  static_range8=iobuff.read(0,36)
  
  'Tstate regards the actual (default?) energy limits, 
  ' for each distance gate and for the maned time
  SELECT CASE TState 
    CASE 0
      Target_state$ = "No target detected"
      moving_LED = 1 'green
      static_LED = 1 'green
    CASE 1
      Target_state$ = "Moving target detected"
      moving_LED = 0 'red
      static_LED = 1 'green
    CASE 2
      Target_state$ = "Static target detected"
      moving_LED = 1 'green
      static_LED = 0 'red
    CASE 3
      Target_state$ = "Moving+static target detected"
      moving_LED = 0 'red
      static_LED = 0 'red
  END SELECT
endif
return

'#########################
WEBPAGE:
'#########################
A$ = ""
A$ = A$ + "<H3>LD2410 radar-sensor visualizer v" + Version$ +"</H3>"
A$ = A$ + textbox$(T$) + "<br>" 
A$ = A$ + textbox$(Target_state$) + " m:" + LED$(moving_LED) + " s:" + LED$(static_LED)+ "<br><br>"
A$ = A$ + "Targets energy in distance ranges: <br>"
A$ = A$ + "_________________<u>moving</u>_____<u>static+breathing</u><br>"
'A$ = A$ + " 0: 0.00m - 0.75m _ "+ meter$(moving_range0,0,100)+ " _ " + meter$(static_range0,0,100)+"<br>"
'A$ = A$ + " 1: 0.75m - 1.50m _ "+ meter$(moving_range1,0,100)+ " _ " + meter$(static_range1,0,100)+"<br>"
A$ = A$ + " 0: 0.00m - 0.75m _ "+ meter$(moving_range0,0,100)+ "<br>"
A$ = A$ + " 1: 0.75m - 1.50m _ "+ meter$(moving_range1,0,100)+ "<br>"
A$ = A$ + " 2: 1.50m - 2.25m _ "+ meter$(moving_range2,0,100)+ " _ " + meter$(static_range2,0,100)+"<br>"
A$ = A$ + " 3: 2.25m - 3.00m _ "+ meter$(moving_range3,0,100)+ " _ " + meter$(static_range3,0,100)+"<br>"
A$ = A$ + " 4: 3.00m - 3.75m _ "+ meter$(moving_range4,0,100)+ " _ " + meter$(static_range4,0,100)+"<br>"
A$ = A$ + " 5: 3.75m - 4.50m _ "+ meter$(moving_range5,0,100)+ " _ " + meter$(static_range5,0,100)+"<br>"
A$ = A$ + " 6: 4.50m - 5.25m _ "+ meter$(moving_range6,0,100)+ " _ " + meter$(static_range6,0,100)+"<br>"
A$ = A$ + " 7: 5.25m - 6.00m _ "+ meter$(moving_range7,0,100)+ " _ " + meter$(static_range7,0,100)+"<br>"
A$ = A$ + " 7: 6.00m - 6.75m _ "+ meter$(moving_range8,0,100)+ " _ " + meter$(static_range8,0,100)+"<br>"

cls
autorefresh 250
html A$
return

'#########################
TICK:
'#########################
t$=time$
RADAR$=IObuff.ToHex$(0)
'wlog t$, count ,RADAR$
wlog t$, count, Tstate
count=0
return


'#########################
SETUP_LD2410_RADAR:
'#########################
serial2.mode 256000,RX_pin,TX_pin

Enable_config$           ="fdfcfbfa0400ff00010004030201"
Enable_engineering_mode$ ="fdfcfbfa0200620004030201"
End_config$              ="fdfcfbfa0200fe0004030201"
'movement: 8 gates; static: 8 gates; unmaned duration: 5s
Default1$                ="fdfcfbfa1400600000000800000001000800000002000500000004030201"

IObuff.FromHex(1, Enable_config$)
SERIAL2.WRITE_IOBUFF(1)
pause 100
IObuff.FromHex(1, Enable_engineering_mode$)
SERIAL2.WRITE_IOBUFF(1)
pause 100
IObuff.FromHex(1, Default1$)
SERIAL2.WRITE_IOBUFF(1)
pause 100
IObuff.FromHex(1, End_config$)
SERIAL2.WRITE_IOBUFF(1)
pause 100
return