40浏览
查看: 40|回复: 0

[ESP8266/ESP32] 使用dfrobot ESP32-S3- AI CAM制作的远程喊话智能监控

[复制链接]
本帖最后由 名动神界 于 2025-5-27 11:15 编辑

测试时比较仓促,加之能力有限、经验不足,测试结果不具备普遍意义,这是一次简易的试用报告。相信dfrobot的产品质量都是过硬的,我没有把它的性能发挥出来。本案例中用到的所有头文件在此,下面不再重复
  1. #include <WiFi.h>
  2. #include <WebServer.h>
  3. #include <HTTPClient.h>
  4. #include <ArduinoJson.h>
  5. #include "ESP_I2S.h"
  6. #include "esp_camera.h"
  7. #include "FS.h"
  8. #include "SD.h"
  9. #include "SPI.h"
复制代码
所有引脚的配置如下图:
  1. // 摄像头引脚配置(ESP32-S3默认)
  2. #define PWDN_GPIO_NUM -1
  3. #define RESET_GPIO_NUM -1
  4. #define XCLK_GPIO_NUM 5
  5. #define Y9_GPIO_NUM 4
  6. #define Y8_GPIO_NUM 6
  7. #define Y7_GPIO_NUM 7
  8. #define Y6_GPIO_NUM 14
  9. #define Y5_GPIO_NUM 17
  10. #define Y4_GPIO_NUM 21
  11. #define Y3_GPIO_NUM 18
  12. #define Y2_GPIO_NUM 16
  13. #define VSYNC_GPIO_NUM 1
  14. #define HREF_GPIO_NUM 2
  15. #define PCLK_GPIO_NUM 15
  16. #define SIOD_GPIO_NUM 8
  17. #define SIOC_GPIO_NUM 9
  18. // TF卡SPI引脚配置
  19. #define SCK_PIN 12
  20. #define MISO_PIN 13
  21. #define MOSI_PIN 11
  22. #define CS_PIN 10
  23. // 麦克风引脚
  24. #define MIC_DATA 39
  25. #define MIC_CLK 38
复制代码

  • 第一步,是测试延时拍摄,因为板子不具备h264等编码器,录制mp4需占用80%以上的cpu且工作非常不稳定。
  1. void setup() {
  2.   Serial.begin(115200);
  3. camera_config_t config;// 初始化摄像头
  4.   config.ledc_channel = LEDC_CHANNEL_0;
  5.   config.ledc_timer = LEDC_TIMER_0;
  6.   config.pin_d0 = Y2_GPIO_NUM;
  7.   config.pin_d1 = Y3_GPIO_NUM;
  8.   config.pin_d2 = Y4_GPIO_NUM;
  9.   config.pin_d3 = Y5_GPIO_NUM;
  10.   config.pin_d4 = Y6_GPIO_NUM;
  11.   config.pin_d5 = Y7_GPIO_NUM;
  12.   config.pin_d6 = Y8_GPIO_NUM;
  13.   config.pin_d7 = Y9_GPIO_NUM;
  14.   config.pin_xclk = XCLK_GPIO_NUM;
  15.   config.pin_pclk = PCLK_GPIO_NUM;
  16.   config.pin_vsync = VSYNC_GPIO_NUM;
  17.   config.pin_href = HREF_GPIO_NUM;
  18.   config.pin_sscb_sda = SIOD_GPIO_NUM;
  19.   config.pin_sscb_scl = SIOC_GPIO_NUM;
  20.   config.pin_pwdn = PWDN_GPIO_NUM;
  21.   config.pin_reset = RESET_GPIO_NUM;
  22.   config.xclk_freq_hz = 20000000;
  23.   config.pixel_format = PIXFORMAT_JPEG;
  24.   config.frame_size = FRAMESIZE_UXGA;
  25.   config.jpeg_quality = 10;
  26.   config.fb_count = 2;
  27. esp_err_t err = esp_camera_init(&config);
  28.   if (err != ESP_OK) {
  29.     Serial.printf("Camera init failed: 0x%x", err);
  30.     return;}
  31.   SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);  //初始化sd卡
  32.   if(!SD.begin(CS_PIN)){
  33.     Serial.println("SD Card Mount Failed");
  34.     return;}}
  35. void loop() {
  36.   // 捕获帧并保存
  37.   camera_fb_t *fb = esp_camera_fb_get();  
  38.   if(!fb) {
  39.     Serial.println("Camera capture failed");
  40.     return;}
  41. String path = "/video_" + String(millis()) + ".jpg"; // 创建唯一文件名
  42.   File file = SD.open(path.c_str(), FILE_WRITE);// 写入SD卡
  43.   if(!file){
  44.     Serial.println("Failed to open file");
  45.   } else {
  46.     file.write(fb->buf, fb->len);
  47.     Serial.println("Saved: " + path);}
  48.   file.close();
  49.   esp_camera_fb_return(fb);
  50. delay(100);} // 控制帧率
复制代码
使用dfrobot ESP32-S3- AI CAM制作的远程喊话智能监控图2
录了6000多张,不过由于昨晚角度没放好,一直录的是距离桌面2米高的屋顶,红外夜视效果就出不来了,官方公布的红外夜视距离是2米以内。后面的图片是选取的典型状态图,第一张是晚上10点,最后一张是早上7点过。
使用dfrobot ESP32-S3- AI CAM制作的远程喊话智能监控图1
(典型的延时拍摄截图)

  • 第二步是测试远程喊话,这个费了点时间,因为我本人硬件调试经验薄弱,有些瞎子摸象的窘态,不过最终还是成功地使用百度语音合成生成了声音。

  1. // 配置参数
  2. #define BAIDU_TTS_URL "http://tsn.baidu.com/text2audio"
  3. #define API_KEY "***"
  4. #define SECRET_KEY "***"
  5. #define SAMPLE_RATE 16000
  6. I2SClass i2s;
  7. WiFiClient client;
  8. String getToken() {
  9.   HTTPClient http;
  10.   String url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials";
  11.   url += "&client_id=" + String(API_KEY);
  12.   url += "&client_secret=" + String(SECRET_KEY);
  13.   
  14.   http.begin(url);
  15.   int httpCode = http.GET();
  16.   
  17.   if(httpCode == HTTP_CODE_OK) {
  18.     String payload = http.getString();
  19.     int tokenStart = payload.indexOf("access_token") + 15;
  20.     int tokenEnd = payload.indexOf(""", tokenStart);
  21.     String accessToken = payload.substring(tokenStart, tokenEnd);
  22.     return accessToken;
  23.   }
  24.   return "";
  25. }
  26. void playAudio(uint8_t* data, size_t len) {
  27.   i2s.write(data, len);
  28. }
  29. void textToSpeech(String text) {
  30.   String token = getToken();
  31.   if(token == "") {
  32.     Serial.println("Failed to get token");
  33.     return;
  34.   }
  35.   HTTPClient http;
  36.   String url = BAIDU_TTS_URL "?tex=" + text;
  37.   url += "&tok=" + token;
  38.   url += "&cuid=esp32_device_zzq";
  39.   url += "&ctp=1";
  40.   url += "&lan=zh";
  41.   url += "&spd=5";
  42.   url += "&pit=5";
  43.   url += "&vol=5";
  44.   url += "&per=0";
  45.   url += "&aue=4"; // mp3格式
  46.   http.begin(client, url);
  47.   int httpCode = http.GET();
  48.   
  49.   if(httpCode == HTTP_CODE_OK) {
  50.     WiFiClient* stream = http.getStreamPtr();
  51.     uint8_t buffer[512];
  52.     while(stream->available()) {
  53.       size_t len = stream->readBytes(buffer, sizeof(buffer));
  54.       playAudio(buffer, len);
  55.     }
  56.   }
  57.   http.end();
  58. }
  59. void setup() {
  60.   Serial.begin(115200);
  61.   WiFi.begin("qzezsteam", "qzez@1953");
  62.   while(WiFi.status() != WL_CONNECTED) delay(500);
  63.   Serial.println(WiFi.localIP());
  64.   i2s.setPins(45, 46, 42);
  65.   if(!i2s.begin(I2S_MODE_STD, SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
  66.     Serial.println("I2S init failed");
  67.   }
  68. }
  69. void loop() {
  70.   if(Serial.available()) {
  71.     String input = Serial.readStringUntil('\n');
  72.     Serial.println(input);
  73.     textToSpeech(input);
  74.   }
  75. }
复制代码
主要的难点是把百度语音合成的音频流格式,也就是aue,和板子的播放命令(playmp3,playwav,playaudio)相匹配。本人水平有限,使用aue=3,也就是mp3格式,aue=36,也就是wav格式,都调试失败。最后我把aue设置了无压缩的pcm格式,这是一种没有文件头、原汗原味的声音流,通过i2s.write命令播放成功。
‌i2s.write‌
  • 功能‌:直接向I2S总线发送原始PCM音频数据流。
  • 数据要求‌:输入数据必须是未经压缩的PCM格式(如16位/32位量化、单/双声道)35。
  • 处理流程‌:需手动完成音频数据的解码、格式转换(如调整字节序、声道排列)和缓冲区管理57。
  • 典型应用‌:播放自定义音频流或需要低延迟控制的场景,如实时语音传输或音频合成
  • 第三步:测试web远程喊话,这个可以通过特殊手段把服务端html模板写入固件来实现,不过我还没学会。我是通过arduino ide中定义了html网页变量来做成功的。
    1. void handleRoot() {
    2.   String html = R"rawliteral(
    3.   <!DOCTYPE html>
    4.   <html>
    5.   <head>
    6.     <meta charset="UTF-8">
    7.     <title>远程监控系统</title>
    8.   </head>
    9.   <body>
    10.     <div>
    11.       <div>
    12.         <h2>远程喊话</h2>
    13.         <form action="/speak" method="POST">
    14.           <input type="text" name="text" placeholder="输入文字"><br>
    15.           <select name="preset">
    16.             <option value="">--选择预设短语--</option>
    17.             <option value="坏人,请赶快离开!">警告短语</option>
    18.             <option value="你有什么事么?">询问短语</option>
    19.             <option value="你好我是实验室主人">欢迎短语</option>
    20.           </select><br>
    21.           <input type="submit" value="播放">
    22.         </form>
    23.       </div>
    24.       <div>
    25.   </body>
    26.   </html>
    27.   )rawliteral";
    28.   server.send(200, "text/html; charset=utf-8", html);
    29. }
    复制代码
    第四步就是制作延时拍摄了,开始走了弯路,总想用板子向web发送更新命令,失败n次,换成web端向板子请求数据,最后终于成功了
  • <h2>实时监控</h2>
    <img id='stream' src='/capture' onload='setTimeout(function(){ document.getElementById(\"stream\").src = \"/capture?\" + new Date().getTime(); }, 100);'>

    onload这个回调函数,可以让图片实时更新,更新的频是100毫秒,也就是每秒钟回传10张。
  • 最后就制作完成了,下面是视频演示





TueMay-202505274529..png
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail