资讯动态

在 Wio Terminal 上接入 IoT Edge 图像分类器:将水果质量检测从云端切换到本地边缘服务(IoT-For-Beginners)

发布时间:2026/9/16 20:44:55 来源:尧图企业网站定制
在 Wio Terminal 上接入 IoT Edge 图像分类器将水果质量检测从云端切换到本地边缘服务IoT-For-Beginners【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本指南讲解 IoT-For-Beginners 项目第 4 章第 3 课中面向 Wio Terminal 的硬件改造流程把fruit-quality-detector应用从调用云端 Custom Vision 分类服务切换为调用部署在本地 IoT Edge 设备上的图像分类器。完成改造后你的 Wio Terminal 将拍照并通过 HTTP 直接请求本机网络内的边缘分类服务获得ripe / unripe成熟/未成熟的实时预测结果整个过程不经过公网。文章完整覆盖配置修改、代码改造、编译上传与串口输出验证并结合仓库源码逐行解释改动原理。改造背景为什么把分类器搬到边缘在上一课第 2 课从设备端检查水果中Wio Terminal 把相机拍摄的 JPEG 图片通过 HTTPS 上传到云端 Custom Vision 服务进行分类。云端调用存在延迟、费用且图片数据要离开本地网络。第 3 课 Run your fruit detector on the edge 引入边缘计算思路将训练好的图像分类模型以 Docker 容器形式部署到本地网络内的 IoT Edge 设备上设备直接访问局域网内的分类服务。这样做的好处是响应更快、可离线工作、图片不出本地网络隐私性更强。本文的关联文档 wio-terminal.md本仓库同时提供 丹麦语翻译版就是 Wio Terminal 一侧的完整改造指南。IoT Edge 分类器的 REST API 端点部署在 IoT Edge 上的图像分类器对外暴露一个与云端 Custom Vision 相同的 REST API只是端点从 Azure 云端地址变成了本地地址http://IP地址或主机名/image其中IP地址或主机名替换为运行 IoT Edge 的那台计算机的 IP 地址或主机名如果代码运行在 IoT Edge 设备本机也可以使用localhost。请求方式是POST请求体为图片二进制内容响应为 JSON其中predictions数组里包含每个标签及其probability置信度。主文档 README.md 中给出了用curl直接验证该端点的示例curl --location \ --request POST http://IP地址或主机名/image \ --header Content-Type: image/png \ --data-binary 文件名由于这是本地网络内的服务而非 Azure 资源调用时不再需要Prediction-Key预测密钥——安全性改由内部网络安全策略保障而不是依赖公网端点和 API Key。这一差异正是本次改造的核心动因。改造步骤总览整个改造围绕从 HTTPS 证书 密钥的云端调用变为HTTP 无证书 无密钥的本地调用展开共涉及两个源文件config.h配置与main.cpp主逻辑工程位于 code-classify/wio-terminal 目录下PlatformIO 工程结构为fruit-quality-detector/src/。1. 打开fruit-quality-detector工程如果你还没有打开 Wio Terminal 的fruit-quality-detector工程请先打开它。工程根目录的 platformio.ini 指定了目标平台为seeed_wio_terminalAtmel SAMD 平台、Arduino 框架并声明了rpcWiFi、ArduinoJson、Seeed Arduino FS等依赖库。2. 清理config.h删除证书与密钥更新预测 URL云端版本中config.h 除了 WiFi 凭据和预测 URL 外还包含两项本地调用不再需要的内容PREDICTION_KEY云端 Custom Vision 服务的预测密钥CERTIFICATEMicrosoft Azure DigiCert Global Root G2 根证书用于 HTTPS 证书校验。因为 IoT Edge 分类器运行在HTTP而非 HTTPS上无需证书校验因此要把CERTIFICATE从config.h中删除PREDICTION_KEY同样不再需要一并删除。改造后的 config.h 只剩三个配置项最终形态如下#pragma once #include string using namespace std; // WiFi credentials const char *SSID SSID; const char *PASSWORD PASSWORD; const char *PREDICTION_URL URL;其中URL替换为你的边缘分类器地址例如const char *PREDICTION_URL http://192.168.1.100/image;3. 修改main.cpp切换为 HTTP 版 WiFi 客户端主逻辑文件 main.cpp 需要做三处改动全部围绕从 HTTPS 客户端降级为 HTTP 客户端第一处替换 include 指令。云端版本导入的是安全版 WiFi 客户端WiFiClientSecure.h现在改为标准 HTTP 版本#include WiFiClient.h第二处修改客户端对象声明。将全局声明的 WiFi 客户端对象改为 HTTP 版本WiFiClient client;第三处删除证书设置。在connectWiFi函数中删除设置根证书的语句// 删除这一行 client.setCACert(CERTIFICATE);改造后的connectWiFi只负责连接 WiFi不再做任何 TLS 证书绑定void connectWiFi() { while (WiFi.status() ! WL_CONNECTED) { Serial.println(Connecting to WiFi..); WiFi.begin(SSID, PASSWORD); delay(500); } Serial.println(Connected!); }第四处删除预测密钥请求头。在classifyImage函数中删除为请求添加Prediction-Key头的语句// 删除这一行 httpClient.addHeader(Prediction-Key, PREDICTION_KEY);源码级解读边缘调用如何完成分类完成上述改动后main.cpp 中的核心调用链路如下void classifyImage(byte *buffer, uint32_t length) { HTTPClient httpClient; httpClient.begin(client, PREDICTION_URL); httpClient.addHeader(Content-Type, application/octet-stream); int httpResponseCode httpClient.POST(buffer, length); if (httpResponseCode 200) { String result httpClient.getString(); DynamicJsonDocument doc(1024); deserializeJson(doc, result.c_str()); JsonObject obj doc.asJsonObject(); JsonArray predictions obj[predictions].asJsonArray(); for(JsonVariant prediction : predictions) { String tag prediction[tagName].asString(); float probability prediction[probability].asfloat(); char buff[32]; sprintf(buff, %s:\t%.2f%%, tag.c_str(), probability * 100.0); Serial.println(buff); } } httpClient.end(); }可以看到改造后的分类请求只保留了两个 HTTP 头Content-Type: application/octet-stream标识请求体为二进制图片流以及与边缘服务地址对应的 URL。调用流程为httpClient.begin(client, PREDICTION_URL)建立到边缘设备的 HTTP 连接httpClient.POST(buffer, length)把相机读入内存的 JPEG 字节流作为请求体直接 POST 到/image端点响应码为200时用 ArduinoJson工程依赖 platformio.ini 中的bblanchon/ArduinoJson 6.17.3解析返回的 JSON遍历predictions数组对每个预测项取出tagName与probability按标签: 百分比格式输出到串口其中概率值乘以 100 并以两位小数格式化。图片的采集来自 camera.h 封装的 ArduCAM OV2640 摄像头startCapture()触发捕获、captureReady()轮询 FIFO 完成标志、readImageToBuffer()通过 SPI 突发读取 JPEG 数据到内存缓冲区缓冲区大小即图片字节数。loop()中检测 Wio Terminal 的C 按钮WIO_KEY_C上拉输入模式按下后依次执行拍照、读缓冲、分类。编译、上传与运行验证完成代码修改后在 PlatformIO 中编译并上传到 Wio Terminal对应环境seeed_wio_terminal。将相机对准水果按下 C 按钮即可在串口监视器看到如下输出Connecting to WiFi.. Connected! Image captured Image read to buffer with length 8200 ripe: 56.84% unripe: 43.16%输出含义Connecting to WiFi..→Connected!connectWiFi成功连上config.h中配置的 WiFiImage capturedC 按钮触发拍照成功Image read to buffer with length 8200摄像头读出的 JPEG 数据共 8200 字节ripe: 56.84% / unripe: 43.16%边缘分类器判定当前画面中水果为成熟的概率约 56.84%未成熟约 43.16%。与上一课云端调用的输出格式完全一致说明边缘 REST API 与云端 Custom Vision API 的响应结构predictions→tagName/probability保持兼容这正是应用可以平滑切换端点、无需改动解析逻辑的原因。注意事项与后续优化HTTP 明文传输本方案使用 HTTP 而非 HTTPS图片在本地网络内明文传输。正如主文档 README.md 所述边缘部署不再依赖公网端点与 API Key安全模型应由内部网络策略负责如需加密传输应在边缘侧自行配置 TLS。模型再训练切到边缘分类后图片不再上传到 Custom Vision因此 Custom Vision 门户的 Predictions 页不会出现这些被分类的图片。若想用新样本改进模型需要自行设计图片留存与人工再标注流程。性能对比可以分别对云端与边缘端点做计时对比评估不同网络拓扑与硬件算力下的延迟差异并研究 GPU/加速硬件如 AI 加速板对边缘推理的加速效果。环境清理本课使用了 Azure IoT Hub、Azure Container Registry 等付费资源实验完成后请参考 clean-up.md 清理项目资源以节省费用。完成上述全部改造后你的水果质量分类程序就成功运行在边缘了——完整代码可对照仓库中的 code-classify/wio-terminal 目录部署清单可参考 code-deployment/deployment/deployment.json。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价