发帖
1 0 0

【电子DIY作品】回家离家提醒 M61-32SU + RD03D + DY-SV17F

lazy
论坛元老

37

主题

983

回帖

1万

积分

论坛元老

积分
10101
电子DIY 11 1 1 小时前
本帖最后由 lazy 于 2025-9-14 03:02 编辑


一、项目介绍

空闲时间越来越少了。最近看到 “申请升级版雷达模组Rd-03_V2” 的活动,就申请了一块。正好手上也有一个RD03D,可以检测x轴的正负值,就想着做一个回家离家检测。

主要的原理就是,通过判断 RD03D 雷达的 正负值,来判断是从 哪个方向 到 哪个方向。
比如,从正方向到负方向。就是离家。 从负方向到正方向就是 回家。

由于RD03D 距离的单位是mm 所以后续都用毫米标识,设置Y轴值 在 1000 mm 内,并且 计算出, 然后 获取 当前 检测到 移动 人的坐标。 再通过Y轴的值 计算出 当前 X轴的坐标值是否在 30度夹角内。如果在,就会触发 回家 、离家检测。 并进行 提醒。

离家提醒:出门三件套,一个不能少。手机揣兜里,钥匙挂腰间,门锁咔嚓响~!
回家提醒:忙了一天辛苦了,欢迎回来。

主打的就是一个情绪价值。

其实,开始构思的时候是想着,使用opus 数据进行语音播报的。使用  M61-32SU 模块请求服务器音频数据,然后再播放出来。研究好久没搞定。浪费了很多时间。
最后换成了熟悉的DY-SV17F。

单纯做这个的话 M61-32SU 有些功能浪费,但是对其他开发板又不是很熟悉,所以就用这个了。 期待安信可可以出一些小小的板子。

原设想:
M61-32SU 获取天气信息,出门的时候,判断天气状态,然后通过 tts 合成 提醒音频。
例如:
今天天气预报说有小雨,记得带伞呀。
今天高温,记得防暑。
等等。
语音播报这块就没搞定。遂猝。

另外可以参考 WT_0213 的这篇文章,将回家、离家接入HomeAssistant。
Ai-M61+VC02语音控制HA设备
之前我也是有HomeAssistant的,后来做了小米的定制 ,HA设备就刷机了。导致想用的时候环境搭建不起来了。 后续看看,能不能做个小板子。找个低功耗的。整个完整版。

二、模块

M61-32SU 介绍:
这个看上去和M61-32S 功能基本一样的,就是天线 M61-32SU 需要外接。

Snipaste_2025-09-14_02-09-10.png
它长这样子

Snipaste_2025-09-14_02-10-14.png
管脚定义和M61-32S没什么区别。

RD03D 数据介绍:
Snipaste_2025-09-14_01-51-32.png

判断最高位是否为 1 使用 x & 0x8000 就可以了。
去掉符号位取出绝对值数据 x & 0x7FFF 就可以了。

Snipaste_2025-09-14_01-51-46.png

Snipaste_2025-09-14_01-51-56.png
获取 x,y 的值,带符号位

  1. int16_t x = UART_RECEIVE_BUFFER[4] + (UART_RECEIVE_BUFFER[5] << 8);
  2.                     int16_t y = UART_RECEIVE_BUFFER[6] + (UART_RECEIVE_BUFFER[7] << 8);
复制代码


文档地址:
Rd-03D快速入门文档

DY-SV17F模块
Snipaste_2025-09-14_02-02-24.png
接口定义
Snipaste_2025-09-14_02-02-58.png

工作模式(这里选择了第二种,还不清楚M61-32SU怎么使用多个UART,看到代码中有个UART2,但是M61-32SU好像是没有。)
Snipaste_2025-09-14_02-03-14.png
IO0 低电平重复播放第一个音频文件,IO1低电平重复播放第二个音频文件。
通过BUSY 引脚可以判断播放状态,高电平 正在播放, 低电平播放完成。
Snipaste_2025-09-14_02-03-34.png

文档:
上传的附件: DY-SV17F模块功能说明.pdf (646.25 KB, 下载次数: 0)


三、代码

雷达数据检测
  1. #include "rd03d.h"
  2. #include <math.h>

  3. #include "sv17f.h"

  4. struct bflb_device_s *gpio;
  5. struct bflb_device_s *rd03d;
  6. uint8_t UART_RECEIVE_BUFFER[30];
  7. // 缓存数据总数,默认Rd03D 数据,是30位 AA FF 03 00
  8. int BUFFER_LEN = 30;

  9. int trendStatus = 0; // 0: 无趋势, 1: 回家, -1: 离家
  10. float angle = 30.0;

  11. void radar_init(void)
  12. {
  13.     gpio = bflb_device_get_by_name("gpio");
  14.     // 初始化led针脚gpio
  15.     bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
  16.     bflb_gpio_reset(gpio, GPIO_PIN_14);
  17.     bflb_gpio_uart_init(gpio, GPIO_PIN_23, GPIO_UART_FUNC_UART1_TX);
  18.     bflb_gpio_uart_init(gpio, GPIO_PIN_24, GPIO_UART_FUNC_UART1_RX);

  19.     rd03d = bflb_device_get_by_name("uart1");

  20.     struct bflb_uart_config_s conf = {
  21.         .baudrate = 256000,
  22.         .data_bits = UART_DATA_BITS_8,
  23.         .stop_bits = UART_STOP_BITS_1,
  24.         .parity = UART_PARITY_NONE,
  25.         .flow_ctrl = UART_FLOWCTRL_NONE,
  26.         .rx_fifo_threshold = 7,
  27.         .tx_fifo_threshold = 7
  28.     };
  29.     bflb_uart_init(rd03d, &conf);
  30.     xTaskCreate(sv17fTask, (char *)"sv17f", 1024, NULL, 2, NULL);
  31. }

  32. float calculate_opposite_side(float adjacent, float angle_degrees)
  33. {
  34.     float angle_radians = angle_degrees * (M_PI / 180.0); // 角度转弧度
  35.     return adjacent * tan(angle_radians);
  36. }

  37. void rd03dTask(void *pvParameters)
  38. {
  39.     int index = 0;
  40.     while (1) {
  41.         // 获取单个数据
  42.         int ch = bflb_uart_getchar(rd03d);
  43.         // 如果ch不等于-1说明有数据
  44.         if (ch != -1) {
  45.             // 如果当前数据是雷达指令头
  46.             if (ch == 0xAA) {
  47.                 // 重置数据缓存
  48.                 memset(UART_RECEIVE_BUFFER, 0, BUFFER_LEN);
  49.                 index = 0;
  50.             }
  51.             // 如果当前数据量小于指令数据
  52.             if (index < BUFFER_LEN) {
  53.                 UART_RECEIVE_BUFFER[index++] = ch;
  54.                 // 如果是数据帧结束标记
  55.                 if (ch == 0xCC) {
  56.                     // 检测坐标变化
  57.                     int16_t x = UART_RECEIVE_BUFFER[4] + (UART_RECEIVE_BUFFER[5] << 8);
  58.                     int16_t y = UART_RECEIVE_BUFFER[6] + (UART_RECEIVE_BUFFER[7] << 8);
  59.                     int16_t real_x = x & 0x7FFF;
  60.                     int16_t real_y = y & 0x7FFF;
  61.                     float px = calculate_opposite_side(real_y, angle);

  62.                     // 一般门宽度一米二左右,所以y值小于1000说明在门附近
  63.                     if (real_y <= 1000 && real_x <= px) {
  64.                         // printf("real_x: %d, real_y:%d, px:%.2f, trendStatus: %d\r\n", real_x, real_y, px, trendStatus);

  65.                         if (trendStatus == 0) {
  66.                             trendStatus = 1;
  67.                             // 判断趋势
  68.                             if (x & 0x8000) {
  69.                                 printf("离家\r\n");
  70.                                 bflb_gpio_reset(gpio, GPIO_PIN_14);
  71.                                 sv17f_send_message("leave");
  72.                             } else {
  73.                                 printf("回家\r\n");
  74.                                 bflb_gpio_set(gpio, GPIO_PIN_14);
  75.                                 sv17f_send_message("home");
  76.                             }
  77.                         }

  78.                     } else {
  79.                         if (real_x == 0 || real_x > px || real_y < 60 || real_y > 1000) {
  80.                             // printf("未检测到人员\r\n");
  81.                             if (trendStatus != 0) {
  82.                                 trendStatus = 0;
  83.                                 bflb_gpio_reset(gpio, GPIO_PIN_14);
  84.                                 printf("未检测到人员\r\n");
  85.                             }
  86.                         }
  87.                     }
  88.                 }
  89.             }
  90.         }
  91.         vTaskDelay(1/portTICK_PERIOD_MS);
  92.     }
  93. }
复制代码


播放音频文件
  1. #include "sv17f.h"
  2. #include "bflb_gpio.h"

  3. extern struct bflb_device_s *gpio;
  4. QueueHandle_t sound_queue;

  5. void sv17fTask(void *pvParameters)
  6. {
  7.      // 初始化led针脚gpio
  8.      bflb_gpio_init(gpio, GPIO_PIN_26, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
  9.      bflb_gpio_init(gpio, GPIO_PIN_28, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
  10.      bflb_gpio_init(gpio, GPIO_PIN_29, GPIO_INPUT | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_0);

  11.      bflb_gpio_set(gpio, GPIO_PIN_26);
  12.      bflb_gpio_set(gpio, GPIO_PIN_28);
  13.      bflb_gpio_reset(gpio, GPIO_PIN_29);

  14.      sound_queue = xQueueCreate(1, 1024*2);
  15.      char* sound_data = NULL;

  16.      while (1)
  17.      {
  18.         sound_data = pvPortMalloc(1024*2);
  19.         memset(sound_data, 0, 1024*2);
  20.         if(xQueueReceive(sound_queue, sound_data, 100/portTICK_PERIOD_MS) == pdTRUE){
  21.             printf("sound_data: %s\n", sound_data);
  22.             if (strcmp(sound_data, "home") == 0) {
  23.                 sv17f_back_home();
  24.             } else if (strcmp(sound_data, "leave") == 0) {
  25.                 sv17f_leave_home();
  26.             }
  27.         }

  28.         vPortFree(sound_data);
  29.      }
  30.      
  31. }

  32. void sv17f_back_home(void)
  33. {
  34.     printf("back home\n");
  35.     bflb_gpio_reset(gpio, GPIO_PIN_28);
  36.     vTaskDelay(100/portTICK_PERIOD_MS);

  37.     while (bflb_gpio_read(gpio, GPIO_PIN_29) == 1)
  38.     {
  39.         printf("waiting for home\n");
  40.         vTaskDelay(1/portTICK_PERIOD_MS);
  41.     }
  42.     printf("home\n");
  43.     bflb_gpio_set(gpio, GPIO_PIN_28);
  44.    
  45. }

  46. void sv17f_leave_home (void)
  47. {
  48.     printf("leave home\n");
  49.     bflb_gpio_reset(gpio, GPIO_PIN_26);
  50.     vTaskDelay(100/portTICK_PERIOD_MS);
  51.     while (bflb_gpio_read(gpio, GPIO_PIN_29) == 1)
  52.     {
  53.         printf("waiting for leave\n");
  54.         vTaskDelay(1/portTICK_PERIOD_MS);
  55.     }
  56.     printf("leave\n");
  57.     bflb_gpio_set(gpio, GPIO_PIN_26);
  58. }

  59. void sv17f_send_message(const char *message)
  60. {
  61.     printf("send message: %s\n", message);
  62.     if (sound_queue != NULL) {
  63.         xQueueSend(sound_queue, message, portMAX_DELAY);
  64.     }
  65. }
复制代码


四、设备展示
外壳之前都是用的嘉立创或者朋友代打的。这次,找了一个元器件外壳。由于研究 opus 数据传输浪费了很多时间,导致最后外壳有点草率了。搞个防水盒也是可以的。不过开始想的设备构造和这个不太一样。

_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=9197600176194145656&skey=@crypt_3423.jpg
_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=5698716114501068012&skey=@crypt_3423.jpg

程序源码:
上传的附件: radar_door.zip (7.95 KB, 下载次数: 0)

程序固件:
上传的附件: radar_door_bl616.zip (37.18 KB, 下载次数: 0)



──── 0人觉得很赞 ────
_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=5159835754972356300&skey=@crypt_3423.jpg

使用道具 举报

1 小时前

【M61-32su + Rd03d + sv17f 回家离家提醒-哔哩哔哩】 https://b23.tv/ewfxGy9

您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 29737 个
  • 话题数: 43249 篇