A lean Rust microservice for the HLK-LD2450 24 GHz mmWave radar sensor on Linux.
The daemon reads the sensor over UART and streams parsed target data as JSON-Lines over a Unix domain socket. A separate CLI tool handles sensor configuration. The protocol library is no_std-compatible.
flowchart TD
SENSOR1(HLK-LD2450 sensor)
SENSOR1 -->|UART 256000 baud| LD2450D(ld2450d daemon)
LD2450D --> JOURNALD("journald (tracing)")
LD2450D -->|Unix Socket: /run/ld2450/radar.sock| JSON("JSON-Lines stream (10Hz) to any connected client")
One-shot CLI for sensor
flowchart LR
LD2450CTL(ld2450-ctl)-->|UART direct, daemon must be stopped| SENSOR2(HLK-LD2450 sensor)
The daemon emits one JSON line per radar frame (10 Hz). Only active targets are included:
{
"ts": 1744489123.456,
"targets": [
{
"x": -0.782,
"y": 1.713,
"speed": -0.16,
"dist": 1.888,
"angle": -24.7
}
]
}| Field | Unit | Description |
|---|---|---|
ts |
seconds (Unix) | Timestamp |
x |
metres | Horizontal position (+ right, − left of sensor) |
y |
metres | Distance in front of sensor (always positive) |
speed |
m/s | Radial speed (+ approaching, − receding) |
dist |
metres | Euclidean distance from sensor |
angle |
degrees | Angle from boresight (−60 to +60) |
Up to 3 targets can be tracked simultaneously.
- Rust 1.74+ (or install via rustup)
- A serial port connected to an HLK-LD2450 sensor
- Linux (any architecture; tested on x86_64 and aarch64)
cargo build --releaseProduces two binaries in target/release/:
ld2450d-- the streaming daemonld2450-ctl-- the configuration CLI
The daemon works out of the box with sensible defaults. A config file is optional -- if none is found, the following defaults are used:
| Setting | Default |
|---|---|
device |
/dev/ttyAMA0 |
baud_rate |
256000 |
socket_path |
/run/ld2450/radar.sock |
log_level |
info |
To override any setting, create a TOML config file:
device = "/dev/ttyUSB0" # Adjust to your serial device
baud_rate = 256000
socket_path = "/run/ld2450/radar.sock"
log_level = "info"Common serial device paths:
/dev/ttyAMA0-- Raspberry Pi GPIO UART/dev/ttyUSB0-- USB-to-serial adapters/dev/ttyACM0-- CDC ACM devices
# Run with defaults (no config file needed)
ld2450d
# Run with explicit config
ld2450d /path/to/config.toml
# Override log level via environment
RUST_LOG=debug ld2450dConnect a client to read the stream:
socat - UNIX-CONNECT:/run/ld2450/radar.sock# Install cross (Docker-based cross-compiler)
cargo install cross
# Build for aarch64
cross build --target aarch64-unknown-linux-gnu --releaseOr use the provided justfile:
just build # default: aarch64-unknown-linux-gnu
TARGET=x86_64-unknown-linux-gnu just build # override targetPre-built binaries for x86_64 and aarch64 Linux are available on the Releases page.
Copy the provided unit files to the target system:
cp deploy/ld2450d.service /etc/systemd/system/
cp deploy/ld2450d.tmpfiles /etc/tmpfiles.d/ld2450d.conf
# Create runtime directory
systemd-tmpfiles --create
# Edit the service to match your serial device if needed
# Default: /dev/ttyAMA0
systemctl edit ld2450d
# Enable and start
systemctl daemon-reload
systemctl enable --now ld2450dThe service unit includes security hardening (ProtectSystem, NoNewPrivileges, PrivateTmp, etc.).
# Deploy to a remote host (requires just + cross)
DEPLOY_HOST=user@hostname just deployStop the daemon before running configuration commands -- both need exclusive UART access. If the UART is busy, the tool will exit with an error.
systemctl stop ld2450d
ld2450-ctl <command>
systemctl start ld2450dld2450-ctl [OPTIONS] <COMMAND>
OPTIONS:
-d, --device <DEVICE> Serial device [default: /dev/ttyAMA0]
-b, --baud-rate <BAUD_RATE> Baud rate [default: 256000]
COMMANDS:
firmware Read firmware version
get-mode Query current tracking mode
set-mode Set tracking mode (single | multi)
set-baud Set baud rate (effective after restart)
factory-reset Restore factory settings
restart Restart the sensor module
bluetooth Enable or disable Bluetooth (on | off)
get-mac Get module MAC address
get-zone Query zone filter configuration
set-zone Set zone filter configuration
# Check firmware version
ld2450-ctl firmware
# Switch to multi-target tracking
ld2450-ctl set-mode multi
# Disable Bluetooth (saves power)
ld2450-ctl bluetooth off
# Use a different serial device
ld2450-ctl -d /dev/ttyUSB0 firmware
# Only detect targets inside a 2x4m rectangle
ld2450-ctl set-zone --filter detect-only --zone1 "-1000,0,1000,4000"
# Disable zone filtering
ld2450-ctl set-zone --filter disableAny process can connect to the Unix socket and receive the JSON-Lines stream:
# Live output
socat - UNIX-CONNECT:/run/ld2450/radar.sock
# Pretty-print with jq
socat - UNIX-CONNECT:/run/ld2450/radar.sock | jq .# Python example
import socket, json
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/run/ld2450/radar.sock")
for line in sock.makefile():
frame = json.loads(line)
print(frame["targets"])The JSON format is compatible with radar-dash — a sensor-agnostic web frontend that works with any daemon emitting this schema.
| Project | Description |
|---|---|
| radar-dash | Sensor-agnostic HTML5 radar visualisation dashboard. Works directly with ld2450d over WebSocket. |
| mr60bha2-rs | Equivalent daemon for the Seeed MR60BHA2 60 GHz sensor — same JSON schema, adds vital signs (heart rate, breathing). |
The HLK-LD2450 uses a 4-pin UART interface. The module is powered at 5V but its TX/RX pins operate at 3.3V TTL level. The datasheet does not specify 5V tolerance on the RX pin -- if your host uses 5V UART logic (e.g. Arduino Uno), use a level shifter or voltage divider on the TX-to-sensor-RX line. No pull-up or pull-down resistors are required.
| Sensor Pin | Connection |
|---|---|
| 5V | 5V power supply |
| GND | Ground |
| TX | UART RX on your host |
| RX | UART TX on your host |
Raspberry Pi GPIO example (3.3V UART -- direct connection, no level shifter needed):
| Sensor Pin | Pi Pin |
|---|---|
| TX | Pin 10 (GPIO15 / UART RX) |
| RX | Pin 8 (GPIO14 / UART TX) |
If using a Raspberry Pi, disable Bluetooth to free the primary UART:
# /boot/firmware/config.txt (or /boot/config.txt on older systems)
enable_uart=1
dtoverlay=disable-bt| Parameter | Value |
|---|---|
| Frequency | 24 GHz ISM band |
| Max detection range | 6 m |
| Detection angle | +/-60 deg azimuth, +/-35 deg pitch |
| Max targets | 3 simultaneous |
| Data rate | 10 Hz |
| Interface | UART (3.3V TTL), default 256000 baud 8N1 |
| Supply voltage | 5V DC, >200 mA |
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.