🍓 第十四章 AIoT 实验范例:Node-RED+TensorFlow.js
📄 一句话概括

给 Node-RED 装 AI 四件套——摄像头节点、编码节点、识别节点、显示节点——外加树莓派上必不可少的一步:tfjs-node 源码重编。

📝 本节和前面几节的关系

13-4 学过节点安装的三条路(面板/命令行/低内存兜底),本节原样复用;13-4 还埋过一条伏笔【Pi 5 上 GPIO 节点因底层库退场而全灭】——本章的 AI 节点也踩在同类底层库(tfjs-node 原生绑定)上,所以要先学会【怎么验证它真的装好了】再谈使用。

一、四件套各管一段

让一张图片在 Node-RED 里走完【拍 → 编码 → 识别 → 看】四步,需要四个社区节点包:

节点包 提供的节点 职责
node-red-contrib-webcam Webcam 在 dashboard 页面上调起浏览器摄像头拍照,输出 jpeg
node-red-node-base64 Base64 二进制与 base64 文本互相转换
node-red-contrib-tfjs-coco-ssd tensorflowCoco 本章主角:COCO-SSD 物体识别
node-red-contrib-image-output image 在 debug 侧栏之外直接显示图片,验收用

安装命令(13-4 的姿势,在 ~/.node-red 目录下执行):

cd ~/.node-red
npm install node-red-contrib-webcam node-red-node-base64 \
            node-red-contrib-tfjs-coco-ssd node-red-contrib-image-output
node-red-restart

看到什么算成功:重启后在编辑器节点面板搜索 tensorflowCoco、webcam、base64、image,四个都能搜到;Node-RED 启动日志里没有红色 ERROR。

二、树莓派专属的一步:tfjs-node 源码重编

tfjs-coco-ssd 节点依赖 tfjs-node——它不是纯 JavaScript,而是一个原生 C++ 绑定,npm 会尝试下载对应平台的预编译二进制。问题在于:ARM(树莓派)平台的预编译包经常对不上,装完直接报底层符号错误,而且报错信息完全不像【装失败】,更像【节点本身坏了】。

解法是官方 README 明写的那一条——源码重编:

cd ~/.node-red
npm rebuild @tensorflow/tfjs-node --build-from-source
node-red-restart

重编需要几分钟(本机要编译 C++),期间机器较忙属正常。识别报错先重编,这是树莓派上 AI 节点的第一诊断动作。

另一个现实约束是内存:模型加载加推理建议机器有 4GB 空闲内存量级。低配树莓派(1GB)跑 14-3 会很勉强,页面都能卡死;这也呼应 13-4 的教训——低内存机器别用面板装大包,命令行更稳。

三、单节点复用原则

tfjs-coco-ssd 节点每次部署都会重新加载一次模型(几百 MB 内存+数秒启动时间)。官方文档专门提醒:

这和 12 章讲 MediaPipe 时的理念一致:模型是重资源,加载一次、处处复用。

四、tensorflowCoco 节点吃什么

它的输入 msg.payload 接受四种形态,本课后面两节各用到其中一种:

形态 例子 来源
文件路径字符串 /home/pi/test.jpg File in / Exec 节点
jpeg 二进制 buffer Buffer [255, 216, ...] Webcam / http request(ret=bin)
https 图片 URL https://example.com/cat.jpg http request
base64 数据串 data:image/jpeg;base64,... Base64 节点转换后

配置面板上还有一个 scoreThreshold(置信度阈值,默认 0.5):低于它的检出结果直接丢弃。14-3 会专门练怎么调它。

输出也固定:msg.payload 变成一个数组,每个元素 {class, score, bbox}——类别名、置信度(0~1)、包围盒四角坐标。用 Debug 面板亲眼看一次输出结构,比背十遍文档都管用。

五、动手 Demo:装好四件套并验证

完整走一遍安装+重编+验证:

cd ~/.node-red
npm install node-red-contrib-webcam node-red-node-base64 \
            node-red-contrib-tfjs-coco-ssd node-red-contrib-image-output
npm rebuild @tensorflow/tfjs-node --build-from-source
node-red-restart

然后建一个最小流验证节点活着:Inject(按钮)→ File in(读一张本地 jpg)→ tensorflowCoco → Debug。File in 设为【单文件读为 buffer】,Inject 点下去,Debug 面板应出现识别结果数组(哪怕只是 [] 空数组也说明节点活着——空数组是【没认出东西】,不是【节点没跑】)。

看到什么算成功:Debug 输出形如:

[{"class": "person", "score": 0.874, "bbox": [112, 24, 380, 470]}, ...]

读结果:bbox 四个数是包围盒左上角 x、y 和宽、高(像素);数组有多个元素就是认出了多件东西;空数组配合 scoreThreshold 调低到 0.3 再试一次,通常就有结果了。

30 秒实验

在编辑器节点面板的搜索框里分别输入 coco、teachable,看搜索结果:

六、常见误区

  1. 识别报错就删了节点重装 —— 树莓派上第一嫌疑是 tfjs-node 预编译包不匹配,重装一百次也没用;先 npm rebuild @tensorflow/tfjs-node --build-from-source。
  2. 多拖几个 coco-ssd 节点会更强大 —— 正相反:模型被重复加载 N 份,启动变慢、内存翻倍;一个识别节点服务多来源才是正路。
  3. Webcam 节点能调树莓派的 CSI 相机 —— 它调起的是浏览器页面(dashboard)里的摄像头(USB 或笔记本内置);CSI 相机走的是 rpicam/picamera2 那条 Python 路(第十章),两套世界别混。
  4. Debug 输出 [] 说明识别节点坏了 —— 空数组的意思是【这张图里没有高于阈值的东西】;调低 scoreThreshold 或换张清晰的图再试。
自测三问(点开对答案) 1. 四件套分别负责流程的哪一段? Webcam 负责拍(浏览器摄像头出 jpeg)、Base64 负责编码转换、tensorflowCoco 负责识别、image 负责显示结果。 2. 树莓派上装完 coco-ssd 识别就报错,第一步做什么? `cd ~/.node-red && npm rebuild @tensorflow/tfjs-node --build-from-source` 然后重启 Node-RED——ARM 预编译包对不上是头号原因。 3. 为什么不把 tensorflowCoco 节点复制三个接三个摄像头? 每个节点都会加载一份模型(内存+启动时间全翻倍);应该把三路图片汇到一个节点复用。

相关笔记