Human Presence Detection
A reliable human presence sensing with a 24GHz Radar module
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
returnBuild This Project
Bring this design to life with the Elektor PCB Service, powered by Eurocircuits. Upload the project files and order professionally manufactured PCBs or assembled boards through a proven European production platform.
Supporting KiCad, Eagle, Gerber, and ODB++ formats, the service is suitable for everything from prototypes and validation builds to series production and volume manufacturing.
Made in Europe. Fast. Reliable. Professional.

Discussion (0 comments)