Contributed by WildboarG, organized by Ai-Thinker
AI-WB2 + RD04 Sentry Check
AI-WB2 + RD04 Radar Detection
Description
Time to fill the pit I dug last time. Renting a place alone isn't safe, so I used the RD04 radar to detect whether someone has broken into the house, and notify my personal phone. It can be paired with a camera for snapshots (up to you to implement).
When an obstacle is in front of the radar, it outputs a high level, and a notification message is pushed to your personal phone.
Materials
- WB2-12F
- RD04
Schematic


The RD04 Radar
The Rd-04 exposes 6 pins of 2.0mm header in total, with the following pinout:

This article needs the I2C pins, so before wiring it up, the onboard MCU of the Rd-04 must be removed. The MCU location is as follows:

Notification Push
Alternatively, you can use WeChat official account push, Bemfa, pushplus, or ServerChan.
Enabling Push
I set up an HTTP server and opened a static toggle page to decide whether to enable notifications, so it won't trigger constantly — a bit more user-friendly.

With the sentry disabled, no messages are pushed; once enabled, messages are pushed to the phone client normally.
Code Example
- Main thread
Click to expand full code
void
rd_task
(
void
*pvParameters)
{
// 构建消息内容结构体
static
const
char
title[] =
"RD04"
;
static
const
char
message[] =
"Trigger the radar notification"
;
static
const
char
priority[] =
"0"
;
static
Message msg = {title, message, priority};
printf
(
"title=%s \r\nmessage=%s\r\npriority=%s\r\n"
, msg.title, msg.message,
msg.priority);
while
(
1
) {
// 循环检测rd输出
hosal_gpio_input_get(&show, status);
vTaskDelay(
3000
);
// 触发通知
if
(status[
0
]) {
// 推送消息到手机
xTaskCreate(¬ify_task,
"notify_task"
,
1024
*
10
, &msg,
5
,
NULL
);
}
}
}- Radar driver
Click to expand full code
#
include
"FreeRTOS.h"
#
include
"hosal_i2c.h"
#
include
"task.h"
#
include
<rd04.h>
#
include
<stdint.h>
#
include
<stdio.h>
#
define
RD_ADDR 0x71
extern
hosal_i2c_dev_t
i2c0;
void
IIC_WriteData
(
uint8_t
reg_addr,
uint8_t
Buff)
{
uint8_t
Data[
2
];
uint8_t
ret =
-1
;
Data[
0
] = reg_addr;
Data[
1
] = Buff;
ret = hosal_i2c_master_send(&i2c0, RD_ADDR, Data,
sizeof
(Data),
HOSAL_WAIT_FOREVER);
if
(ret !=
0
) {
printf
(
"err:%c\n"
, Buff);
}
}
uint8_t
IIC_ReadData
(
uint8_t
reg_addr)
{
uint8_t
read_data[
1
];
read_data[
0
] = reg_addr;
hosal_i2c_master_recv(&i2c0, RD_ADDR, read_data,
1
, HOSAL_WAIT_FOREVER);
return
read_data;
}
void
RD_04_Init
(
void
)
{
printf
(
"init radar\r\n"
);
uint8_t
value;
for
(
uint8_t
i =
0
; i <
5
; i++) {
IIC_WriteData(
0x13
,
0x9B
);
vTaskDelay(
1
);
value = IIC_ReadData(
0x13
);
printf
(
"READ VALUE =0x%02X\r\n"
, value);
}
IIC_WriteData(
0x24
,
0x03
);
IIC_WriteData(
0x04
,
0x20
);
IIC_WriteData(
0x10
,
0x20
);
IIC_WriteData(
0x03
,
0x40
);
IIC_WriteData(
0x1C
,
0x21
);
IIC_WriteData(
0x18
,
0x6a
);
IIC_WriteData(
0x19
,
0x00
);
IIC_WriteData(
0x1A
,
0x55
);
IIC_WriteData(
0x1B
,
0x01
);
IIC_WriteData(
0x1D
,
0x80
);
IIC_WriteData(
0x1E
,
0x0C
);
IIC_WriteData(
0x1F
,
0x00
);
IIC_WriteData(
0x20
,
0x00
);
IIC_WriteData(
0x21
,
0x7D
);
IIC_WriteData(
0x22
,
0x00
);
IIC_WriteData(
0x23
,
0x0C
);
vTaskDelay(
3000
);
printf
(
"init radar successfuly\r\n"
);
}- Notification task
Click to expand full code
void
notify_task
(
void
*pvParameters)
{
Message *params = (Message *)pvParameters;
// 接收参数
printf
(
"title=%s \r\nmessage=%s\r\npriority=%s\r\n"
, params->title,
params->message, params->priority);
//
const
struct
addrinfo
hints
=
{
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct
addrinfo
*
res
;
struct
in_addr
*
addr
;
int
s, r;
char
recv_buf[
4096
];
while
(
1
) {
int
err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
if
(err !=
0
|| res ==
NULL
) {
blog_error(
"DNS lookup failed err=%d res=%p"
, err, res);
vTaskDelay(
1000
/ portTICK_PERIOD_MS);
continue
;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code
*/
addr = &((
struct
sockaddr_in *)res->ai_addr)->sin_addr;
blog_info(
"DNS lookup succeeded. IP=%s"
, inet_ntoa(*addr));
s = socket(res->ai_family, res->ai_socktype,
0
);
if
(s <
0
) {
blog_error(
"... Failed to allocate socket."
);
freeaddrinfo(res);
vTaskDelay(
1000
/ portTICK_PERIOD_MS);
continue
;
}
blog_info(
"... allocated socket"
);
if
(connect(s, res->ai_addr, res->ai_addrlen) !=
0
) {
blog_error(
"... socket connect failed errno=%d"
, errno);
close(s);
freeaddrinfo(res);
vTaskDelay(
4000
/ portTICK_PERIOD_MS);
continue
;
}
blog_info(
"... connected"
);
freeaddrinfo(res);
// 构造请求体
char
body[
1024
];
snprintf
(body,
sizeof
(body),
"--%s\r\n"
"Content-Disposition: form-data; name=\"title\"\r\n\r\n"
"%s\r\n"
"--%s\r\n"
"Content-Disposition: form-data; name=\"message\"\r\n\r\n"
"%s\r\n"
"--%s\r\n"
"Content-Disposition: form-data; name=\"priority\"\r\n\r\n"
"%s\r\n"
"--%s--\r\n"
,
BOUNDARY, params->title, BOUNDARY, params->message, BOUNDARY,
params->priority, BOUNDARY);
snprintf
(REQUEST,
sizeof
(REQUEST),
"POST %s%s HTTP/1.0\r\n"
"Host: %s:%s\r\n"
"User-Agent: aithinker wb2\r\n"
"Content-Type: multipart/form-data; boundary=%s\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s"
,
WEB_PATH_BASE, QUERY_STRING, WEB_SERVER, WEB_PORT, BOUNDARY,
strlen
(body), body);
printf
(REQUEST);
if
(write(s, REQUEST,
strlen
(REQUEST)) <
0
) {
blog_error(
"... socket send failed"
);
close(s);
vTaskDelay(
4000
/ portTICK_PERIOD_MS);
continue
;
}
blog_info(
"... socket send success"
);
struct
timeval
receiving_timeout
;
receiving_timeout.tv_sec =
5
;
receiving_timeout.tv_usec =
0
;
if
(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
sizeof
(receiving_timeout)) <
0
) {
blog_error(
"... failed to set socket receiving timeout"
);
close(s);
vTaskDelay(
4000
/ portTICK_PERIOD_MS);
continue
;
}
blog_info(
"... set socket receiving timeout success"
);
// FIXME fix putchar
extern
int
bl_putchar
(
int
c)
;
/* Read HTTP response */
do
{
bzero(recv_buf,
sizeof
(recv_buf));
r = read(s, recv_buf,
sizeof
(recv_buf) -
1
);
for
(
int
i =
0
; i < r; i++) {
bl_putchar(recv_buf[i]);
}
}
while
(r >
0
);
blog_info(
"... done reading from socket. Last read return=%d "
"errno=%d\r\n"
,
r, errno);
close(s);
for
(
int
countdown =
10
; countdown >=
0
; countdown--) {
blog_info(
"%d... "
, countdown);
vTaskDelay(
1000
/ portTICK_PERIOD_MS);
}
blog_info(
"Starting again!"
);
vTaskDelete(
NULL
);
}
}Final Result



