这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 电子DIY+SeeedStudioXIAOESP32S3Sense功能驱动

共1条 1/1 1 跳转至

电子DIY+SeeedStudioXIAOESP32S3Sense功能驱动

高工
2026-03-18 17:01:41     打赏

Seeed Studio XIAO ESP32S3 Sense 是一款集成度极高的开发板,在硬件配置上亮点十足。它搭载了 ESP32-S3R8 SoC 处理器,具备强大的无线通信能力,支持 2.4GHz WiFi 以及低功耗蓝牙® BLE 5.0 双模,能轻松应对各类无线应用场景。


在图像采集方面,该开发板配备插入式 OV2640 摄像头传感器,可呈现 16001200 的全分辨率画面。不仅如此,其底座兼容性出色,还能适配 OV5640,支持高达 25921944 的分辨率,满足对图像质量有更高要求的项目。

音频处理上,开发板内置数字麦克风,可用于语音感应和音频识别,为语音交互类应用提供了硬件基础。同时,它具备锂电池充电管理功能,方便为设备供电,增强了使用的便捷性与灵活性。


值得一提的是,SenseCraft AI 为 XIAO ESP32S3 Sense 提供了丰富多样的预训练人工智能模型,并且支持无代码部署,大大降低了 AI 应用开发的门槛,让开发者能快速将 AI 功能融入项目。为了进一步提升使用体验,还为该开发板配备了专门的扩展板。扩展板专为 Seeed Studio XIAO 设计,尺寸小巧,仅有半个 Raspberry Pi 4 大小。通过扩展板丰富的外设,如 OLED 显示屏、RTC 实时时钟、可扩展内存、无源蜂鸣器、RESET/用户按钮、5V 伺服连接器以及多种数据接口等,开发者可以更加简单快捷地进行原型开发和项目构建,充分探索 Seeed Studio XIAO ESP32S3 Sense 的无限可能性,无论是物联网项目、智能监控,还是语音交互应用等,都能借助它轻松实现。


开发板的布局图

image.png

在开发工具与编程语言的选择上,采用 Vscode 搭配 platformIO 开发环境,运用 Arduino 编程方式开展项目开发。系统整体架构清晰明了,以 Seeed XIAO ESP32S3 Sense 为核心控制单元。其中,摄像头作为关键的视觉输入模块,负责实时采集周围环境的数据,为后续的 AI 理解提供原始素材;按键则作为用户与设备交互的触发装置,用户可通过按下按键来主动获取信息或执行特定操作;OLED 屏幕作为输出显示模块,将 AI 分析理解后的文字信息清晰呈现给用户,方便用户快速获取所需内容。通过各模块之间的协同工作,实现互动标牌从数据采集、处理到展示的完整流程。

b0328b6d-dbfd-4ad0-99d2-27b0840267f6.png

基本思路:Seeed XIAO ESP32S3 Sense通过摄像头收集图像数据,当用户按下按键,就把当前摄像头获得的图像打包为json,通过http方式上送到阿里云的AI接口。AI负责解析图片内容,然后返回解析的内容,ESP32S3收到返回的内容,就用OLED现实出来,展示给用户解读。因为OLED比较小,采用多页展示的方式显示给用户。以此逻辑绘制流程图:

ce6fd0c2-977e-486b-a6ff-e668866da107.png


首先在阿里云大模型服务平台 申请API Key,后边图像的解析都需要用到阿里云的大模型服务平台。

c44aa87b-496b-456e-90a1-540403ec93dc.png

然后系统先初始化硬件,给摄像头单独启用一个进程,用来不停地读取摄像头。并将每次读取到的图片转换为base64编码格式。

代码

uint8_t CAMER_FLAG = 0;
String imageStr;
uint8_t camera_init()
{
    camera_config_t config;
    config.ledc_channel = LEDC_CHANNEL_0;
    config.ledc_timer = LEDC_TIMER_0;
    config.pin_d0 = Y2_GPIO_NUM;
    config.pin_d1 = Y3_GPIO_NUM;
    config.pin_d2 = Y4_GPIO_NUM;
    config.pin_d3 = Y5_GPIO_NUM;
    config.pin_d4 = Y6_GPIO_NUM;
    config.pin_d5 = Y7_GPIO_NUM;
    config.pin_d6 = Y8_GPIO_NUM;
    config.pin_d7 = Y9_GPIO_NUM;
    config.pin_xclk = XCLK_GPIO_NUM;
    config.pin_pclk = PCLK_GPIO_NUM;
    config.pin_vsync = VSYNC_GPIO_NUM;
    config.pin_href = HREF_GPIO_NUM;
    config.pin_sccb_sda = SIOD_GPIO_NUM;
    config.pin_sccb_scl = SIOC_GPIO_NUM;
    config.pin_pwdn = PWDN_GPIO_NUM;
    config.pin_reset = RESET_GPIO_NUM;
    config.xclk_freq_hz = 20000000;
    config.pixel_format = PIXFORMAT_JPEG;
    // init with high specs to pre-allocate larger buffers
    if (psramFound())
    {
        config.frame_size = FRAMESIZE_UXGA;
        config.jpeg_quality = 10;
        config.fb_count = 2;
    }
    else
    {
        config.frame_size = FRAMESIZE_SVGA;
        config.jpeg_quality = 12;
        config.fb_count = 1;
    }
    // camera init
    esp_err_t err = esp_camera_init(&config);
    if (err != ESP_OK)
    {
        Serial.printf("Camera init failed with error 0x%x", err);
        return err;
    }
    // drop down frame size for higher initial frame rate
    sensor_t *s = esp_camera_sensor_get();
    s->set_framesize(s, FRAMESIZE_QVGA);
    return 0;
}

// 从摄像头不停读取图片,当有信号发生时,拍照
void TaskCamImage(void *pvParameters)
{
    camera_fb_t *pic = NULL;
    camera_init();
    for (;;)
    {
        pic = esp_camera_fb_get();
        if (!pic)
        {
            log_e("Camera capture failed");
        }
        log_d("img_buf_len=%d , width=%d , height=%d ", pic->len, pic->height, pic->width);
        log_w("Total PSRAM: %d,  %d", ESP.getPsramSize(), ESP.getFreePsram());
        if (CAMER_FLAG==1)
        {
            // fb->buf转为base64字符串
            imageStr = base64::encode(pic->buf, pic->len);
            // Serial.print("image_base64 success!");
            Serial.print("  len=");
            Serial.print(pic->len);
            Serial.println();
            // Serial.print("  base64_str=");
            // Serial.println(imageStr);
            CAMER_FLAG = 9;     //形成了完整的图片base64字符串,可以发送给AI了
        }
        esp_camera_fb_return(pic);
    }
}

在按键功能实现方面,引入了“OneButton”库来精准监控按键操作。该库能够实时捕捉按键按下的动作,一旦检测到按键被按下,系统便会迅速构建符合 AI 识别要求的 JSON 语句。此 JSON 语句作为数据载体,会与当前通过摄像头采集到的图片内容一同打包。随后,借助 HTTP 接口,将包含图片和 JSON 语句的数据包上传至指定服务器,以便后续 AI 模型对图片内容进行分析与处理。

// 构建待上传的json 数据
String buildPalyLoad()
{
  String payload;
  data_json.clear();
  data_json["model"] = "qwen-vl-max-latest";
  JsonArray msg = data_json.createNestedArray("messages"); // 添加数组.
  StaticJsonDocument<120> subnode;
  subnode["role"] = "user";
  JsonArray content = subnode.createNestedArray("content");
  StaticJsonDocument<120> connode;
  connode["type"] = "image_url";
  connode["image_url"] = "CAME_IMAGE_BASE64";
  // connode["image_url"] = image_base64();
  content.add(connode);
  connode.clear();
  connode["type"] = "text";
  connode["text"] = "简单描述图片";
  content.add(connode);
  msg.add(subnode);
  serializeJson(data_json, payload);
  return payload;
}

void loop(void)
{
  // String imageStr;
  uint8_t butflag;
  btn.tick();
  if (WiFi.status() == WL_CONNECTED)
  {
    if (CAMER_FLAG == 9)
    {
      CAMER_FLAG = 10;
      aiEchoStr = "网络请求中";
      String payload = buildPalyLoad();
      payload.replace("\"CAME_IMAGE_BASE64\"", "{\"url\":\"data:image/jeg;base64," + imageStr + "\"}");
      // Serial.println(payload);
      // Serial.println("请稍后...");


      HTTPClient http_image_request;
      http_image_request.setTimeout(60000);
      http_image_request.begin(apiUrl);
      http_image_request.addHeader("Content-Type", "application/json");
      http_image_request.addHeader("Authorization", String("Bearer ") + String(apiKey));
      int httpCode = http_image_request.POST(payload);
      if (httpCode == 200)
      {
        String response = http_image_request.getString();
        http_image_request.end();
        DynamicJsonDocument jsonDoc(1024);
        deserializeJson(jsonDoc, response);
        const char* world = jsonDoc["choices"][0]["message"]["content"];
        aiEchoStr = world; //获得到AI返回的文字
        CAMER_FLAG = 11;
        // Serial.println(response);
      }
      else
      {
        CAMER_FLAG = 0;
        Serial.println("error request: " + String(httpCode));
        http_image_request.end();
      }
    }
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
  else
  {
    log_e("[WIFI] is not Connecting!");
    vTaskDelay(10000 / portTICK_PERIOD_MS);
  }
}
通过 HTTP 协议将摄像头实时捕捉到的图片内容上传至阿里云后,阿里云服务器会迅速对图片进行解析,并返回一串解析后的字符串。由于解析内容采用中文表述,所以返回的字符串也是一连串中文字符。为了在 OLED 屏幕上清晰呈现这些中文内容,项目选用了 U8g2 库来驱动 OLED 显示中文。不过,板子上的 OLED 屏幕尺寸仅为 128X64 像素,显示空间有限,无法一次性完整展示所有返回的汉字。针对这一问题,采用了分屏显示的方式。每次在屏幕上显示 4 行内容,每行限定为 8 个汉字,这样既能保证汉字清晰可辨,又能充分利用屏幕空间。并且,每一页内容会在屏幕上停留 2 秒钟,方便用户阅读,之后系统会自动翻页,展示后续内容,以此实现解析内容的完整呈现。


void oledDispRow(String dispstr, uint8_t rownum)
{
  Serial.println(rownum);
  u8g2.setFont(u8g2_font_unifont_t_chinese3); // use chinese2
  u8g2.clear();
  u8g2.firstPage();
  do
  {
    for (uint16_t i = 0; i <= rownum; i++)
    {
      String subStr = dispstr.substring(i * OLED_ROW, i * OLED_ROW + OLED_ROW);
      Serial.printf("i=%d   ,rows= %d  ", i, rownum);
      Serial.println(subStr);
      u8g2.setCursor(0, (i + 1) * 16);
      u8g2.print(subStr); // Chinese "Hello World"
    }
  } while (u8g2.nextPage());
}
// 将AI获得的字符串解析出来,并显示
void TaskOledDisp(void *pvParameters)
{
  uint16_t strlen = 0;
  u8g2.begin();
  u8g2.enableUTF8Print();
  for (;;)
  {
    if (CAMER_FLAG == 10)
    {
      strlen = aiEchoStr.length();
      Serial.print("10 strlen:");
      Serial.println(strlen);
      for (uint16_t i = 0; i < strlen; i += OLED_ROW * 4)
      {
        String subStr = aiEchoStr.substring(i, i + OLED_ROW * 4);
        Serial.println(subStr);
        oledDispRow(subStr, (subStr.length() / (OLED_ROW)));
        vTaskDelay(pdMS_TO_TICKS(2000)); 
      }
    }
    if (CAMER_FLAG == 11)
    {
      strlen = aiEchoStr.length();
      Serial.print("11 strlen:");
      Serial.println(strlen);
      for (uint16_t i = 0; i < strlen; i += OLED_ROW * 4)
      {
        String subStr = aiEchoStr.substring(i, i + OLED_ROW * 4);
        Serial.println(subStr);
        oledDispRow(subStr, (subStr.length() / (OLED_ROW)));
        vTaskDelay(pdMS_TO_TICKS(5000)); 
      }
      CAMER_FLAG = 0;
    }
    if (CAMER_FLAG == 0) u8g2.clear();
    vTaskDelay(pdMS_TO_TICKS(50)); 
  }
}

效果展示:

系统上电后,需要保障WIFI的畅通。

a5d238b4-932c-496c-9eed-49fd4483308a.png

当遇到感兴趣的画面后,将摄像头对准感兴趣的场景,然后按下蓝色按键(红色按键未接入系统)。oled显示网络请求中,需要等待一会,等待AI的处理。

稍后阿里平台传回AI模型分析的结果,在OLED上展示。

09518548-a284-4de9-972a-a0c4cb22599f.png

如果开发板有连着电脑,可以通过电脑串口看见AI平台返回的结果内容。

8d2b5fc8-17ae-4d73-8b1a-11dec418ae1d.png



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]