发帖
9 0 0

安信可小安派BW21-CBV-Kit 超市进门拍照提示门铃

915992026
中级会员

3

主题

4

回帖

237

积分

中级会员

积分
237
小安派·BW21-CBV-KIt 310 9 2025-3-16 20:36:01
本帖最后由 915992026 于 2025-3-19 18:20 编辑

前几天开箱和环境搭建测试完成,想想这块开发板搭配AI物联网蓝牙话筒内存卡等等结合在一起能实现很多功能,接下来结合例程做一个简单实用的小工具,制作过程很简单,看例程拿来主义搭配在一起,像是搭积木一样多个项目堆在一起就是一个实用工具。使用起来非常方便,对新手友好还实用

超市入口拍照门铃
功能:1、进门提示音,
         2、有人进门就拍照(基于移动侦测功能,本来想人脸拍照来着,想想万一头戴丝袜的进去就没法识别了呢)
         3、照片按当前时间存储
         4、可查看监控视角用来调整拍摄角度(就是rtsp串流数据,电脑、手机也能播放,软件都是VLC
优点:1、按照片存储比存储视频节省内存空间
          2、按时间为名称查找方便,不用来回翻找视频
          3、后期程序提升功能空间很大,比如利用话筒蓝牙等功能实现对开发板门铃的参数设置,连接物联网实现监控报警等等

用料
代码内改成自己当前的时间,PWM输出的声音码根据自己喜好修改
注意:屏幕设置成GC2053

实物接线和展示:

接线就是喇叭接到开发板的INF15和GND引脚
jiexian.jpg

时间和拍照成功串口日志有提示的
zhanshi.jpg


拔出内存卡,插在电脑上面可看见有移动物体拍下的照片
存储卡相片.jpg


视频展示:
飞翔的老宫本刚刚发布的视频https://b23.tv/9UAk9VC




完整代码
  1. #include <Arduino.h>
  2. #include "WiFi.h"
  3. #include "VideoStream.h"
  4. #include "StreamIO.h"
  5. #include "RTSP.h"
  6. #include "MotionDetection.h"
  7. #include "VideoStreamOverlay.h"
  8. #include "AmebaFatFS.h"
  9. #include "Base64.h"

  10. #include <stdio.h>
  11. #include <time.h>
  12. #include "rtc.h"

  13. //蜂鸣器
  14. #define NOTE_    0
  15. #define NOTE_B0  31
  16. #define NOTE_C1  33
  17. #define NOTE_CS1 35
  18. #define NOTE_D1  37
  19. #define NOTE_DS1 39
  20. #define NOTE_E1  41
  21. #define NOTE_F1  44
  22. #define NOTE_FS1 46
  23. #define NOTE_G1  49
  24. #define NOTE_GS1 52
  25. #define NOTE_A1  55
  26. #define NOTE_AS1 58
  27. #define NOTE_B1  62
  28. #define NOTE_C2  65
  29. #define NOTE_CS2 69
  30. #define NOTE_D2  73
  31. #define NOTE_DS2 78
  32. #define NOTE_E2  82
  33. #define NOTE_F2  87
  34. #define NOTE_FS2 93
  35. #define NOTE_G2  98
  36. #define NOTE_GS2 104
  37. #define NOTE_A2  110
  38. #define NOTE_AS2 117
  39. #define NOTE_B2  123
  40. #define NOTE_C3  131
  41. #define NOTE_CS3 139
  42. #define NOTE_D3  147
  43. #define NOTE_DS3 156
  44. #define NOTE_E3  165
  45. #define NOTE_F3  175
  46. #define NOTE_FS3 185
  47. #define NOTE_G3  196
  48. #define NOTE_GS3 208
  49. #define NOTE_A3  220
  50. #define NOTE_AS3 233
  51. #define NOTE_B3  247
  52. #define NOTE_C4  262
  53. #define NOTE_CS4 277
  54. #define NOTE_D4  294
  55. #define NOTE_DS4 311
  56. #define NOTE_E4  330
  57. #define NOTE_F4  349
  58. #define NOTE_FS4 370
  59. #define NOTE_G4  392
  60. #define NOTE_GS4 415
  61. #define NOTE_A4  440
  62. #define NOTE_AS4 466
  63. #define NOTE_B4  494
  64. #define NOTE_C5  523
  65. #define NOTE_CS5 554
  66. #define NOTE_D5  587
  67. #define NOTE_DS5 622
  68. #define NOTE_E5  659
  69. #define NOTE_F5  698
  70. #define NOTE_FS5 740
  71. #define NOTE_G5  784
  72. #define NOTE_GS5 831
  73. #define NOTE_A5  880
  74. #define NOTE_AS5 932
  75. #define NOTE_B5  988
  76. #define NOTE_C6  1047
  77. #define NOTE_CS6 1109
  78. #define NOTE_D6  1175
  79. #define NOTE_DS6 1245
  80. #define NOTE_E6  1319
  81. #define NOTE_F6  1397
  82. #define NOTE_FS6 1480
  83. #define NOTE_G6  1568
  84. #define NOTE_GS6 1661
  85. #define NOTE_A6  1760
  86. #define NOTE_AS6 1865
  87. #define NOTE_B6  1976
  88. #define NOTE_C7  2093
  89. #define NOTE_CS7 2217
  90. #define NOTE_D7  2349
  91. #define NOTE_DS7 2489
  92. #define NOTE_E7  2637
  93. #define NOTE_F7  2794
  94. #define NOTE_FS7 2960
  95. #define NOTE_G7  3136
  96. #define NOTE_GS7 3322
  97. #define NOTE_A7  3520
  98. #define NOTE_AS7 3729
  99. #define NOTE_B7  3951
  100. #define NOTE_C8  4186
  101. #define NOTE_CS8 4435
  102. #define NOTE_D8  4699
  103. #define NOTE_DS8 4978
  104. //蜂鸣器
  105. int melody[] = {
  106.     NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_D4, NOTE_C4,
  107.     NOTE_E4, NOTE_D4, NOTE_C4, NOTE_A3, NOTE_G3, NOTE_A3, NOTE_G3,
  108.     NOTE_A3, NOTE_A3, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_D4, NOTE_E4,
  109.     NOTE_D4, NOTE_D4, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_C4};
  110. //蜂鸣器
  111. int noteDurations[] = {
  112.     6, 16, 8, 8, 8, 8, 4,
  113.     6, 16, 8, 8, 8, 8, 4,
  114.     6, 16, 8, 8, 8, 8, 4,
  115.     6, 16, 8, 8, 8, 8, 4};


  116. // 用户配置(已移除谷歌服务相关配置)
  117. #define CHANNEL   0              // 视频通道用于流媒体和快照
  118. #define CHANNELMD 3              // 仅通道3支持RGB格式低分辨率运动检测

  119. /* Change these values to set the current initial date */
  120. #define YEAR  2020
  121. #define MONTH 1
  122. #define DAY   1
  123. /* Change these values to set the current initial time */
  124. #define HOUR 13
  125. #define MIN  14
  126. #define SEC  15
  127. long long seconds = 0;
  128. struct tm *timeinfo;

  129. char ssid[] = "jifanG";    // 你的WiFi名称
  130. char pass[] = "88888888";        // 你的WiFi密码

  131. // 添加全局变量声明
  132. uint32_t img_addr = 0;  // 声明图像地址变量
  133. uint32_t img_len = 0;   // 声明图像长度变量

  134. // 创建对象
  135. VideoSetting config(VIDEO_D1, CAM_FPS, VIDEO_H264_JPEG, 1);    // 高分辨率视频流配置
  136. VideoSetting configMD(VIDEO_VGA, 10, VIDEO_RGB, 0);            // 低分辨率RGB视频流配置(用于运动检测)
  137. RTSP rtsp;
  138. StreamIO videoStreamer(1, 1);
  139. StreamIO videoStreamerMD(1, 1);
  140. MotionDetection MD;
  141. AmebaFatFS fs;
  142. WiFiSSLClient wifiClient;

  143. // 全局变量
  144. char buf[512];
  145. char *p;
  146. bool flag_motion = false;

  147. // 运动检测结果处理回调函数
  148. void mdPostProcess(std::vector<MotionDetectionResult> md_results)
  149. {
  150.     OSD.createBitmap(CHANNEL);
  151.     if (MD.getResultCount() > 0) {
  152.         for (uint16_t i = 0; i < MD.getResultCount(); i++) {
  153.             MotionDetectionResult result = md_results[i];
  154.             int xmin = (int)(result.xMin() * config.width());
  155.             int xmax = (int)(result.xMax() * config.width());
  156.             int ymin = (int)(result.yMin() * config.height());
  157.             int ymax = (int)(result.yMax() * config.height());
  158.             OSD.drawRect(CHANNEL, xmin, ymin, xmax, ymax, 3, COLOR_GREEN);
  159.         }
  160.         flag_motion = true;
  161.     } else {
  162.         flag_motion = false;
  163.     }
  164.     OSD.update(CHANNEL);
  165.     delay(100);
  166. }

  167. //蜂鸣器
  168. void play(int *melody, int *noteDurations, int num)
  169. {
  170.     for (int note = 0; note < num; note++) {
  171.         int noteDuration = 3000 / noteDurations[note];

  172.         tone(8, melody[note], noteDuration);

  173.         delay(noteDuration * 1.30);
  174.     }
  175. }



  176. void setup()
  177. {
  178.     Serial.begin(115200);

  179.     // WiFi连接
  180.     while (WiFi.status() != WL_CONNECTED) {
  181.         Serial.print("正在连接WiFi:");
  182.         Serial.println(ssid);
  183.         WiFi.begin(ssid, pass);
  184.         delay(2000);
  185.     }
  186.     WiFiCon();    // 连接成功指示灯闪烁

  187.     // 配置摄像头视频通道
  188.     Camera.configVideoChannel(CHANNEL, config);
  189.     Camera.configVideoChannel(CHANNELMD, configMD);
  190.     Camera.videoInit();

  191.     // 配置RTSP流媒体
  192.     rtsp.configVideo(config);
  193.     rtsp.begin();

  194.     // 配置运动检测模块
  195.     MD.configVideo(configMD);
  196.     MD.setResultCallback(mdPostProcess);
  197.     MD.begin();

  198.     // 配置视频流管道(高分辨率通道→RTSP服务器)
  199.     videoStreamer.registerInput(Camera.getStream(CHANNEL));
  200.     videoStreamer.registerOutput(rtsp);
  201.     if (videoStreamer.begin() != 0) {
  202.         Serial.println("视频流管道启动失败");
  203.     }

  204.     // 启动视频通道
  205.     Camera.channelBegin(CHANNEL);
  206.     Serial.println("RTSP流媒体已启动");

  207.     // 配置视频流管道(低分辨率通道→运动检测模块)
  208.     videoStreamerMD.registerInput(Camera.getStream(CHANNELMD));
  209.     videoStreamerMD.setStackSize();
  210.     videoStreamerMD.registerOutput(MD);
  211.     if (videoStreamerMD.begin() != 0) {
  212.         Serial.println("视频流管道启动失败");
  213.     }

  214.     // 启动低分辨率通道
  215.     Camera.channelBegin(CHANNELMD);
  216.     Serial.println("===============================");
  217.     Serial.println("运动检测系统已启动");
  218.     Serial.println("===============================");
  219.     delay(2000);

  220.     rtc.Init();
  221.     long long epochTime = rtc.SetEpoch(YEAR, MONTH, DAY, HOUR, MIN, SEC);
  222.     rtc.Write(epochTime);
  223. }

  224. void loop()
  225. {
  226.     if (flag_motion) {
  227.         Serial.println("检测到运动!");
  228.         play(melody, noteDurations, (sizeof(melody) / sizeof(int)));//播放蜂鸣器
  229.         // SD卡初始化
  230.         if (!fs.begin()) {
  231.             StreamEnd();    // 停止所有模块
  232.             pinMode(LED_B, OUTPUT);
  233.             digitalWrite(LED_B, HIGH);    // 错误指示灯常亮
  234.             Serial.println("===============================");
  235.             Serial.println("[错误] SD卡挂载失败!");
  236.             Serial.println("===============================");
  237.             while (1);    // 停止运行
  238.         }

  239.         // 获取当前时间并生成文件名
  240.         long long current_seconds = rtc.Read();
  241.         struct tm *current_timeinfo = localtime(&current_seconds);
  242.         char filename[25];  // 增大缓冲区确保安全
  243.   int ret = snprintf(filename, sizeof(filename), "%04d%02d%02d_%02d%02d%02d.jpg",
  244.                 current_timeinfo->tm_year + 1900,
  245.                 current_timeinfo->tm_mon + 1,
  246.                 current_timeinfo->tm_mday,
  247.                 current_timeinfo->tm_hour,
  248.                 current_timeinfo->tm_min,
  249.                 current_timeinfo->tm_sec);

  250. // 安全检查(同时处理返回值错误和缓冲区溢出)
  251. if (ret < 0) {
  252.     Serial.println("文件名格式错误!");
  253.     return;
  254. }
  255. if (static_cast<unsigned int>(ret) >= sizeof(filename)) {
  256.     Serial.println("文件名生成错误,缓冲区过小!");
  257.     return;
  258. }
  259.         String filepath = String(fs.getRootPath()) + String(filename);

  260.         // 创建并打开文件
  261.         File file = fs.open(filepath);
  262.         if (!file) {
  263.             Serial.println("===============================");
  264.             Serial.println("[错误] 无法创建文件!");
  265.             Serial.println("===============================");
  266.             fs.end();
  267.             return;
  268.         }

  269.         // 拍摄新照片
  270.         CamFlash();    // 拍照指示灯闪烁
  271.         Camera.getImage(CHANNEL, &img_addr, &img_len);
  272.         file.write((uint8_t *)img_addr, img_len);
  273.         file.close();
  274.         Serial.println("===============================");
  275.         Serial.print("[信息] 已保存照片:");
  276.         Serial.println(filename);
  277.         Serial.println("===============================");

  278.         flag_motion = false;    // 重置运动标志
  279.     } else {
  280.         Serial.print(".");    // 无运动时显示进度
  281.     }

  282.     seconds = rtc.Read();
  283.     printEpochTime();
  284.     printBasicString();
  285.     printStringTime();
  286.     Serial.println("----------------------------------------------------------------------");
  287.     rtc.Wait(1);
  288. }

  289. // LED闪烁函数(连接成功提示)
  290. void WiFiCon()
  291. {
  292.     pinMode(LED_B, OUTPUT);
  293.     for (int i = 0; i < 2; i++) {
  294.         digitalWrite(LED_B, HIGH);
  295.         delay(300);
  296.         digitalWrite(LED_B, LOW);
  297.         delay(300);
  298.     }
  299. }

  300. // 拍照指示灯闪烁函数
  301. void CamFlash()
  302. {
  303.     pinMode(LED_G, OUTPUT);
  304.     for (int i = 0; i < 5; i++) {
  305.         digitalWrite(LED_G, HIGH);
  306.         delay(100);
  307.         digitalWrite(LED_G, LOW);
  308.         delay(100);
  309.     }
  310. }

  311. // 停止所有模块函数
  312. void StreamEnd()
  313. {
  314.     videoStreamer.pause();
  315.     videoStreamerMD.pause();
  316.     rtsp.end();
  317.     Camera.channelEnd();
  318.     MD.end();
  319.     Camera.videoDeinit();
  320.     delay(1000);
  321. }

  322. void printEpochTime(void)
  323. {
  324.     Serial.print("Epoch Time(in s) since January, 1, 1970:");
  325.     Serial.print(seconds);
  326.     Serial.print("s");
  327. }

  328. void printBasicString(void)
  329. {
  330.     Serial.println();
  331.     Serial.print("Time as a basic string:                  ");
  332.     Serial.print(ctime(&seconds));
  333. }

  334. void printStringTime(void)
  335. {
  336.     timeinfo = localtime(&seconds);
  337.     Serial.print("Time as a custom formatted string:       ");
  338.     Serial.print(timeinfo->tm_year + 1900);
  339.     Serial.print("-");
  340.     Serial.print(timeinfo->tm_mon + 1);
  341.     Serial.print("-");
  342.     Serial.print(timeinfo->tm_mday);
  343.     Serial.print(" ");
  344.     Serial.print(timeinfo->tm_hour);
  345.     Serial.print(":");
  346.     Serial.print(timeinfo->tm_min);
  347.     Serial.print(":");
  348.     Serial.println(timeinfo->tm_sec);
  349. }
复制代码

实测移动侦测人活动10米以内,挂在墙上完全够用。
参考例程:MotionDetectGoogleLineNotify、Simple_RTC、PWM_BuzzerPlayMelody

──── 0人觉得很赞 ────
zhanshi1.jpg

使用道具 举报

2025-3-17 08:27:43
好酷的想法
2025-3-17 08:34:09
配上硬件图片和接线图片就更好了。
2025-3-17 09:46:57
WT_0213 发表于 2025-3-17 08:34
配上硬件图片和接线图片就更好了。

好嘞过一阵子会更新
2025-3-17 09:47:58
2025-3-17 09:59:09
创意挺好,就是帖子不太完整,需要配上相应的图片。
2025-3-17 10:03:00
代替了进门的人体感应传感器,一般都是微波或者热释电的传感器
2025-3-17 14:32:53
HaydenHu 发表于 2025-3-17 10:03
代替了进门的人体感应传感器,一般都是微波或者热释电的传感器

哈哈,成本增加了
2025-3-18 09:22:00
2025-3-19 18:23:59
爱笑 发表于 2025-3-17 09:59
创意挺好,就是帖子不太完整,需要配上相应的图片。

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