发帖
6 0 0

【安信可小安派BW21-CBV-Kit】基于BW21和Rd-04低功耗双模态人体检测装置

qhsj
论坛元老

8

主题

96

回帖

5152

积分

论坛元老

积分
5152
小安派·BW21-CBV-KIt 82 6 4 天前
[i=s] 本帖最后由 qhsj 于 2025-3-28 22:18 编辑 [/i]

0x01 简介

上一篇:【安信可小安派BW21-CBV-Kit】开箱与Arduino环境搭建

既然 BW21 能够本地运行 AI 模型,如人脸识别,但是推理一张图像甚至是视频流需要大量的计算处理,导致 MCU 发热,功耗较大;而 Rd-04 雷达能够检测周围物体运动,并且功耗较低,但不能检测人体。结合两者特性,我利用 BW21-CBV-Kit 开发板Rd-04 雷达模组 DIY 一个低功耗双模态人体检测装置

0x02 硬件连接

image.png

0x03 软件部分

0b0001 IIC 设置 Rd-04 初始化

#include "Wire.h"

#define RD04_ADDRESS      0x71

void IIC_WriteData(uint8_t reg_addr, uint8_t Buff) {
  Wire.beginTransmission(RD04_ADDRESS);
  Wire.write(reg_addr);
  Wire.write(Buff);
  int result = Wire.endTransmission();

  if (result != 0) {
    Serial.print("Error code: ");
    Serial.println(result);
  }
}

uint8_t IIC_ReadData(uint8_t reg_addr) {  // 有问题读不了,待改进
  Wire.beginTransmission(RD04_ADDRESS);
  Wire.write(reg_addr);
  Wire.endTransmission(false);

  Wire.requestFrom(RD04_ADDRESS, 1);

  if (Wire.available()) 
  {
    return Wire.read();
  }
  return 0;
}

void Rd04_Init() {
    int i;
    //uint8_t value;
    Serial.println("\nRd-04 Init...");

    for (i = 0; i < 5; i++) {
      IIC_WriteData(0x13, 0x9B);
      delay(1);
      /*
      value = IIC_ReadData(0x13);

      Serial.print("READ VALUE = 0x");
      if (value < 16) {
          Serial.print("0");
      }
      Serial.print(value, HEX);
      Serial.println("\n");
      */
    }

    IIC_WriteData(0x24, 0x03);

    IIC_WriteData(0x04, 0x20);

    IIC_WriteData(0x10, 0x20);

    IIC_WriteData(0x03, 0x40);

    IIC_WriteData(0x1C, 0x21);

    // IIC_WriteData(0x11, 0x10);

    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);
    delay(3000);
    Serial.println("\nRd-04 Finished");
}

void setup()
{
    ......
    // Rd-04 Init
    Rd04_Init();  // 配置一次即可,后面可以注释

    ......
}

在使用 BW21 用 Wire.h 库 IIC 写入从机设备地址和寄存器地址后,想切换读取请求读取不了从机寄存器的数据,感觉代码也没啥问题...

感觉也没必要读取,应该也是读取为了验证是否写入,那我就把读取部分注释掉了

image.png

0b0010 读取雷达输出



#define USER_LED          24      // AMB_D24  PE_6  Green LED

#define RD04_ADDRESS      0x71    // Rd-04 雷达 iic 从机地址
#define RD04_OUTPUT_PIN   0       // 读取雷达输出引脚
int NN_Status = 1;                // 1 开启人脸识别;0 关闭
int Rd04_count0 = 0;              // 无人时计数器
int Rd04_count1 = 0;              // 有人时计数器
int count = 0;

void setup()
{
    ......

    pinMode(USER_LED, OUTPUT);
    digitalWrite(USER_LED, HIGH);
    pinMode(RD04_OUTPUT_PIN, INPUT_PULLDOWN);

    ......
}

void loop()
{
    ......

    if (digitalRead(RD04_OUTPUT_PIN)) { // 1 雷达捕获到人体运动
      Rd04_count1 ++;
      Rd04_count0 = 0;
      if (Rd04_count1 >= 5 && NN_Status == 0) {
        facerecog.begin();
        videoStreamerRGBFD.registerInput(Camera.getStream(CHANNELNN));
        videoStreamerRGBFD.setStackSize();
        videoStreamerRGBFD.setTaskPriority();
        videoStreamerRGBFD.registerOutput(facerecog);
        if (videoStreamerRGBFD.begin() != 0) {
            Serial.println("StreamIO link start failed");
        }
        Camera.channelBegin(CHANNELNN);

        NN_Status = 1;
        digitalWrite(USER_LED, HIGH);
      }
    } else {                           // 0 雷达没有捕获到人体运动
      Rd04_count0 ++;
      Rd04_count1 = 0;
      if (Rd04_count0 >= 40 && NN_Status == 1) {  // 4秒内雷达无捕获人体运动则取消人脸识别推理
            facerecog.end();
            Camera.channelEnd(CHANNELNN);

            NN_Status = 0;
            digitalWrite(USER_LED, LOW);
      }
    }

    delay(100);
    if (count >= 20) {
      OSD.createBitmap(CHANNEL);
      OSD.update(CHANNEL);
      count = 0;
    }
    count++;
}

主循环读雷达输出电平,当过久为低电平,即没有检测物体运动时,则关闭 AI 模型推理,并且关闭绿灯;当有检测物体运动时,则开启 AI 模型推理进行人脸识别。因此可以有效减少功耗,甚至可以再配置睡眠模式。

0b0011 人脸识别

基于 Arduino 例程修改的,参考教程:https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45738

“文件” -> “示例” -> “AmebaNN” -> “RTSPFaceRecognition” 中打开人脸识别示例

image.png

仅修改了尺寸 720 * 480以及热点账号密码

0b0100 完整代码

/*

 Example guide:
 https://www.amebaiot.com/en/amebapro2-arduino-neuralnework-face-recognition/

 Face registration commands
 --------------------------
 Point the camera at a target face and enter the following commands into the serial monitor,
 Register face:                       "REG={Name}"  Ensure that there is only one face detected in frame
 Remove face:                         "DEL={Name}"  Remove a registered face
 Reset registered faces:              "RESET"       Forget all previously registered faces
 Backup registered faces to flash:    "BACKUP"      Save registered faces to flash
 Restore registered faces from flash: "RESTORE"     Load registered faces from flash

 NN Model Selection
 -------------------
 Select Neural Network(NN) task and models using modelSelect(nntask, objdetmodel, facedetmodel, facerecogmodel).
 Replace with NA_MODEL if they are not necessary for your selected NN Task.

 NN task
 =======
 OBJECT_DETECTION/ FACE_DETECTION/ FACE_RECOGNITION

 Models
 =======
 YOLOv3 model         DEFAULT_YOLOV3TINY   / CUSTOMIZED_YOLOV3TINY
 YOLOv4 model         DEFAULT_YOLOV4TINY   / CUSTOMIZED_YOLOV4TINY
 YOLOv7 model         DEFAULT_YOLOV7TINY   / CUSTOMIZED_YOLOV7TINY
 SCRFD model          DEFAULT_SCRFD        / CUSTOMIZED_SCRFD
 MobileFaceNet model  DEFAULT_MOBILEFACENET/ CUSTOMIZED_MOBILEFACENET
 No model             NA_MODEL

*/

#include "WiFi.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "RTSP.h"
#include "NNFaceDetectionRecognition.h"
#include "VideoStreamOverlay.h"
#include "Wire.h"

#define CHANNEL   0
#define CHANNELNN 3

// Customised resolution for NN
#define NNWIDTH  576
#define NNHEIGHT 320

VideoSetting config(VIDEO_FHD, 30, VIDEO_H264, 0);
VideoSetting configNN(NNWIDTH, NNHEIGHT, 10, VIDEO_RGB, 0);
NNFaceDetectionRecognition facerecog;
RTSP rtsp;
StreamIO videoStreamer(1, 1);
StreamIO videoStreamerFDFR(1, 1);
StreamIO videoStreamerRGBFD(1, 1);

char ssid[] = "your network SSID";            // your network SSID (name)
char pass[] = "your network password";        // your network password
int status = WL_IDLE_STATUS;

IPAddress ip;
int rtsp_portnum;

#define USER_LED          24      // AMB_D24  PE_6  Green LED
// Rd-04
#define RD04_ADDRESS      0x71    // Rd-04 雷达 iic 从机地址
#define RD04_OUTPUT_PIN   0       // 读取雷达输出引脚
int NN_Status = 1;                // 1 开启人脸识别;0 关闭
int Rd04_count0 = 0;              // 无人时计数器
int Rd04_count1 = 0;              // 有人时计数器
int count = 0;

void IIC_WriteData(uint8_t reg_addr, uint8_t Buff) {
  Wire.beginTransmission(RD04_ADDRESS);
  Wire.write(reg_addr);
  Wire.write(Buff);
  int result = Wire.endTransmission();

  if (result != 0) {
    Serial.print("Error code: ");
    Serial.println(result);
  }
}

uint8_t IIC_ReadData(uint8_t reg_addr) {  // 有问题读不了,待改进
  Wire.beginTransmission(RD04_ADDRESS);
  Wire.write(reg_addr);
  Wire.endTransmission(false);

  Wire.requestFrom(RD04_ADDRESS, 1);

  if (Wire.available()) 
  {
    return Wire.read();
  }
  return 0;
}

void Rd04_Init() {
    int i;
    //uint8_t value;
    Serial.println("\nRd-04 Init...");

    for (i = 0; i < 5; i++) {
      IIC_WriteData(0x13, 0x9B);
      delay(1);
      /*
      value = IIC_ReadData(0x13);

      Serial.print("READ VALUE = 0x");
      if (value < 16) {
          Serial.print("0");
      }
      Serial.print(value, HEX);
      Serial.println("\n");
      */
    }

    IIC_WriteData(0x24, 0x03);

    IIC_WriteData(0x04, 0x20);

    IIC_WriteData(0x10, 0x20);

    IIC_WriteData(0x03, 0x40);

    IIC_WriteData(0x1C, 0x21);

    // IIC_WriteData(0x11, 0x10);

    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);
    delay(3000);
    Serial.println("\nRd-04 Finished");
}

void setup()
{
    Serial.begin(115200);

    // Rd-04 Init
    //Rd04_Init();  // 配置一次即可
    pinMode(USER_LED, OUTPUT);                 // 配置用户绿灯引脚为输出模式
    digitalWrite(USER_LED, HIGH);              // 绿灯亮
    pinMode(RD04_OUTPUT_PIN, INPUT_PULLDOWN);  // 配置引脚 0 为读取模式

    // Attempt to connect to Wifi network:
    while (status != WL_CONNECTED) {
        Serial.print("Attempting to connect to WPA SSID: ");
        Serial.println(ssid);
        status = WiFi.begin(ssid, pass);

        // wait 2 seconds for connection:
        delay(2000);
    }

    ip = WiFi.localIP();

    // Configure camera video channels with video format information
    // Adjust the bitrate based on your WiFi network quality
    config.setBitrate(2 * 720 * 480);    // Recommend to use 2Mbps for RTSP streaming to prevent network congestion
    Camera.configVideoChannel(CHANNEL, config);
    Camera.configVideoChannel(CHANNELNN, configNN);
    Camera.videoInit();

    // Configure RTSP with corresponding video format information
    rtsp.configVideo(config);
    rtsp.begin();
    rtsp_portnum = rtsp.getPort();

    // Configure Face Recognition model
    // Select Neural Network(NN) task and models
    facerecog.configVideo(configNN);
    facerecog.modelSelect(FACE_RECOGNITION, NA_MODEL, DEFAULT_SCRFD, DEFAULT_MOBILEFACENET);
    facerecog.begin();
    facerecog.setResultCallback(FRPostProcess);

    // Configure StreamIO object to stream data from video channel to RTSP
    videoStreamer.registerInput(Camera.getStream(CHANNEL));
    videoStreamer.registerOutput(rtsp);
    if (videoStreamer.begin() != 0) {
        Serial.println("StreamIO link start failed");
    }
    // Start data stream from video channel
    Camera.channelBegin(CHANNEL);

    // Configure StreamIO object to stream data from RGB video channel to face detection
    videoStreamerRGBFD.registerInput(Camera.getStream(CHANNELNN));
    videoStreamerRGBFD.setStackSize();
    videoStreamerRGBFD.setTaskPriority();
    videoStreamerRGBFD.registerOutput(facerecog);
    if (videoStreamerRGBFD.begin() != 0) {
        Serial.println("StreamIO link start failed");
    }

    // Start video channel for NN
    Camera.channelBegin(CHANNELNN);

    // Start OSD drawing on RTSP video channel
    OSD.configVideo(CHANNEL, config);
    OSD.begin();
}

void loop()
{
    if (Serial.available() > 0) {
        String input = Serial.readString();
        input.trim();

        if (input.startsWith(String("REG="))) {
            String name = input.substring(4);
            facerecog.registerFace(name);
        } else if (input.startsWith(String("DEL="))) {
            String name = input.substring(4);
            facerecog.removeFace(name);
        } else if (input.startsWith(String("RESET"))) {
            facerecog.resetRegisteredFace();
        } else if (input.startsWith(String("BACKUP"))) {
            facerecog.backupRegisteredFace();
        } else if (input.startsWith(String("RESTORE"))) {
            facerecog.restoreRegisteredFace();
        }
    }

    if (digitalRead(RD04_OUTPUT_PIN)) { // 1 雷达捕获到人体运动
      Rd04_count1 ++;
      Rd04_count0 = 0;
      if (Rd04_count1 >= 5 && NN_Status == 0) {
        facerecog.begin();
        videoStreamerRGBFD.registerInput(Camera.getStream(CHANNELNN));
        videoStreamerRGBFD.setStackSize();
        videoStreamerRGBFD.setTaskPriority();
        videoStreamerRGBFD.registerOutput(facerecog);
        if (videoStreamerRGBFD.begin() != 0) {
            Serial.println("StreamIO link start failed");
        }
        Camera.channelBegin(CHANNELNN);

        NN_Status = 1;
        digitalWrite(USER_LED, HIGH);
      }
    } else {                           // 0 雷达没有捕获到人体运动
      Rd04_count0 ++;
      Rd04_count1 = 0;
      if (Rd04_count0 >= 40 && NN_Status == 1) {  // 4秒内雷达无捕获人体运动则取消人脸识别推理
            facerecog.end();
            Camera.channelEnd(CHANNELNN);

            NN_Status = 0;
            digitalWrite(USER_LED, LOW);
      }
    }

    delay(100);
    if (count >= 20) {
      OSD.createBitmap(CHANNEL);
      OSD.update(CHANNEL);
      count = 0;
    }
    count++;
}

// User callback function for post processing of face recognition results
void FRPostProcess(std::vector<FaceRecognitionResult> results)
{
    uint16_t im_h = config.height();
    uint16_t im_w = config.width();

    Serial.print("Network URL for RTSP Streaming: ");
    Serial.print("rtsp://");
    Serial.print(ip);
    Serial.print(":");
    Serial.println(rtsp_portnum);
    Serial.println(" ");

    printf("Total number of faces detected = %d\r\n", facerecog.getResultCount());
    OSD.createBitmap(CHANNEL);

    if (facerecog.getResultCount() > 0) {
        for (int i = 0; i < facerecog.getResultCount(); i++) {
            FaceRecognitionResult item = results[i];
            // Result coordinates are floats ranging from 0.00 to 1.00
            // Multiply with RTSP resolution to get coordinates in pixels
            int xmin = (int)(item.xMin() * im_w);
            int xmax = (int)(item.xMax() * im_w);
            int ymin = (int)(item.yMin() * im_h);
            int ymax = (int)(item.yMax() * im_h);

            uint32_t osd_color;
            if (String(item.name()) == String("unknown")) {
                osd_color = OSD_COLOR_RED;
            } else {
                osd_color = OSD_COLOR_GREEN;
            }

            // Draw boundary box
            printf("Face %d name %s:\t%d %d %d %d\n\r", i, item.name(), xmin, xmax, ymin, ymax);
            OSD.drawRect(CHANNEL, xmin, ymin, xmax, ymax, 3, osd_color);

            // Print identification text above boundary box
            char text_str[40];
            snprintf(text_str, sizeof(text_str), "Face:%s", item.name());
            OSD.drawText(CHANNEL, xmin, ymin - OSD.getTextHeight(CHANNEL), text_str, osd_color);
        }
    }
    OSD.update(CHANNEL);
}

0x04 成果及演示视频

  • 检测到物体运动,开启人脸识别

image.png

image.png

  • 静默状态,关闭人脸识别

image.png

image.png

演示视频https://www.bilibili.com/video/BV1ikoQYsEp9/

0x05 其他拓展

想拓展增加功能:检测到人脸时录制视频保存至 sd 卡,然后可取消 rstp 推流,不依赖网络

应用场景:放在工位或其他监控位置,直接离线运行 AI 模型推理人脸识别,识别到陌生人则录制视频,保存至 sd 卡,需要时再查看 sd 卡内的视频文件

但是我目前问题是识别不了我的 sd 卡,已经按要求格式化为 FAT32 文件系统了还是不行...

image.png

image.png

用示例读取 sd 卡容量也不行 ...

image.png

感觉是 sd 卡物理损坏了,后面再买个卡试试看

对了... 还想吐槽一下 Rd-04 的引脚,居然不是 2.54 间距的... 还有 IIC_EN 引脚为什么不一起焊上排针...为什么 MCU 还要自己拆掉...

──── 0人觉得很赞 ────

使用道具 举报

Rd-04好像就是不如前面几个精致。
赞~
赞~~~
很棒!
跟我想到一块了,我也是做人体存在传感器
3 天前
HaydenHu 发表于 2025-3-28 19:43
跟我想到一块了,我也是做人体存在传感器

抢先做出来了
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28208 个
  • 话题数: 40123 篇