备注:本文是使用 SenseCAP K1100 传感器原型套件的相关教程,翻译自 CNX Software 泰国站。文章将会展示如何使用 Arduino 可编程 Wio 终端、Grove 相机模块和 LoRa-E5 模块将计算机视觉、AI 视觉与 LoRaWAN 相结合,接着再使用 Node-RED 和 InfluxDB 等开源工具连接到私有 LoRaWAN 网络。
在SenseCAP K1100 教程的第一部分,我们将各种传感器连接到了 Wio 终端板,并将其设置为泰国频段—AS923,接着通过 LoRa-E5 LoRaWAN 模块无线传输数据。在本文中,我们会将 SenseCAP K1100 传感器原型套件的 Grove Vision AI 模块部分连接到 Wio 终端,接着训练模型捕捉人脸,并将摄像头的结果显示在计算机上。在这之后,我们也会评估人脸检测模型准确度的结果。最后,我们将使用 LoRa-E5 模块将数据(例如:Confidence 置信度数据)发送到私有的 LoRaWAN 物联网平台系统。
为了了解人工智能是什么?它是如何服务于各类业务和组织?我们先定义一些术语:
- 人工智能(AI) 将类人智能引入计算机,目标是通过让计算机能够处理特定信息(例如图像、音频)从而使计算机像人类一样智能。而且需要保证每次处理数据时,计算机都能计算出最接近标准的结果
- 机器学习 (ML)是 AI 的一个子类别,它使用算法自动学习洞察力并从数据中识别模式。算法与由多个样本组成的模型数据集(训练集)一起使用,从而获得可立刻使用的结果
- 深度学习 (DL)通过模仿人类神经系统的功能,它比机器学习更进了一步。它利用大型神经网络系统重叠多个层的方式学习样本数据。这样就可以将获得的信息用于查找模式或对具有记忆面孔、客户行为等能力的数据进行分类
Grove Vision AI 模块
Grove AI Vision 模块带有一个支持 TinyML(微型机器学习)算法的小型 AI 摄像头。它可以实现矽递科技( Seeed Studio)提供的各种 AI 功能,例如:人员检测、宠物检测、人数统计、物体识别等等,用户甚至还可以通过机器学习的训练工具生成自己的模型从而采用该模型。它十分方便部署且可以在几分钟内获得结果。该解决方案通过 2.5mW/帧摄像头和低功耗 LoRaWAN 连接 (19.5mW) 就能实现超低功耗。
Grove Vision AI 模块还带有一个麦克风和一个 6 轴运动传感器,因此它不只能用于 AI 视觉。
硬件要求
我们的 AI 视觉和 LoRaWAN 项目需要用到以下项目(粗体项目是 SenseCAP K1100 套件的一部分):
- Wio终端
- Grove Vision AI 模块
- Grove LoRa-E5 模块
- 2 根 USB Type-C 数据线
- 电脑
部署预训练的 AI Vision 模型和 Arduino sketch
矽递科技还提供了预训练模型,我们可以使用这些模型来加快我们对 Vision AI 相机模块的学习体验,包括人脸识别、人脸身体检测。现在我们看看要如何使用它们:
- 第 1 步 – 将Grove Vision AI 模块通过USB Type-C 电缆与你的计算机连接
- 第 2步 – 按 Vision AI 模块上的 BOOT 按钮两次后即可进入 Boot 模式,然后它应该就会在你的计算机中显示为“GROVEAI”驱动器,其中包含 2 个文件:HTM 和 INFO_UF2.TXT。
- 第 3 步- 我们现在选择具有预训练“人脸识别”模型的UF2固件 ( grove_ai_camera_v01-00-0x10000000.uf2 )。将 UF2 固件复制到 GROVEAI 驱动器,大家应该会看到 Vision AI 模块上指示灯闪烁,这就表明它正在执行固件更新
注意:如果预训练模型带有多个文件,则一次只能复制一个文件。从第一个文件开始,等到闪烁的灯熄灭,然后再次进入 Bootloader 模式并复制下一个文件序列,直到全部完成 - 第 4步 – 当 Vision AI 模块连接到计算机时,就可以使用 Grove I2C 线将其连接到 Wio 终端,然后就可以将 USB type-C 电缆连接到 Wio 终端控制器。
COM4 是 Wio 终端,COM8 是 Grove Vision AI 模块
- 第 5步 – 通过下载 Seeed-Grove-Vision-AI-Moudle.zip添加 Vision AI 模块 Arduino 库。然后转到 Arduino IDE 的顶部菜单,并选择 Sketch -> Include Library -> Add .ZIP Library,接着再选择 Seeed-Grove-Vision-AI-Moudle
- 第 6 步 – 通过下载zip 添加 LoRa-E5 模块 Arduino 库。然后选择Include Library -> Add .ZIP Library,然后选择 Disk91_LoRaE5
- 第 7 步- 将LoRa-VisionAI-FaceDetection.ino 示例代码复制到 Arduino IDE 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
// LoRaWAN + Vision AI Face Detection + TFT LCD // by.. Ninephon kongangkab <ninephon9@gmail.com> #include <SoftwareSerial.h> #include "Seeed_Arduino_GroveAI.h" #include <Wire.h> #include "TFT_eSPI.h" #include "Seeed_FS.h" //Including SD card library #include "RawImage.h" //Including image processing library TFT_eSPI tft; GroveAI ai(Wire); uint8_t state = 0; SoftwareSerial mySerial(A0, A1); // RX, TX static char recv_buf[512]; static bool is_exist = false; static bool is_join = false; static int at_send_check_response(char *p_ack, int timeout_ms, char *p_cmd, ...) { int ch; int num = 0; int index = 0; int startMillis = 0; va_list args; memset(recv_buf, 0, sizeof(recv_buf)); va_start(args, p_cmd); mySerial.printf(p_cmd, args); Serial.printf(p_cmd, args); va_end(args); delay(200); startMillis = millis(); if (p_ack == NULL) { return 0; } do { while (mySerial.available() > 0) { ch = mySerial.read(); recv_buf[index++] = ch; Serial.print((char)ch); delay(2); } if (strstr(recv_buf, p_ack) != NULL) { return 1; } } while (millis() - startMillis < timeout_ms); return 0; } static void recv_prase(char *p_msg) { if (p_msg == NULL) { return; } char *p_start = NULL; int data = 0; int rssi = 0; int snr = 0; p_start = strstr(p_msg, "RX"); if (p_start && (1 == sscanf(p_start, "RX: \"%d\"\r\n", &data))) { Serial.println(data); } p_start = strstr(p_msg, "RSSI"); if (p_start && (1 == sscanf(p_start, "RSSI %d,", &rssi))) { Serial.println(rssi); } p_start = strstr(p_msg, "SNR"); if (p_start && (1 == sscanf(p_start, "SNR %d", &snr))) { Serial.println(snr); } } void setup(void) { //Initialise SD card if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) { while (1); } tft.begin(); tft.setRotation(3); drawImage<uint16_t>("cnxsoftware.bmp", 0, 0); //Display this 16-bit image in sd card Wire.begin(); Serial.begin(115200); mySerial.begin(9600); delay(5000); Serial.print("E5 LORAWAN TEST\r\n"); if (ai.begin(ALGO_OBJECT_DETECTION, MODEL_EXT_INDEX_1)) // Object detection and pre-trained model 1 { Serial.print("Version: "); Serial.println(ai.version()); Serial.print("ID: "); Serial.println( ai.id()); Serial.print("Algo: "); Serial.println( ai.algo()); Serial.print("Model: "); Serial.println(ai.model()); Serial.print("Confidence: "); Serial.println(ai.confidence()); state = 1; } else { Serial.println("Algo begin failed."); } if (at_send_check_response("+AT: OK", 100, "AT\r\n")) { is_exist = true; at_send_check_response("+ID: DevEui", 1000, "AT+ID=DevEui,\"2CF7xxxxxxxx034F\"\r\n"); at_send_check_response("+ID: AppEui", 1000, "AT+ID=AppEui,\"8000xxxxxxxx0009\"\r\n"); at_send_check_response("+MODE: LWOTAA", 1000, "AT+MODE=LWOTAA\r\n"); at_send_check_response("+DR: AS923", 1000, "AT+DR=AS923\r\n"); at_send_check_response("+CH: NUM", 1000, "AT+CH=NUM,0-2\r\n"); at_send_check_response("+KEY: APPKEY", 1000, "AT+KEY=APPKEY,\"8B91xxxxxxxxxxxxxxxxxxxxxxxx6545\"\r\n"); at_send_check_response("+CLASS: A", 1000, "AT+CLASS=A\r\n"); at_send_check_response("+PORT: 8", 1000, "AT+PORT=8\r\n"); delay(200); is_join = true; } else { is_exist = false; Serial.print("No E5 module found.\r\n"); } } void loop(void) { if (is_exist) { int ret = 0; char cmd[128]; if (is_join) { ret = at_send_check_response("+JOIN: Network joined", 12000, "AT+JOIN\r\n"); if (ret) { is_join = false; } else { Serial.println(""); Serial.print("JOIN failed!\r\n\r\n"); delay(5000); } } else { if (state == 1) { if (ai.invoke()) // begin invoke { while (1) // wait for invoking finished { CMD_STATE_T ret = ai.state(); if (ret == CMD_STATE_IDLE) { break; } delay(20); } uint8_t len = ai.get_result_len(); // receive how many people detect if(len) { Serial.print("Number of people: "); Serial.println(len); object_detection_t data; //get data for (int i = 0; i < len; i++) { Serial.println("result:detected"); Serial.print("Detecting and calculating: "); Serial.println(i+1); ai.get_result(i, (uint8_t*)&data, sizeof(object_detection_t)); //get result Serial.print("confidence:"); Serial.print(data.confidence); Serial.println(); sprintf(cmd, "AT+CMSGHEX=\"%04X %04X\"\r\n", len, data.confidence); ret = at_send_check_response("Done", 10000, cmd); if(!ret){ break; Serial.print("Send failed!\r\n\r\n"); } else{ recv_prase(recv_buf); } } } else { Serial.println("No identification"); } } else { delay(1000); Serial.println("Invoke Failed."); } } } } else { delay(1000); } delay(500); } |
- 第 8 步- 确保编辑 LoRaWAN 配置程序:
- 8 字节 DevEui 编号
- 8 字节 AppvEui 编号
- 16 字节 APPKEY 编号
- 设置 OTAA(无线激活)连接
- 为所再国家设置频段,例如:我在泰国使用的是 AS923频段
- 第 9 步- 将程序上传到 Wio 终端
- 第 10 步 – 打开串行监视器就可以查看人脸检测算法的输出,特别是两个参数可以注意:
- “人数”:检测到的人数,或者说从技术上来讲的人数,也就是检测到的面孔数量
- “置信度”:人脸检测算法的置信度百分比
- 第 11 步 – 使用 Google Chrome 或 Microsoft Edge 浏览器访问此链接,从而检查相机的输出
- 第 12 步- 单击 SenseCAP AI Vision 网页中的连接按钮,选择 Grove AI-Paired,然后单击连接
- 第 13 步- 握住 Grove Vision AI 模块,将摄像头对准人或人的图像。识别出人脸人的百分比的置信度一起显示在网络浏览器中的阅读框中
这里有一个简短的演示,可以展示 Grove Vision AI 模块的运行情况。相关视频链接,点击此处可查看。
私有 LoRaWAN IoT 本地平台
到目前为止,我们只演示了计算机视觉,但我们还没有使用到 LoRa-E5 模块。之后我们会依赖跟第一部分一样的“开源驱动”私有 LoRaWAN 物联网平台,比较不一样的只是上次使用的环境传感器被 Grove Vision AI 模块替代了。
- ChirpStack开源 LoRaWAN 网络和应用服务器,注册 LoRaWAN IoT 设备编号并通过充当发送者的 MQTT 代理、以AES128 格式解密的方式接收到的数据。
- 用于编程的基于Node-RED flow的开发工具。它是通过 MQTT 协议从 ChirpStack 接收(订阅)并从有效payload中获取数据并根据 BASE64 格式对其进行解码。它将传感器数据存储在 InfluxDB 数据库中。
- InfluxDB开源时序数据库用于存储传感器和LoRaWAN网关数据,并自动按时序排序,方便我们分析任意时间段的数据。
- Grafana实时仪表板允许用户可视化来自 InfluxDB 数据库的数据,此时显示的是检测到的人数和推理置信度。
最后总结
- 现在我们已经非常熟悉 SenseCAP K1100 传感器原型了,包括:Grove 传感器、Arduino 可编程 Wio 终端,以及将传感器数据发送到 LoRaWAN 网关的 LoRa-E5 模块。我觉得体验越多,得到的乐趣就越大,因为可以使用40 针 GPIO 接头将许多模拟或数字传感器接入,或者使用具有 I2C 或 SPI 接口的现成的传感器模块。
- 无需按任何按钮Wio 终端板就可以从 Arduino IDE 自动编程。自动进入 Automatic Bootloader 模式如果有问题的话,矽递科技设计的固件也支持手动 Bootloader 模式,可以通过快速滑动两次开关进入。进入手动 Bootloader 模式的说明你们可以在评测的第一部分找到。
- 因为 LoRaWAN 的连接过程比 Wi-Fi 和蓝牙更复杂,我不得不依靠我在 LoRaWAN 方面的知识和经验来配置长距离地无线传输数据。如果矽递科技可以开发一种无需任何编码就能连接的新固件,那就太好了。
- SenseCAP K1100 是一款功能强大且可靠的套件,它对于小学、中学和高等教育都特别有用,而且可以集成到 STEM(科学、技术、工程和数学)课程的教材中。
虽然 SenseCAP K1100 原型传感器套件可用于AI计算机视觉与 LoRaWAN 相结合,而且非常适合教育和原型设计,如果用户计划在现场部署此类解决方案,记得要选择工业级传感器。因为工业级传感器应该能够承受雨、热和灰尘等元素,而且也更加可靠。有一个很典型的应用就是—工业级 SenseCAP A1101 LoRaWAN 视觉 AI 传感器,它在矽递科技网页上的售价是 79 美元。
最后,十分感谢矽递科技为我本次的评测赠送 SenseCAP K1100 传感器原型套件。它的售价是 99 美元,运费需要另外付。

文章翻译者:Jacob,嵌入式系统测试工程师、RAK高级工程师,物联网行业多年工作经验,熟悉嵌入式开发、测试各个环节,对不同产品有自己专业的分析与评估。