行业资讯
📅 2026/8/1 12:13:51
Grove Vision AI V2与XIAO ESP32-S3串口通信:构建稳定边缘AIoT应用
1. 项目缘起当“眼睛”遇见“大脑”最近在折腾一个智能识别小项目手头正好有一块Seeed Studio的Grove Vision AI V2模块和一块小巧的XIAO ESP32-S3。前者是一个集成了算力、摄像头和屏幕的“视觉AI模组”后者则是乐鑫ESP32-S3家族里以极致紧凑和丰富接口著称的“微控制器单元”。把它们俩凑在一起一个很自然的想法就冒出来了能不能让Vision AI V2这个“眼睛”负责看和识别然后把识别结果通过串口发给XIAO ESP32这个“大脑”再由“大脑”去执行更复杂的逻辑比如连接Wi-Fi上报数据、驱动其他执行器或者通过蓝牙发送通知这个组合的潜力很大。Vision AI V2本身就能运行一些轻量级的AI模型比如人脸检测、物体识别但它更偏向于一个独立的“端侧AI设备”逻辑控制能力相对有限。而XIAO ESP32-S3则弥补了这个短板它拥有双核240MHz的处理器、充足的RAM和Flash以及Wi-Fi、蓝牙等无线连接能力非常适合做“决策中枢”。把它们结合就构成了一个典型的“感知-决策-执行”边缘AI系统雏形。网上关于Vision AI V2的教程大多集中在它自带的Arduino例程上也就是用一块主板比如Seeed Studio XIAO nRF52840 Sense直接驱动它完成识别并在自带的屏幕上显示。但关于如何让它与另一块独立的MCU比如我们手头的XIAO ESP32-S3进行稳定、高效的通信并把识别数据真正“用起来”的资料就比较零散了。这正是我这次想深入探索并分享的核心打通Grove Vision AI V2与XIAO ESP32-S3之间的数据链路构建一个可扩展的AIoT应用框架。2. 硬件拆解与连接不仅仅是插上线那么简单在开始写代码之前我们必须先搞清楚手头这两块板子的“脾气”以及它们如何“对话”。2.1 Grove Vision AI V2不止是摄像头Grove Vision AI V2的核心是一颗算力约为0.1TOPS的AI协处理器专门用于加速神经网络推理。它集成了一个200万像素的摄像头、一块1.69英寸的LCD屏幕以及一个六轴IMU加速度计陀螺仪。最重要的是它的接口一个Grove I2C接口和一个Grove UART接口。I2C接口通常用于配置模块参数、读取IMU数据等。在标准Arduino库中我们通过I2C向模块发送指令例如切换模型、设置识别阈值。UART接口这是本次项目的数据高速公路。当Vision AI V2完成图像识别后会将识别结果如物体类别、置信度、边界框坐标通过这个串口以特定的数据格式打印出来。我们的XIAO ESP32-S3就需要监听这个串口解析这些数据。模块上电后屏幕会显示预装的AI模型如“Face Detection”和实时画面识别到的结果会以矩形框和标签的形式叠加显示在屏幕上。同时串口会持续输出日志和数据。2.2 XIAO ESP32-S3小而强大的连接中枢XIAO ESP32-S3的尺寸虽然只有21x17.5mm但功能齐全。它基于ESP32-S3R8双核240MHz Xtensa处理器8MB PSRAM16MB Flash。其引脚排布兼容Arduino并提供了多个UART、I2C、SPI接口。对于本项目我们最关心的是它的UART1。我们将用UART1的RX接收和TX发送引脚与Vision AI V2的UART接口进行通信。2.3 硬件连接图与供电考量连接非常简单但有两个关键点引脚连接Vision AI V2 (UART)的RX-XIAO ESP32-S3的TX1(Pin D6)Vision AI V2 (UART)的TX-XIAO ESP32-S3的RX1(Pin D7)Vision AI V2的VCC-XIAO ESP32-S3的5V或3V3(注意)Vision AI V2的GND-XIAO ESP32-S3的GND供电电压的坑这是第一个容易出错的地方。XIAO ESP32-S3的VCC引脚输出是3.3V。而Grove Vision AI V2的UART接口逻辑电平虽然是3.3V兼容但其模块整体的供电电压VCC要求是5V。如果只接3.3V模块可能无法正常工作或者屏幕背光异常、摄像头初始化失败。重要提示务必使用外部5V电源如USB充电器通过XIAO ESP32-S3的USB-C口供电或者使用一个5V升压模块。确保整个系统的电源能提供足够的电流建议500mA以上。不要试图用XIAO的3.3V引脚给Vision AI V2供电。连接好后给XIAO ESP32-S3上电Vision AI V2的屏幕应该会亮起并开始运行预装模型。3. 软件环境搭建与基础通信测试硬件连通后下一步是让软件跑起来。我们需要在两个设备上分别准备程序。3.1 XIAO ESP32-S3侧Arduino IDE配置与串口监听首先在Arduino IDE中配置好ESP32-S3开发环境。确保已安装ESP32开发板支持包可以通过开发板管理器添加esp32。选择开发板为“XIAO ESP32S3”端口选择正确的串口。我们的第一个程序极其简单仅仅监听UART1并把收到的一切数据原样转发到电脑的串口监视器让我们看看Vision AI V2到底在“说”什么。// XIAO_ESP32S3_UART_Listener.ino // 功能监听UART1并将数据转发到Serial(USB) #define RXD1 7 // XIAO ESP32-S3的RX1引脚 #define TXD1 6 // XIAO ESP32-S3的TX1引脚 void setup() { // 初始化与电脑通信的串口波特率115200 Serial.begin(115200); // 初始化与Vision AI V2通信的串口波特率115200 Serial1.begin(115200, SERIAL_8N1, RXD1, TXD1); Serial.println(XIAO ESP32-S3 UART Listener Ready.); Serial.println(Waiting for data from Grove Vision AI V2...); } void loop() { // 如果Serial1来自Vision AI有数据可读 if (Serial1.available()) { // 读取一个字节 char c Serial1.read(); // 将该字节发送到电脑串口监视器 Serial.write(c); } // 如果电脑有发送数据可选用于测试双向通信 if (Serial.available()) { Serial1.write(Serial.read()); } }将这段代码上传到XIAO ESP32-S3。打开Arduino IDE的串口监视器波特率设置为115200。你应该会看到类似下面的滚动信息[I][识别模块] 系统启动完成运行人脸检测模型。 [W][摄像头] 自动曝光调整中... [D][AI推理] 帧率: 12.3 FPS ...这些是Vision AI V2的系统日志。但我们需要的是结构化的识别结果数据。通常这些数据会以更规整的格式打印比如JSON或自定义的文本格式。我们需要在滚动日志中找到它们。例如当检测到人脸时你可能会看到{type:face,id:0,x:120,y:80,width:50,height:50,confidence:0.92}或者是一种更简单的格式Detect: face (120,80) w50 h50 conf:0.92这一步至关重要你需要观察并记录下Vision AI V2输出识别结果的具体格式。不同固件版本或不同模型输出格式可能略有差异。记下这个格式它是我们后续解析数据的依据。3.2 Vision AI V2侧固件与模型确认Vision AI V2开箱即用预装了固件和示例模型。为了确保最佳兼容性建议访问Seeed Studio的Wiki页面检查是否有最新的固件更新。更新固件通常需要使用一个专门的烧录工具如pyocd和.bin文件过程稍复杂但如果当前版本运行稳定可以暂不更新。更重要的是确认当前运行的AI模型。通过模块上的按钮或通过I2C发送指令如果有对应的库支持可以切换模型。确保它运行的是你希望测试的模型例如“Face Detection”或“Object Detection (20 classes)”。4. 核心挑战稳定解析串口数据流直接从串口读取字节并打印很简单但要从一个持续不断、可能夹杂着系统日志的数据流中稳定、准确地提取出我们需要的结构化识别数据是本项目真正的难点。这涉及到数据协议解析和状态机设计。4.1 理解数据流的特点Vision AI V2的串口输出通常是这样的非结构化日志以[I]、[W]、[D]开头的调试信息行尾有换行符\n。结构化数据我们需要的识别结果可能是一行完整的JSON也可能是一行特定前缀的文本行尾也有\n。数据可能连续或突发在没有识别到目标时可能只输出日志一旦识别到可能会连续多帧输出数据造成数据流“拥堵”。数据完整性在MCU端由于串口中断和循环处理一个完整的数据行可能会被loop()函数切割成多次接收。我们不能假设一次Serial1.available()就能读到一整行。4.2 实现一个简单的行缓冲解析器我们需要一个缓冲区来暂存从串口读取到的字符直到遇到换行符\n才认为收到了一条完整的信息然后对其进行解析。以下是XIAO ESP32-S3上改进后的代码包含了一个行缓冲区和简单的关键词过滤解析// XIAO_ESP32S3_VisionAI_Parser.ino #define RXD1 7 #define TXD1 6 #define BUFFER_SIZE 256 // 缓冲区大小根据最长数据行调整 char serialBuffer[BUFFER_SIZE]; int bufferIndex 0; void setup() { Serial.begin(115200); Serial1.begin(115200, SERIAL_8N1, RXD1, TXD1); Serial.println(Vision AI Data Parser Started.); } void loop() { // 读取串口数据到缓冲区 while (Serial1.available() 0) { char inChar Serial1.read(); // 如果收到换行符说明一条消息结束 if (inChar \n) { serialBuffer[bufferIndex] \0; // 字符串终止符 processReceivedLine(serialBuffer); bufferIndex 0; // 重置缓冲区索引 } else { // 将字符存入缓冲区防止溢出 if (bufferIndex BUFFER_SIZE - 1) { serialBuffer[bufferIndex] inChar; bufferIndex; } else { // 缓冲区溢出清空并报错或采取其他策略 Serial.println([ERROR] Serial buffer overflow!); bufferIndex 0; } } // 添加一个小延迟防止过于频繁的读取导致任务阻塞对于ESP32双核这不是必须但有好习惯 delay(1); } } void processReceivedLine(char* line) { // 1. 首先打印原始行用于调试 // Serial.print(Raw: ); // Serial.println(line); // 2. 过滤我们只关心包含特定关键词的行例如“Detect:”或“{” // 假设数据格式为: Detect: face (120,80) w50 h50 conf:0.92 if (strstr(line, Detect:) ! NULL) { Serial.print([Parsed] ); Serial.println(line); // 3. 开始解析具体内容 // 这里以简单的字符串分割为例实际应用建议使用更健壮的解析库如ArduinoJson如果是JSON格式 // 例如提取置信度 char* confStr strstr(line, conf:); if (confStr ! NULL) { float confidence atof(confStr 5); // “conf:”后面是数字 Serial.print(Confidence: ); Serial.println(confidence, 2); // 打印两位小数 // 4. 根据置信度做出决策 if (confidence 0.8) { Serial.println( High confidence detection! Triggering action...); // 这里可以触发其他动作比如点亮LED发送网络请求等 // digitalWrite(LED_BUILTIN, HIGH); // sendToServer(line); } } } // 如果是JSON格式例如以“{”开头 else if (line[0] {) { Serial.println([JSON Data Received]); // 使用ArduinoJson库解析需提前安装 // parseJSONData(line); } }这个代码框架实现了一个最基础的解析流程。processReceivedLine函数是关键你可以在这里根据实际的数据格式编写更精确的解析逻辑。4.3 使用ArduinoJson解析JSON格式数据如果Vision AI V2输出的是JSON格式这是更理想和通用的方式强烈推荐使用ArduinoJson库。它轻量且高效非常适合在MCU上使用。在Arduino IDE的库管理中搜索并安装 “ArduinoJson”。修改processReceivedLine函数中处理JSON的部分#include ArduinoJson.h // 包含库 void processReceivedLine(char* line) { // 检查是否是JSON简单判断以‘{’开头 if (line[0] {) { StaticJsonDocument256 doc; // 根据JSON大小调整256字节通常足够 DeserializationError error deserializeJson(doc, line); if (error) { Serial.print(JSON解析失败: ); Serial.println(error.c_str()); return; } // 提取字段 const char* type doc[type]; // face int id doc[id]; // 0 int x doc[x]; int y doc[y]; int width doc[width]; int height doc[height]; float confidence doc[confidence]; Serial.printf(Parsed - Type: %s, ID: %d, Pos:(%d,%d), Size:%dx%d, Conf:%.2f\n, type, id, x, y, width, height, confidence); // 基于解析的数据进行后续处理... if (strcmp(type, face) 0 confidence 0.85) { triggerAlarm(); } } // ... 处理其他格式 }5. 从数据到应用构建一个简单的安防监控原型现在我们已经能稳定地获取并解析识别数据了。让我们把这些数据用起来构建一个简单的概念验证应用当检测到高置信度的人脸时通过XIAO ESP32-S3的Wi-Fi向手机发送一条通知。5.1 系统设计思路感知层Grove Vision AI V2持续进行人脸检测。数据链路层XIAO ESP32-S3通过UART接收并解析检测结果。决策与网络层XIAO ESP32-S3判断是否满足触发条件如人脸置信度 0.9如果满足则通过Wi-Fi连接互联网向一个通知服务如IFTTT Webhooks、Bark、Telegram Bot发送HTTP请求。应用层手机接收到推送通知。5.2 代码实现集成Wi-Fi与HTTP请求我们需要在之前的解析代码基础上加入Wi-Fi连接和HTTP客户端功能。这里以使用IFTTT Webhooks为例因为它非常简单。#include WiFi.h #include HTTPClient.h #include ArduinoJson.h // 你的Wi-Fi凭证 const char* ssid 你的Wi-Fi名称; const char* password 你的Wi-Fi密码; // IFTTT Webhooks 设置 const char* iftttWebhookKey 你的IFTTT_Webhooks密钥; const char* iftttEventName vision_ai_alert; // 你在IFTTT上创建的事件名 String iftttURL https://maker.ifttt.com/trigger/ String(iftttEventName) /with/key/ String(iftttWebhookKey); // 全局状态变量 unsigned long lastDetectionTime 0; const long detectionCooldown 10000; // 防抖时间10秒内不重复发送 void setup() { Serial.begin(115200); Serial1.begin(115200, SERIAL_8N1, RXD1, TXD1); // 连接Wi-Fi WiFi.begin(ssid, password); Serial.print(Connecting to WiFi); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(\nConnected! IP address: ); Serial.println(WiFi.localIP()); Serial.println(Vision AI Security Monitor Ready.); } void loop() { // 原有的串口数据读取和行缓冲解析代码略 // 假设在 processReceivedLine 中解析到数据后调用一个函数 // handleDetectionResult(type, confidence, x, y); } void handleDetectionResult(const char* type, float confidence, int x, int y) { // 1. 判断是否为关心的类型且置信度达标 if (strcmp(type, face) 0 confidence 0.9) { // 2. 防抖处理避免短时间内连续触发 unsigned long now millis(); if (now - lastDetectionTime detectionCooldown) { Serial.println(Cooldown, skip notification.); return; } lastDetectionTime now; // 3. 准备发送通知 Serial.println( High-confidence face detected! Sending notification...); sendIftttNotification(confidence, x, y); } } void sendIftttNotification(float conf, int posX, int posY) { if (WiFi.status() ! WL_CONNECTED) { Serial.println(WiFi not connected!); return; } HTTPClient http; http.begin(iftttURL); http.addHeader(Content-Type, application/json); // 构建JSON消息体 StaticJsonDocument200 doc; doc[value1] Face Detected; doc[value2] String(conf, 2); // 置信度保留两位小数 doc[value3] String(() String(posX) , String(posY) ); String requestBody; serializeJson(doc, requestBody); int httpResponseCode http.POST(requestBody); if (httpResponseCode 0) { String response http.getString(); Serial.printf(IFTTT通知发送成功响应码: %d\n, httpResponseCode); Serial.println(响应内容: response); } else { Serial.printf(IFTTT通知发送失败错误码: %d\n, httpResponseCode); Serial.println(错误信息: http.getString()); } http.end(); }5.3 在IFTTT上配置通知注册并登录IFTTT。创建一个新的Applet。“If This” 选择 “Webhooks”触发事件填写vision_ai_alert与代码中iftttEventName一致。“Then That” 选择 “Notifications”编辑消息内容可以使用{{Value1}}{{Value2}}{{Value3}}来接收代码中发送的数据。保存Applet。现在当Grove Vision AI V2检测到高置信度人脸时你的手机就会收到一条推送通知内容包含检测到的位置和置信度。6. 优化、调试与扩展思考一个基础的系统跑通了但要让它稳定、可靠、实用还有很长的路要走。这里分享几个关键的优化点和扩展方向。6.1 稳定性优化错误处理与看门狗串口通信超时与复位如果长时间收不到Vision AI V2的数据可能是模块卡死。可以添加一个软件看门狗定时器在超时后尝试向Vision AI V2发送一个重启指令如果协议支持或者重新初始化串口。JSON解析容错使用DeserializationError仔细检查错误类型对损坏的数据包进行丢弃避免程序崩溃。Wi-Fi重连机制网络可能不稳定。在loop()中检查WiFi.status()如果断开连接尝试自动重连。可以使用非阻塞式的重连逻辑避免阻塞主循环。电源管理如果使用电池供电需要考虑功耗。可以让XIAO ESP32-S3在空闲时进入轻量级睡眠模式由Vision AI V2的识别结果通过GPIO中断来唤醒它。6.2 性能优化数据流与内存管理缓冲区大小BUFFER_SIZE需要足够大以容纳最长的一行数据但也不宜过大以免浪费宝贵的RAM。256或512字节通常是安全的起点。非阻塞式设计loop()中的while (Serial1.available())在数据量大时可能阻塞过久。对于ESP32可以考虑使用FreeRTOS任务将串口读取和数据处理放在一个独立的低优先级任务中通过队列与主任务通信。减少串口打印调试完成后尽量减少Serial.print()的使用特别是高频打印这会影响程序性能。6.3 功能扩展不止于通知本地报警驱动一个蜂鸣器或LED在检测到特定目标时发出声光报警。图像捕获与上传虽然Vision AI V2的原始图像数据不易获取但可以探索其SDK看是否支持在检测到事件时通过串口或I2C命令让其抓拍一张JPEG图片并存储到SD卡如果模块支持或者通过XIAO ESP32-S3的Wi-Fi将缩略图上传到云存储。多模块协同一个XIAO ESP32-S3可以连接多个传感器如温湿度、PIR人体感应结合视觉识别结果做出更综合的判断。例如只有PIR触发且人脸识别通过时才开门。模型自定义深入研究Grove Vision AI V2的模型训练和部署工具链训练一个识别特定物品如你的宠物、某个工具的模型然后部署到模块上实现高度定制化的应用。6.4 调试技巧串口监听与逻辑分析仪双串口监听在开发时可以同时打开两个串口监视器窗口一个监听XIAO ESP32-S3与电脑的Serial另一个通过USB转TTL工具直接监听Vision AI V2的原始输出。这能帮你快速定位问题是出在数据源、通信链路还是解析代码。使用逻辑分析仪如果遇到奇怪的通信问题如数据丢失、乱码用逻辑分析仪抓取UART引脚上的波形可以直观地看到起始位、数据位、停止位和波特率是否匹配是排查硬件层问题的终极手段。把Grove Vision AI V2和XIAO ESP32-S3组合起来远不止是连几根线、跑个示例代码那么简单。它涉及到硬件接口的匹配、串口通信协议的解析、嵌入式系统的稳定编程以及云服务的集成。这个过程里最花时间的往往不是让代码跑起来而是让它在各种边界条件下网络抖动、数据异常、长时间运行依然能可靠工作。我自己的体会是前期把数据解析和错误处理的框架搭得健壮一些后期增加新功能时会顺畅得多。这个组合的灵活性很高一旦打通了数据流这个“任督二脉”后面无论是做智能门禁、仓库巡检还是互动艺术装置都只是在此基础上添加不同的“决策逻辑”和“执行动作”而已。