回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页
best-icon

【校园】欺凌预警北斗授时牌 简单

头像 云天 2024.05.08 803 3

项目简介

采用北斗授时模块、国产开源语音识别模块,为学生提供欺凌预警功能。在校园偏僻角落,提供LED屏字幕提醒,可语音识别“老师救命”呼救,并从北斗授时模块获取精准时间,通过物联网发送至值班老师手机上,老师及时赶到事发地点,制止欺凌事件并处理。

目的与问题

解决校园偏僻角落如厕所无法安装监控的地点,提供预防欺凌警示,语音识别呼救报警的问题,并通过物联网与手机APP关联,及时通知老师到现场处理欺凌事件。

项目背景:校园欺凌是指发生在学生之间蓄意或恶意通过肢体、语言及网络等手段,实施欺负、侮辱造成伤害的行为。不同于校园暴力以伤人和毁物为目的的打砸抢,校园欺凌更多是欺负和侮辱。根据外部行为表现可以分为身体欺凌、言语欺凌、关系欺凌、网络欺凌等形式。身体欺凌是指通过身体或工具对受欺凌者实施的欺凌行为,如殴打、强迫、勒索等。言语欺凌是指通过语言对受欺凌者实施的欺凌行为,如辱骂、起外号、恐吓等,言语欺凌在所有欺凌类型中发生率最高。校园欺凌不仅对受欺凌者的身体产生伤害,还会容易形成心理障碍。受到校园欺凌的学生很容易产生焦虑、紧张、恐惧,甚至抑郁的心理,从而出现厌学和逃学的情况。当受欺凌者长期将情绪隐藏,不敢宣之于口时,可能会产生自伤、自残甚至自杀等行为。被欺凌的女生更多地表现出自我攻击性,而男生更多表现出攻击他人性。对于欺凌者而言,实施欺凌会进一步强化欺凌的想法,增加个体的暴力行为。在少年时,如果不对欺凌者的行为加以规范,成年后容易失控,甚至引发暴力犯罪。而那些校园欺凌的旁观者,在目睹了校园欺凌后或置身事外、满不在乎,或参与其中、学习效仿,或自我保护、自责矛盾,内心变得极度不平衡。阻止校园欺凌,义不容辞且刻不容缓。作为学生首先不能充当欺凌者,更不能在被欺凌时助长欺凌者的气焰。面对校园欺凌时,尽量冷静下来,保持镇定,不要激怒欺凌者。学会迂回,当下向一切能提供帮助的人求助,并第一时间寻求父母和老师的帮助,勇敢地反映。如果发现身边的同学被欺凌,不做冷漠的旁观者。

 

基于以上背景,我们设计了一个为“欺凌预警北斗授时牌”。

项目设计:

本“欺凌预警北斗授时牌”,采用北斗授时模块(北斗授时&定位模块集成了卫星定位功能以及RTC实时时钟,该模块会按照预设的校时周期自动获取卫星时间,并对板载RTC芯片进行精准校时,可有效消除RTC芯片因长时间工作或意外情况而产生的时间误差。)1.8位数码管显示模块实时显示精准时间,日常做为时间显示,当欺凌发生时,可供学生记忆欺凌发生的准确时间,并在呼救后,欺凌发生时间会通过物联网发送到值班教师手机APP上。2.使用两块32*16显示屏,前后各一块,滚动显示“教师!救命”提醒呼救词,当有人呼救后,显示屏全屏“红色”闪烁,起警示作用。3.使用“语音识别模块”,录制自定义唤醒词“老师救命”,当有学生呼喊“老师救命”时,语音识别并做出反应。4.使用物联网模块,连接校园内无线WIFI,语音识别模块识别到“老师救命”唤醒词后,通过物联网模块向物联网Easy IOT发送时间信息。4.使用Mit Appinventor2自制手机app,app连接物联网,当接收到信息后,屏幕显示欺凌发生地点、发生时间,并播放警报音加震动提醒值班老师接收信息并及时到现场处理。

项目硬件:

北斗授时模块,Arduino及扩展板2个,8位数码管显示模块,32x16RGB点阵屏2个,物联网模块,语音合成模块,3.7V18650锂电池2节、充电宝。

项目成品:

增加了太阳能板,为LED灯供电,双显示屏前后显示提示信息。

 

image.png

 

2. 效果图1

3. 效果图2

 

 image.png

 

 

 

 

语音、联网、时间显示屏程序

代码
#include "DFRobot_GNSSAndRTC.h"
#include "DFRobot_LedDisplayModule.h"
#include "Arduino.h"
#include "SoftwareSerial.h"

#include "DFRobot_DF2301Q.h"
//DFRobot_DF2301Q_I2C asr;

DFRobot_DF2301Q_I2C asr;


static unsigned long currentTime = 0; 


DFRobot_LedDisplayModule LED(&Wire, 0xE0);

#define I2C_COMMUNICATION  //use I2C for communication, but use the serial port for communication if the line of codes were masked

#ifdef  I2C_COMMUNICATION
DFRobot_GNSSAndRTC_I2C rtc(&Wire, MODULE_I2C_ADDRESS);
#endif
#define WIFISSID "sxs" 
#define WIFIPWD  "smj080823"
#define SERVER   "iot.dfrobot.com.cn"
#define PORT     1883
#define IOTID    "rGltuGbIR"
#define IOTPWD   "9GlpXGbIRz"


const String separator = "|";
bool pingOn = true;
bool obloqConnectMqtt = false;
static unsigned long pingInterval = 2000;
static unsigned long sendMessageInterval = 10000;
unsigned long previousPingTime = 0;
unsigned long previousSendMessageTime = 0;
String receiveStringIndex[10] = {};



bool subscribeMqttTopic = false;




bool subscribeSuccess = false;

//wifi异常断开检测变量
bool wifiConnect = false;
bool wifiAbnormalDisconnect = false;

//mqtt因为网络断开后重新连接标志
bool mqttReconnectFlag = false;

SoftwareSerial softSerial(10,11);

enum state{
    WAIT,
    PINGOK,
    WIFIOK,
    MQTTCONNECTOK
}obloqState;

/********************************************************************************************
Function    : sendMessage      
Description : 通过串口向OBLOQ发送一次消息
Params      : 无
Return      : 无 
********************************************************************************************/
void sendMessage(String message)
{
    softSerial.print(message+"\r"); 
}

/********************************************************************************************
Function    : ping      
Description : 通过串口向OBLOQ发送一次字符串"|1|1|",尝试与OBLOQ取得连接
Params      : 无
Return      : 无 
********************************************************************************************/
void ping()
{
    String pingMessage = "|1|1|";
    sendMessage(pingMessage);
}

/********************************************************************************************
Function    : connectWifi      
Description : 连接wifi   
Params      : ssid 连接wifi的ssid;pwd 连接wifi的password
Return      : 无 
********************************************************************************************/
void connectWifi(String ssid,String pwd)
{
    String wifiMessage = "|2|1|" + ssid + "," + pwd + separator;
    sendMessage(wifiMessage);
} 

/********************************************************************************************
Function    : connectMqtt      
Description : 连接DF-IoT    
Params      : server 物联网网址;port 端口;iotid 物联网登录后分配的iotid;iotpwd 物联网登录后分配的iotpwd
Return      : 无 
********************************************************************************************/
void connectMqtt(String server, String port, String iotid, String iotpwd)
{
    String mqttConnectMessage = "|4|1|1|" + server + separator + port + separator + iotid + separator + iotpwd + separator;
    sendMessage(mqttConnectMessage);
}


/********************************************************************************************
Function    : reconnectMqtt      
Description : 重新连接DF-IoT    
Params      : 无 
Return      : 无 
********************************************************************************************/
void reconnectMqtt()
{
    String mqttReconnectMessage = "|4|1|5|"; 
    sendMessage(mqttReconnectMessage);
}


/********************************************************************************************
Function    : publish      
Description : 向DF-IoT物联网设备发送信息    
Params      : topic DF-IoT物联网设备编号;message 发送的消息内容
Return      : 无 
********************************************************************************************/
void publish(String topic,String message)
{
    String publishMessage = "|4|1|3|" + topic + separator + message + separator;
    sendMessage(publishMessage);
}

/********************************************************************************************
Function    : handleUart      
Description : 处理串口传回的数据      
Params      : 无   
Return      : 无 
********************************************************************************************/
void handleUart()
{
    while(softSerial.available() > 0)
    {
        String receivedata = softSerial.readStringUntil('\r');
        const char* obloqMessage = receivedata.c_str();
        // Serial.print("receivedata = ");
        // Serial.println(receivedata);
        if (strcmp(obloqMessage, "|1|1|") == 0)
		{
			Serial.println("Pong");
			pingOn = false;
			obloqState = PINGOK;
		}
        if(strcmp(obloqMessage, "|2|1|") == 0)
        {
            if(wifiConnect)
            {
                wifiConnect = false;
                wifiAbnormalDisconnect = true;
            }
        }
        else if (strstr(obloqMessage,"|2|3|") != NULL && strlen(obloqMessage) != 9)
		{
			Serial.println("Wifi ready");
            wifiConnect = true;
            if(wifiAbnormalDisconnect)
            {
                wifiAbnormalDisconnect = false;
                return;
            }
			obloqState = WIFIOK;
		}
		else if (strcmp(obloqMessage, "|4|1|1|1|") == 0)
		{
			Serial.println("Mqtt ready");
            obloqConnectMqtt = true;
            if(mqttReconnectFlag)
            {
                mqttReconnectFlag = false;
                return;
            }
            obloqState = MQTTCONNECTOK;
        }
        else if (strcmp(obloqMessage, "|4|1|2|1|") == 0)
		{
			Serial.println("subscribe successed");
            //subscribeMqttTopic = false;
        }
        //DF-IoT接收到消息,topic和message传入receiveMessageCallbak函数
        else if (strstr(obloqMessage, "|4|1|5|") != NULL)
        {
            splitString(receiveStringIndex,receivedata,"|");
            receiveMessageCallbak(receiveStringIndex[3],receiveStringIndex[4]);
        }

    }
}
/********************************************************************************************
Function    : subscribeSingleTopic      
Description : 监听单个DF-IoT物联网设备  
Params      : topic DF-IoT物联网设备编号
Return      : 无 
********************************************************************************************/
void subscribeSingleTopic(String topic)
{
    if(!subscribeMqttTopic && obloqConnectMqtt)
    {
        subscribeMqttTopic = true;
        subscribe(topic);
    }    
}
/********************************************************************************************
Function    : receiveMessageCallbak      
Description : 接收消息的回调函数  
Params      : topic 发出消息的DF-IoT物联网设备编号;message 收到的消息内容
Return      : 无 
********************************************************************************************/
void receiveMessageCallbak(String topic,String message)
{
    //Serial.println("Message from: " + topic);
    //Serial.println("Message content: " + message);
    if(message=="R")
    {
      Serial.print("1");
    }
    if(message=="C")
    {
      Serial.print("2");
    }
}
/********************************************************************************************
Function    : splitString      
Description : 剔除分隔符,逐一提取字符串     
Params      : data[] 提取的字符串的目标储存地址;str 源字符串;delimiters 分隔符
Return      : 共提取的字符串的个数 
********************************************************************************************/
int splitString(String data[],String str,const char* delimiters)
{
  char *s = (char *)(str.c_str());
  int count = 0;
  data[count] = strtok(s, delimiters);
  while(data[count]){
    data[++count] = strtok(NULL, delimiters);
  }
  return count;
}
/********************************************************************************************
Function    : sendPing      
Description : 每隔pingInterval一段时间,通过串口向OBLOQ ping一次      
Params      : 无   
Return      : 无 
********************************************************************************************/
void sendPing()
{
    if(pingOn && millis() - previousPingTime > pingInterval)
    {
        previousPingTime = millis();
        ping();
    }
}

/********************************************************************************************
Function    : execute      
Description : 根据OBLOQ的状态,进行下一步相应操作。      
Params      : 无
Return      : 无 
********************************************************************************************/
void execute()
{
    switch(obloqState)
    {
        case PINGOK: connectWifi(WIFISSID,WIFIPWD); obloqState = WAIT; break;
        case WIFIOK: connectMqtt(SERVER,String(PORT),IOTID,IOTPWD);obloqState = WAIT; break;
        case MQTTCONNECTOK : obloqState = WAIT; break;
        default: break;
    }
}

/********************************************************************************************
Function    : checkWifiState      
Description : 检查wifi状态,如果检测到wifi热点断开会间隔1分钟去重新连接wifi
Params      : 无
Return      : 无
********************************************************************************************/
void checkWifiState()
{
    static unsigned long previousTime = 0;
    static bool reconnectWifi = false;
    if(wifiAbnormalDisconnect && millis() - previousTime > 60000)
    {
        previousTime = millis();
        //Serial.println("Wifi abnormal disconnect");
        reconnectWifi = true;
        obloqConnectMqtt = false;
        connectWifi(WIFISSID,WIFIPWD);
    }
    if(!wifiAbnormalDisconnect && reconnectWifi)
    {
        reconnectWifi = false;
        mqttReconnectFlag = true;
        //Serial.println("Reconnect mqtt");
        reconnectMqtt();
    }

}
/********************************************************************************************
Function    : subscribe      
Description : 订阅DF-IoT物联网设备     
Params      : topic DF-IoT物联网设备编号
Return      : 无 
********************************************************************************************/
void subscribe(String topic)
{
    String subscribeMessage = "|4|1|2|" + topic + separator;
    sendMessage(subscribeMessage);
}


void setup()
{
  Serial.begin(9600);
  softSerial.begin(9600);
  //显示初始化
  while(LED.begin(LED.e8Bit) != 0)
  {
    //Serial.println("Failed to initialize the chip , please confirm the chip connection!");
    delay(1000);
  }
   LED.setDisplayArea(1,2,3,4,5,6,7,8);  
   LED.print("8","8","8","8","8","8","8","8");
   delay(3000);
   LED.print("","","","","","","","");
  while (!(asr.begin())) {
    //Serial.println("Communication with device failed, please check connection");
    delay(3000);
  }
  LED.print("0","0","0","0","0","0","0","0");
  delay(3000);
  LED.print("","","","","","","","");
  //语音初始化
  asr.setVolume(4);
  asr.setMuteMode(0);
  asr.setWakeTime(20);
  asr.playByCMDID(23);  // 普通词ID
  //北斗授时初始化
  while (!rtc.begin()) {
      //Serial.println("Failed to init chip, please check if the chip connection is fine. ");
      delay(10000);
  }
  rtc.setHourSystem(rtc.e24hours);//Set display format
  rtc.calibRTC(1);
  //
 }
uint8_t underCalibCount = 0;
char hour1[2];
char hour2[2];
char second1[2];
char second2[2];
char minute1[2];
char minute2[2];
char xian[2];
int currentTime1=0;
int currentTime2=0;
DFRobot_GNSSAndRTC::sTimeData_t sTime;
void show22()
{
  LED.print("1","8","-","2","7","-","1","9");
}
void show()
{
 if(millis() - currentTime1 > 900){
    currentTime1 =  millis();
    uint8_t status = rtc.calibStatus();
    if (DFRobot_GNSSAndRTC::eCalibComplete == status) {
        underCalibCount = 0;
        //Serial.println("Calibration success!");
    } else if (DFRobot_GNSSAndRTC::eUnderCalib == status) {
        underCalibCount += 1;
        if (60 <= underCalibCount) {   // If the calibration fails for a long time, manually terminate the calibration
            rtc.calibStatus(false);
            underCalibCount = 0;
            //Serial.println("Calibration failed!");
            //Serial.println("It may be due to weak satellite signals.");
           //Serial.println("Please proceed to an open outdoor area for time synchronization.");
        }
    }
    sTime = rtc.getRTCTime();
    xian[0]='-';
    String hour = String(sTime.hour+8);
    if(sTime.hour>9){
      hour1[0]=hour.charAt(0);
      hour2[0]=hour.charAt(1);
    }
    else{
      hour1[0]='0';
      hour2[0]=hour.charAt(0);
    }
    String minute = String(sTime.minute);
    if(sTime.minute>9){
      minute1[0]=minute.charAt(0);
      minute2[0]=minute.charAt(1);
    }
    else{
      minute1[0]='0';
      minute2[0]=minute.charAt(0);
    }
    String second = String(sTime.second);
    if(sTime.second>9){
      second1[0]=second.charAt(0);
      second2[0]=second.charAt(1);
    }
    else{
      second1[0]='0';
      second2[0]=second.charAt(0);
    }
    LED.print(hour1,hour2,xian,minute1,minute2,xian,second1,second2);
  }

}
void voice()
{
  if(millis() - currentTime2 > 300)
    {
      currentTime2 =  millis();
      uint8_t CMDID = asr.getCMDID();
      switch (CMDID) {
      case 1: 
        if(obloqConnectMqtt){
          publish("1ugQpffSR", String(sTime.hour)+":"+String(sTime.minute)+":"+String(sTime.second)); 
          Serial.print("R");
        }
        
        break;
      default:
       if (CMDID != 0) {
        
        //Serial.print("CMDID = ");  //打印命令ID
        //Serial.println(CMDID);
      }
     }
    }
}
void loop()
{ //物联网
  sendPing();
  execute();
  handleUart();
  subscribeSingleTopic("9VnL8sfIg");
  checkWifiState();
  //时间显示
  show();
  
  //语音求救 
  voice();    
}

求救显示屏

代码
#include <Adafruit_GFX.h>   
#include <RGBmatrixPanel.h> 
#define CLK 8  
#define LAT A3
#define OE  9
#define A   A0
#define B   A1
#define C   A2
RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
//RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
//可用Mind+通过扩展添加oled,显示汉字,在“自动生成”处看此汉字字模
int num=5;
int str[5][32]={
{0x02,0x00,0x02,0x08,0x3f,0xd0,0x02,0x20,0x02,0x40,0xff,0xfe,0x01,0x00,0x02,0x00,0x0c,0x10,0x18,0xe0,0x2f,0x00,0x48,0x08,0x88,0x08,0x08,0x08,0x07,0xf8,0x00,0x00},
{0x08,0x00,0x0b,0xfe,0x48,0x20,0x48,0x20,0x48,0x20,0x49,0xfc,0x49,0x24,0x49,0x24,0x49,0x24,0x49,0x24,0x49,0x24,0x09,0x34,0x11,0x28,0x10,0x20,0x20,0x20,0x40,0x20},
{0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00},
{0x10,0x40,0x14,0x40,0x12,0x40,0x10,0x80,0xfe,0xfe,0x11,0x08,0x10,0x88,0x92,0x88,0x54,0x88,0x10,0x50,0x38,0x50,0x54,0x20,0x92,0x50,0x10,0x88,0x51,0x04,0x22,0x02},
{0x01,0x00,0x01,0x00,0x02,0x80,0x04,0x40,0x08,0x20,0x37,0xd8,0xc0,0x06,0x00,0x00,0x3e,0xf8,0x22,0x88,0x22,0x88,0x22,0x88,0x3e,0xa8,0x22,0x90,0x00,0x80,0x00,0x80}
};
//int ma[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int ma[8]={128,64,32,16,8,4,2,1};
int bs=0;
void setup() {
  Serial.begin(9600);
  matrix.begin();
}
uint8_t underCalibCount = 0;
void loop() {
 //物联网
  if(Serial.available()>0)
  {
    char c=char(Serial.read());
    Serial.print(c);
    if(c=='R')
    {
      bs=1;
    }
    else if(c=='1')
    {
      bs=2;
    }
    else{
      bs=0;
    } 
  }
  if(bs==0){
   matrix.fillScreen(matrix.Color333(0, 0, 0));
   ts();
   delay(1000);
  }
  else if(bs==1){
   matrix.fillScreen(matrix.Color333(0, 0, 0));
   delay(1000);
   matrix.fillScreen(matrix.Color333(7, 0, 0));
   delay(1000);
  }
  else{
   matrix.fillScreen(matrix.Color333(0, 0, 0));
   delay(1000);
   matrix.fillScreen(matrix.Color333(0, 7, 0));
   delay(1000);
  }
 
}
void ts(){
int i,j,a,n,m,k;
n=0;
for(m=31;m>=-num*16;m--){
 for(i=0;i<32;i++)
  {
    for(j=0;j<8;j++){ 
      for(k=0;k<num;k++){
      a=(str[k][i]&ma[j])>>(7-j);//16进制数,按位取,如0x45(十六进制)对应01000101(二进制),一位一位取
      if(a==1&&n+m+k*16>=0&&n+m+k*16<=31){//对应位为1,点亮
          matrix.drawPixel(n+m+k*16,i/2, matrix.Color333(7, 7, 0)); //n为列号,因为这里一个十六进制数为8位,两个为一行,所以行号为i/2
       }
      }
      n=n+1;
      if(n==16){//16*16每过16列,换行,列号从0开始
          n=0;
      }
    }
   }
   delay(20);
   matrix.fillScreen(matrix.Color333(0, 0, 0));
 }
}

 

2. 手机App界面设计及图形化编程代码

image.png

预期效果

本项目使用北斗授时模块,可通过北斗获取精准时间,语音识别“老师救命”,通过物联网将信息发送至手机App。主要用于学生在校园偏僻角落欺凌时报警求救使用,也可用于公共场所紧急情况下报警呼救使用。

创意点

在学校无法安装摄像头的场所,为遭受欺凌的学生提供呼救使用。使用北斗授时,提供精准时间。使用语音识别,实现即时呼救。使用物联网,即时通知老师。

总结与展望

遇到的难点:因在学校角落或学校卫生间内,无线网络信号弱,信息传送可能出现不稳定。因设备原因,未实现语音对讲功能,对于学生的呼救,老师无法即时响应。

研究计划:建议学校在这些无线信号弱的地方,增加无线信号强度,来满足信息传送需求,增加语音广播设备,当学生呼救后,即时开启对讲功能,及时进行确认并制止欺凌行为继续发展。

成员及分工

孟繁芃 八年级2班 负责项目创意、程序编写、文档制作、海报制作。  

赵雪睿 八年级4班 负责项目视频录制、剪辑。

刘楚涵 八年级4班 负责项目硬件组装、调试。

孟繁芃,赵雪睿,刘楚涵-河北省涿鹿县涿鹿中学-8.2班,8.4班,8.4班-设计海报.jpg

评论

user-avatar
  • DeadWalking

    DeadWalking2024.05.25

    666 学习了!

    0
    • _深蓝_

      _深蓝_2024.05.13

      我再想,这是不是老师的学生做的呢,格式都没有呀

      0
      • _深蓝_

        _深蓝_2024.05.13

        好想复现云天老师的作品,效果满满,电路一块都是难点哦

        0