手机进校园危害学生学习和身心健康已经成为一个不可忽视的社会问题。2018年8月,教育部等8部委在《综合防控儿童青少年近视实施方案》中明确提出了严禁学生将个人手机、平板电脑等电子产品带入课堂的要求,2018年12月,教育部再次出台相关文件强力实施。
虽然“手机”等智能设备拒之校园,减轻了一些软件打卡、沉迷游戏等现象,但“校园之大,安得吾师”,老师可能因为开会、跑班讲课、教研、学习而留下字条或便贴纸,师生难以得到准确或者及时的信息,时常无奈,只能将问题留到第二天,一下让校园内的通讯回到“原始社会”。
针对以上校园问题,尝试开发一种满足师生通讯要求的互动设备,第一老师可以通过手机发布消息,第二学生可以主动回复和发布问题,第三控制娱乐功能、减少成本。
互动门板的基本需求适用诸多场景与人群,例如①企业部门领导门前,可以及时得知出差或者访客信息;②业务单位楼下,可以植入简单的专家系统,满足休假期间的问题解决;③录影棚门口,可以保证录音作业时处理突发拜访;④酒店客房门前,主动发送消息当前休息、工作或需要打扫等需求;⑤家用时,安置门上用于外卖、报纸、信件、快递人员抵达登记等问题,同时其可以开锁,减少了钥匙繁多的困扰。
本项目主要解决手机端和硬件端实时收发消息的问题,针对校园和竞赛教室场景,增加打卡签到、语音呼叫、备忘提示等功能。
项目使用环境限定于一定物理范围,且通常办公室、教室、录影棚等具备网络条件,手机端(互动宝)与硬件端(互动板)采用网络通讯,数据通过物联网交换,手机端和硬件端均能实现主动收发消息。
MQTT协议:即Message Queuing Telemetry Transport,是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议。硬件连入wifi的情况下,在 TCP/IP协议之上,实现手机端与硬件端的消息队列遥测传输,其优点在于,以极少有限的带宽满足远程设备实时可靠的消息服务。
语音识别:主要是模式匹配法,基于百度AI提供的短语音识别模型,将输入语音的特征矢量依次与模板库中的每个模板进行相似度比较,将相似度最高者作为识别结果输出,包括中文普通话、英语、粤语、四川话、远场5个识别模型。
语音唤醒:采用百度语音唤醒技术,在手机端预置唤醒词,当用户发出该语音指令时,设备便从休眠状态中被唤醒,并作出指定响应,大大提升了人机交互的效率,配合语音识别实现无障碍模型,满足特殊人群使用需求。
语音合成:采用百度语音合成技术,基于业界领先的深度神经网络技术,提供高度拟人、流畅自然的语音合成服务,让应用开口说话,更具个性。
(一)手机端(互动宝)功能
采用APP Inventor开发,整体界面以蓝色和白色为主,聚焦重点功能键,界面分为三个功能区,即硬件端连接区、发送消息区、接收消息区。
1.语音唤醒:唤醒词为“互动一下”,即使用者可以在息屏状态下唤醒客户端,发送“呼叫”“探声”“照明”等系统消息时无需打开软件即可发送,发送成功后,接收消息区将收到返回信息,即设置成功。
2.语音识别发送消息:使用者可以通过长按话筒按钮进行语音消息录入,系统将自动生成词句,此功能支持普通话、英语、粤语、四川话等。
3.多控设备:一个手机客户端可以连接多个硬件终端,只需要输入“设备主题”,连接成功后收到两条消息,即状态栏回复“订阅成功”,接收消息区收到“互动板上线”。也可通过“退订”开启勿扰模式。
4.系统功能:包括呼叫、照明、探声、留言等。用户可以通过按“呼叫”按钮,让硬件端奏提示音,配合留言,即提醒室内用户当前有紧急消息,需要立刻查看;当用户开启“探声”功能后,会对硬件周围环境持续10秒收集声音,已查看是否需要返回办公室或办公室是否有人。
(二)硬件端(互动板)功能
夜间灯:有两种启动模式,一种利用光敏传感器,读取引脚数值,当数值小于300时判定亮等;另一种为用户主动照明,用户可将互动板脱离门,在手机息屏模式下,通过“互动一下”“照明”两个口令匹配打开灯,提供照明。
主叫移动端:可以通过按下左键发起语音识别,通过右键将语音识别结果发送到互动宝(手机移动端)。
NFC识别:可以为空白卡注册用户信息,通过已经注册的用户可以通过打卡实现开门与签到。
语音合成:通过手机端发送消息可以直接说出发送的消息,可以说出系统提示音。
阶段一:学习物联网实现远程通讯原理。
学习HTTP协议、MQTT协议等传输原理,最终确定了低耗能、双向通讯的MQTT作为硬件端和手机端互动的传输协议。探索储存临时信息的物联网平台,先后注册并尝试使用ONENET、阿里云、SIOT等物联网数据服务商,最终选定EasyIOT作为信息交换平台,更加自由和便捷。
阶段二:手机端与物联网平台通讯。
制作手机APP选用APP Inventor平台,具备MQTT协议的图形化接口,按照技术文档输入主题、设备号等信息后,实现手机端与物联网平台的双向通讯。
阶段三:硬件端与物联网平台通讯。
首先尝试硬件连入wifi,然后基于技术文档实现物联网对硬件的控制,磨合多指令的传输关系。
阶段四:实现三者数据传输。
进行基础物理搭建,组合元件。发现硬件主动传输传感器的数据不够及时、稳定性不够,因此采取硬件端优先处理传感器数据,将判断结果再入物联网的方式,成功优化。
阶段五:增强用户体验。
硬件端主动发送数据一直是难题之一,因此我们将数字触控板替换成了语音识别方案,硬件端仅确认识别结果,然后通过触控板发送,减少了数字对应固定指令的限制,同时简洁了操作,同样我们给手机端也加入了语音唤醒与语音识别的功能,极大程度满足特殊人群的无障碍操作,通过唤醒词激活手机端,系统内置消息会识别后会自送发送。
阶段六:功能整合。
整合门锁,由原来的物理按钮,尝试实用NFC实现一人一卡签到,且与电机锁关联,实现电子钥匙的功能。
阶段七:提高交互、实地调试。
1.无障碍模式:基于语音唤醒和语音识别技术,手机端实现语音无障碍操作,满足特殊人群,或者适用手头有工作暂时不方便的用户操控,通过“互动一下“唤醒词激活息屏APP,通过语音识别内置指令或者自定义留言可直接发送至硬件端。
2.1:N双向主叫功能:手机端可以通过订阅不同主题实现切换控制终端,硬件端和手机端均可以通过语音识别的方式互发消息。手机端历史消息区对不同类型的消息进行了颜色区分,便于用户关注重要消息,而硬件端可在WIFI条件下实现收发消息、照明、探声等功能。
3.多合一电子卡:用户可通过按键登记或者NFC打卡的方式,基于NFC技术实现了实名签到、电子开锁的功能,可将NFC信息读入手机,极大方便了用户,减少钥匙累赘。
4.语音合成:系统的提示音和手机端上发送的消息会通过语音合成表达,通过简洁的自然语言互动,增强其友好性。
拓展一:人脸识别。互动板端将加入人脸识别模块,由互动宝采集用户数据后,访客将通过互动板进行人脸识别,实现访客登记、常驻解锁、嫌犯排查等功能,用智能化取代自动化和机械化。
拓展二:自然语言处理。通过DNN网络,训练问答专家系统,及时侦测情感倾向、提取观点,有针对性的回应和处理,增加信访部门、业务窗口的适配性,同时也可以作为AI教师,解答常规且重复的问题。
反思一:硬件端主动发送数据一直是难题之一,因此我们将数字触控板替换成了语音识别方案,硬件端仅确认识别结果,然后通过触控板发送,极大程度满足特殊人群的无障碍操作,通过唤醒词激活手机端,系统内置消息会识别后会自送发送。
互动板端:
#include <Iot.h>
#include < ASR.h>
#include <IOBOX_Motor.h>
#include <NFC0231.h>
#include < NtpTime.h>
// 动态变量
volatile float mind_n_ShengYin, mind_n__2333;
// 函数声明
Void NFCJianCe();
void onButtonABPressed();
void obloqMqttEventT0(String& message);
// 静态常量
const String topics[5] = {"vhw7zH2Zg","Z0P00yCWR","","",""};
const MsgHandleCb msgHandles[5] = {obloqMqttEventT0,NULL,NULL,NULL,NULL};
const uint8_t imageMatrix[][350] = {
{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2d,0x80,0x0,0x0,0x0,0x0,0x0,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x0,0x0,0x0} //图像解码
};
// 创建对象
Iot myIot;
PN532_UART nfc;
NtpTime ntptime;
ASR mpythonAsr;
String str_mpythonAsr_result;
IOBOX_Motor motor_ib;
// 主程序
void setup() {
mPython.begin();
myIot.setMqttCallback(msgHandles);
buttonAB.setPressedCallback(onButtonABPressed);
display.setCursorLine(4);
display.printLine("互动板运行ing");
myIot.wifiConnect("Andre", "12345678");
while (!myIot.wifiStatus()) {yield();}
display.setCursorLine(1);
display.printLine("wifi已连接");
display.setCursorLine(2);
display.printLine(myIot.getWiFiLocalIP());
myIot.init("iot.dfrobot.com.cn","2UFHSBCZg","","2UKHSfCWRz",topics,1883);
myIot.connect();
while (!myIot.connected()) {yield();}
display.setCursorLine(3);
display.printLine("MQTT已建立");
myIot.publish(topic_0, "互动板已上线");
nfc.begin(&Serial1, P8, P9);
ntptime.setNtpTime(ntptime.UTCEast8_t, "ntp.ntsc.ac.cn");
display.fillScreen(0);
}
void loop() {
if (nfc.scan()) {
if ((nfc.readUid()=="67a5aa60")) {
display.fillScreen(0);
display.setCursorLine(1);
display.printLine("签到中");
myIot.publish(topic_0, (String("李老师签到") + String(">")));
buzz.freq(523, BEAT_1);
}
if ((nfc.readUid()=="129f0834")) {
display.fillScreen(0);
display.setCursorLine(1);
display.printLine("签到中");
myIot.publish(topic_0, (String("孙垂波签到") + String(">")));
buzz.freq(523, BEAT_1);
}
}
if ((buttonB.isPressed())) {
display.fillScreen(0);
myIot.publish(topic_0, (str_mpythonAsr_result));
display.setCursorLine(2);
display.printLine("消息已发送");
}
if (((light.read())<20)) {
rgb.brightness(round(1));
rgb.write(-1, 0xFFFF00);
}
else {
rgb.write(-1, 0x000000);
}
if ((buttonA.isPressed())) {
buzz.freq(523, BEAT_1);
display.fillScreen(0);
display.setCursorLine(1);
display.printLine("开始识别");
str_mpythonAsr_result=mpythonAsr.getAsrResult(2);
display.setCursorLine(2);
display.printLine((str_mpythonAsr_result));
display.setCursorLine(4);
display.printLine("按下p发送至手机");
}
}
// 事件回调函数
void onButtonABPressed() {
buzz.freq(523, BEAT_1);
display.fillScreen(0);
if (myIot.connected()) {
myIot.publish(topic_0, "签到");
display.setCursorLine(1);
display.printLine("已签到");
}
else {
display.setCursorLine(1);
display.printLine("签到失败");
}
}
void obloqMqttEventT0(String& message) {
if ((message=="aj")) {
buzz.stop();
}
else if ((message=="hj")) {
buzz.play(PRELUDE, OnceInBackground);
}
else {
if ((message=="off")) {
display.fillScreen(0);
rgb.write(-1, 0x000000);
display.setCursorLine(1);
display.printLine("互动一下");
}
else if ((message=="on")) {
display.fillScreen(0);
rgb.brightness(round(5));
rgb.write(-1, 0x0000FF);
display.drawImage(39, 7, 50, 50, imageMatrix[0]);
}
else {
if ((message=="s")) {
for (int index = 0; index < 20; index++) {
if ((30<(sound.read()))) {
mind_n_ShengYin += 1;
delay(500);
}
if ((2<mind_n_ShengYin)) {
myIot.publish(topic_0, "当前有人");
}
else {
myIot.publish(topic_0, "当前无人");
}
yield();
}
}
else {
if ((message=="open")) {
if ((mind_n__2333==1)) {
buzz.freq(523, BEAT_1);
motor_ib.motorRun(motor_ib.M1, motor_ib.CW, 200);
delay(160);
motor_ib.motorStop(motor_ib.M1);
mind_n__2333 = 0;
}
}
else {
if ((message=="close")) {
if ((mind_n__2333==0)) {
buzz.freq(196, BEAT_1_4);
motor_ib.motorRun(motor_ib.M1, motor_ib.CCW, 200);
delay(160);
motor_ib.motorStop(motor_ib.M1);
buzz.freq(196, BEAT_1_2);
mind_n__2333 = 1;
}
}
else {
display.fillScreen(0);
display.setCursorLine(1);
display.printLine((String("成功>>") + String(message)));
}
}
}
}
}
}