摘要:拒绝枯燥的按钮启动!本项目利用二哈识图2捕捉手势(点赞、Yeah、握拳),通过行空板K10与MQTT联动大屏粒子特效。视觉代码完全由 Google AI Studio 生成,是一次“用AI代码展示AI视觉”的硬核尝试。
一、 项目简介
🔖 项目概述
本项目专为校园科技节或展会设计了一套“沉浸式”的启动仪式装置。区别于传统的“按按钮”或“剪彩”,本装置利用 二哈识图2 进行边缘 AI 视觉识别,捕捉参与者的手势动作(大拇指、Yeah、握拳)。通过 行空板 K10 进行逻辑处理与物联网通讯(MQTT),联动 PC 端的大屏粒子特效(可延申拓展现场物理灯光控制)。
✨ 创意亮点
值得一提的是,本项目的上位机视觉代码采用了 AIGC(Google AI Studio) 辅助生成,实现了“用 AI 生成的代码来展示 AI 视觉的魅力”,构建了从感知到生成的全链路 AI 体验。
二、 硬件与软件清单
2.1 硬件清单
| 设备名称 | 数量 | 说明 |
| 行空板 K10 | 1 | 核心主控,带彩屏,负责逻辑与网络 |
| 二哈识图 2 | 1 | AI视觉传感器,负责手势识别 |
| PC 电脑 | 1 | 运行 SIOT 服务器及大屏展示网页 |
| 连接线 | 1 | I2C 线 (PH2.0) |
2.2 软件工具
💠Mind+ V2.0:编写 K10 控制程序
💠SIOT v2:局域网 MQTT 服务器
💠Google AI Studio:生成 p5.js 视觉特效代码
三、 制作步骤
步骤1 二哈识图2 手势训练
1. 二哈识图2 固件更新至 V1.2
最新版本HUSKYLENS 2固件:HUSKYLENSV2v1.2[251208]
固件更新教程:二哈识图 2 固件更新教程
2. 手势识别训练
我们将二哈识图2设置为“手势识别”模式,长按学习键分别录制三种手势:

ID 1:大拇指(点赞) -> 对应大屏“能量汇聚”
ID 2:Yeah(剪刀手) -> 对应大屏“情感注入”
ID 3:握拳(力量) -> 对应大屏“最终启动”
步骤2 SIOT 服务器搭建
SIoT是一个针对学校场景的开源免费的MQTT服务器软件, 可一键创建本地物联网服务器。
SIOT包含一个MQTT服务器和一个数据库以及一个网页界面,MQTT服务器负责数据的转发以及判断是否存储,网页界面可以方便的查看数据或者简单的测试程序。
SIoT V2是新的升级,性能提升,可以支持更快的速度,同时使用QOS区分了快速数据以及存入数据的数据以应对不同的使用场景,网页界面也进行了更新更美观。
1. SIoT软件下载
- SIoT V2版本 下载链接:
腾讯微云下载(推荐):
链接: https://share.weiyun.com/6SFhgLQj
百度云盘下载:
链接:https://pan.baidu.com/s/17clVjJXWTZh02FteKy3mcA?pwd=mind
提取码:mind
2. 在电脑上运行SIoT

注意:启动时需要将SIoT添加到允许应用通过防火墙,勾选专用网络和公用网络,否则外部设备可能无法访问。

3. 添加主题
在浏览器输入 127.0.0.1:8080 即可打开网页端口,登录账号依然为siot,密码为dfrobot,打开后可以新建主题(Topic) 。

步骤3 行空板 K10 编程 (Mind+ V2.0)
K10 作为中枢,连接 WiFi 和 MQTT 服务器。当接收到二哈的 ID 信号后,发送对应指令给电脑。
核心逻辑:为了防止误触,我们设计了状态机,必须按照 ID1 -> ID2 -> ID3 的顺序才能触发最终效果。
使用说明
- 上电后自动进入识别流程并显示当前模式
- 若要改为手动识别:按 A 键切换到“手动识别”,按 B 依次推进步骤
- 若要恢复自动识别:再次按 A 键切换回“自动识别”,设备会在 loop() 中继续自动检测并推进
– 重置流程:快速依次按下并释放 A+B
(以下为 Mind+ V2 上传模式核心代码)
/*!
* MindPlus
* DFRobot, 行空板 K10
*/
#include <DFRobot_Iot.h>
#include "unihiker_k10.h"
#include "DFRobot_HuskylensV2.h"
// 动态变量
volatile float mind_n_a, mind_n_b, mind_n_c, mind_n_JinDu;
volatile bool autoMode = true;
// 静态常量
const String topics[] = {"siot/launch_event","","","",""};
// 创建对象
HuskylensV2 huskylens;
DFRobot_Iot myIot;
UNIHIKER_K10 k10;
uint8_t screen_dir=2;
void DF_ShiBieShouShiJieGuo();
void DF_LiuChengQiDong();
void DF_ShuaXinPingMuWenZi(String mind_s_string, float mind_n_row);
void onButtonAUnPressed();
void onButtonBUnPressed();
void DF_TextColor(String s, float row, uint32_t color);
void DF_ShowStatus(String s);
void DF_ShowHint(String s);
void DF_ShowProgress(int step, String detail);
void DF_ClearRows(int fromRow, int toRow);
void DF_UpdateModeHint();
void DF_ResetFlow();
void onButtonABPressed();
const uint32_t COL_TITLE = 0xFF66CC;
const uint32_t COL_HINT = 0x66CCFF;
const uint32_t COL_PENDING = 0x999999;
const uint32_t COL_SUCCESS = 0x33DD77;
const uint32_t COL_FINAL = 0xFF6699;
const uint32_t COL_INFO = 0x00AAFF;
const uint32_t COL_WARN = 0xFFCC66;
// 主程序开始
void setup() {
k10.begin();
k10.buttonA->setUnPressedCallback(onButtonAUnPressed);
k10.initScreen(screen_dir);
k10.creatCanvas();
k10.buttonB->setUnPressedCallback(onButtonBUnPressed);
k10.buttonAB->setPressedCallback(onButtonABPressed);
Wire.begin();
while (!huskylens.begin(Wire)) {
delay(100);
}
huskylens.switchAlgorithm(ALGORITHM_HAND_RECOGNITION);
delay(5000);
DF_TextColor("行空版", 1, COL_TITLE);
myIot.wifiConnect("BCM-RJ", "bcm123456");
while (!myIot.wifiStatus()) {}
DF_ShowStatus("WiFi已连接");
myIot.init("192.168.1.14","siot","2627086117766205","dfrobot", topics, 1883);
myIot.connect();
while (!myIot.connected()) {}
DF_ShowStatus("MQTT已连接");
DF_UpdateModeHint();
DF_LiuChengQiDong();
}
void loop() {
if (autoMode) {
if (mind_n_JinDu==1) {
DF_ShiBieShouShiJieGuo();
if (mind_n_a>2) {
DF_TextColor((String("识别到:") + String(RET_ITEM_STR(huskylens.getCachedResultByID(ALGORITHM_HAND_RECOGNITION, 1), Result, name))), 5, COL_SUCCESS);
myIot.publish(topic_0, "step1");
DF_ShowProgress(1, "完成");
mind_n_b = 0;
mind_n_JinDu = 2;
}
} else if (mind_n_JinDu==2) {
DF_ShiBieShouShiJieGuo();
if (mind_n_b>2) {
DF_TextColor((String("识别到:") + String(RET_ITEM_STR(huskylens.getCachedResultByID(ALGORITHM_HAND_RECOGNITION, 2), Result, name))), 7, COL_SUCCESS);
myIot.publish(topic_0, "step2");
DF_ShowProgress(2, "完成");
mind_n_c = 0;
mind_n_JinDu = 3;
}
} else if (mind_n_JinDu==3) {
DF_ShiBieShouShiJieGuo();
if (mind_n_c>2) {
DF_TextColor((String("识别到:") + String(RET_ITEM_STR(huskylens.getCachedResultByID(ALGORITHM_HAND_RECOGNITION, 3), Result, name))), 9, COL_SUCCESS);
myIot.publish(topic_0, "step3");
DF_TextColor("科技节启动", 11, COL_FINAL);
mind_n_JinDu = 4;
}
}
}
}
// 自定义函数
void DF_ShiBieShouShiJieGuo() {
mind_n_a = 0;
mind_n_b = 0;
mind_n_c = 0;
for (int index = 0; index < 3; index++) {
huskylens.getResult(ALGORITHM_HAND_RECOGNITION);
if (huskylens.available(ALGORITHM_HAND_RECOGNITION)) {
if ((huskylens.getCachedResultByID(ALGORITHM_HAND_RECOGNITION, 1) != NULL)) {
mind_n_a += 1;
}
else if ((huskylens.getCachedResultByID(ALGORITHM_HAND_RECOGNITION, 2) != NULL)) {
mind_n_b += 1;
}
else if ((huskylens.getCachedResultByID(ALGORITHM_HAND_RECOGNITION, 3) != NULL)) {
mind_n_c += 1;
}
else {
}
}
delay(100);
}
}
void DF_LiuChengQiDong() {
myIot.publish(topic_0, "step0");
DF_ClearRows(3,11);
DF_TextColor("准备启动流程", 3, COL_INFO);
DF_TextColor("", 4, COL_PENDING);
DF_TextColor("手势1 待识别", 5, COL_PENDING);
DF_TextColor("", 6, COL_PENDING);
DF_TextColor("手势2 待识别", 7, COL_PENDING);
DF_TextColor("", 8, COL_PENDING);
DF_TextColor("手势3 待识别", 9, COL_PENDING);
DF_TextColor("", 10, COL_PENDING);
mind_n_a = 0;
mind_n_b = 0;
mind_n_c = 0;
mind_n_JinDu = 1;
if (!autoMode) {
DF_ShowProgress(1, "待手动激活");
DF_ShowProgress(2, "待手动激活");
DF_ShowProgress(3, "待手动激活");
}
}
void DF_ShuaXinPingMuWenZi(String mind_s_string, float mind_n_row) {
k10.canvas->canvasClear(mind_n_row);
k10.canvas->canvasText(mind_s_string, mind_n_row, 0x0000FF);
k10.canvas->updateCanvas();
}
void DF_TextColor(String s, float row, uint32_t color) {
k10.canvas->canvasClear(row);
k10.canvas->canvasText(s, row, color);
k10.canvas->updateCanvas();
}
void DF_ShowStatus(String s) {
DF_TextColor(s, 1, COL_INFO);
}
void DF_ShowHint(String s) {
DF_TextColor(s, 3, COL_HINT);
}
void DF_ShowProgress(int step, String detail) {
if (step==1) DF_TextColor((String("手势1 ") + detail), 5, COL_SUCCESS);
if (step==2) DF_TextColor((String("手势2 ") + detail), 7, COL_SUCCESS);
if (step==3) DF_TextColor((String("手势3 ") + detail), 9, COL_SUCCESS);
}
void DF_ClearRows(int fromRow, int toRow) {
for (int r=fromRow; r<=toRow; r++) {
k10.canvas->canvasClear(r);
}
k10.canvas->updateCanvas();
}
void DF_UpdateModeHint() {
if (autoMode) {
DF_TextColor("模式:自动识别 按A键切换 A+B重置", 3, COL_HINT);
} else {
DF_TextColor("模式:手动识别 按A键切换 A+B重置", 3, COL_HINT);
}
}
// 事件回调函数
void onButtonAUnPressed() {
autoMode = !autoMode;
DF_UpdateModeHint();
}
void onButtonBUnPressed() {
if ((mind_n_JinDu==1)) {
DF_TextColor((String("手动激活:") + String("1")), 5, COL_WARN);
myIot.publish(topic_0, "step1");
DF_ShowProgress(1, "已手动激活");
mind_n_JinDu = 2;
}
else if ((mind_n_JinDu==2)) {
DF_TextColor((String("手动激活:") + String("2")), 7, COL_WARN);
myIot.publish(topic_0, "step2");
DF_ShowProgress(2, "已手动激活");
mind_n_JinDu = 3;
}
else if ((mind_n_JinDu==3)) {
DF_TextColor((String("手动激活:") + String("3")), 9, COL_WARN);
myIot.publish(topic_0, "step3");
DF_TextColor("科技节启动", 11, COL_FINAL);
}
else {
DF_TextColor("按A+B键,重置", 11, COL_HINT);
}
}
void DF_ResetFlow() {
myIot.publish(topic_0, "reset");
mind_n_a = 0;
mind_n_b = 0;
mind_n_c = 0;
mind_n_JinDu = 1;
autoMode = true;
DF_UpdateModeHint();
DF_LiuChengQiDong();
}
void onButtonABPressed() {
DF_ResetFlow();
}
步骤4 生成大屏视觉程序 (Google AI Studio)
这是本项目的最有趣的部分。我没有手写网页代码,而是向 Google AI Studio 发送了以下提示词:
Prompt: "角色设定:你是一个精通 Creative Coding 和 IoT 的前端开发专家。
任务:请帮我编写一个单文件的 HTML 网页,用于互动装置展示。
技术栈:
使用 CDN 引入 p5.js 用于绘图。
使用 CDN 引入 mqtt.js 用于连接 SIOT v2 服务器。
功能要求:
网页背景为黑色。
建立 MQTT 连接:
连接地址:ws://127.0.0.1:1888/ws(注意使用 WebSocket 协议)。
Topic:siot/launch_event。
账号密码留空变量让我填写。
屏幕中央显示文字“等待接入...”。
当收到 MQTT 消息时触发分步骤的视觉特效
视觉设计要求:
待机状态:屏幕中心有一个微弱呼吸的白色光圈,周围有少量漂浮粒子。
阶段一 (接收到 "step1"):触发【能量汇聚】特效。从屏幕四周向中心汇聚蓝色的光流粒子,速度较快,形成科技感。
阶段二 (接收到 "step2"):触发【情感注入】特效。在蓝色光流的基础上,增加粉色/暖色的光晕粒子,柔和地扩散并交融。
阶段三 (接收到 "step3"):触发【最终启动】。
粒子先极速收缩成一个点。
然后瞬间爆炸(Boom),满屏五彩粒子四散。
2秒后,粒子慢慢汇聚成文字 "科技节启动" 。
音效设计:
背景音乐 步骤音效 都改为 本地mp3文件
bgm.mp3 - 背景音乐
step1.mp3 - 能量汇聚音效
step2.mp3 - 情感注入音效
step3.mp3 - 启动爆发音效
代码要求:
使用 p5.js 的粒子系统(Particle System)来实现。
动画要流畅,转换要有过渡感。
输出:请直接给出完整的 index.html 代码。"
项目源码:
github仓库地址:dhtbo/iot-launch-interface
AI 生成的代码直接运行效果惊人!
![]() | ![]() |
![]() | ![]() |
四、 演示效果 (见视频)

初始状态:大屏显示 "等待接入..."。
互动开始:体验者竖起大拇指,屏幕蓝光升腾。
气氛升温:体验者比出 Yeah,屏幕彩带飞舞。
高潮启动:体验者用力握拳,屏幕瞬间炸裂显示 "科技节启动",完成启动仪式。
五、 总结
通过行空板 K10 和二哈识图2,我们用极低的成本实现了一个看似复杂的互动装置。更重要的是,在 Google AI Studio 的帮助下,我们验证了 "AI 工具 + 开源硬件 = 无限创意" 的可能性。希望这个项目能为校园科技节增添一抹亮色!

返回首页
回到顶部







评论