亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

校园智能体温监测系统 - 精准、实时、安全的学生健康守护方案

组件与物料清单

组件数量
Pycom SiPy 模块1
Raspberry Pi 3 Model B1
Arduino Nano R31
双向逻辑电平转换模块1
NFC RFID-RC522 模块1
Sharp GP2Y0A41SK0F 模拟测距传感器 (4-30cm)1
MLX90614-DCI I2C 红外测温传感器1
DFRobot I2C 16x2 LCD 显示模块1
LED1
330Ω 电阻2
蜂鸣器1

软件与云服务

问题背景

亚洲炎热气候及 2003 年 SARS 经验,要求中小学生定期测温。传统方式学生自带体温计,易遗失、损坏、忘带,卫生禁止共用,购买负担重,导致测温练习成功率低。教师事后手工录入 40 人数据极其繁琐。

解决方案架构

核心理念:自动测量合法用户体温,数据云端存储,异常自动报警。对应联合国可持续发展目标 (SDG) "良好健康与福祉"。

核心流程:Raspberry Pi + Arduino 协同

  1. Raspberry Pi 运行 Python 程序管理 MySQL 数据库,自动建表
  2. 串口等待 Arduino 数据
  3. 用户刷 RFID 卡 → Arduino 发送 UID → Pi 校验合法性
  4. 合法用户:LCD 显示欢迎,提示测温
  5. 测距传感器确认用户就位 → 红外测温 → LCD 显示结果
  6. 有效温度 (28-42℃) → 经串口发送 Pi (入库 MySQL) 与 SiPy (上传 Sigfox/ThingSpeak)

握手同步机制:双方通过 "READY"/"RECEIVED" 信号同步,避免时序竞争。

Sigfox 云端上传 (SiPy)

SiPy 解析温度整数/小数部分,以字节数组上传 Sigfox 后台,再经回调转发 ThingSpeak。自定义载荷格式确保字段对应正确。

云端数据处理 (ThingSpeak + MATLAB + IFTTT)

  1. 私有通道:接收原始分离数据 (整数、小数、用户ID)
  2. MATLAB Analysis:触发合并温度值,写入公共通道
  3. 公共通道:整合后的温度+用户ID,自动更新表格
  4. React 触发:新数据到达时运行 MATLAB 脚本
  5. IFTTT Webhooks:温度 ≥ 38℃ 触发邮件报警管理员

硬件接线指南 (Arduino Nano)

模块连接引脚
RFID-RC522SDA-D10, SCK-D13, MOSI-D11, MISO-D12, RST-D9, 3.3V, GND
I2C LCDSDA-A4, SCL-A5, 5V, GND
测距传感器VCC-5V, GND, OUT-A0
蜂鸣器GND, OUT-D6
红外测温SDA-A4, SCL-A5, 5V, GND
LED阴极-GND, 阳极-D7

Raspberry Pi 环境搭建

  1. 刷写 Raspbian 系统 (推荐 balenaEtcher)
  2. 启用 SSH/VNC,可选配置静态 IP
  3. 安装 Apache2 + PHP + MariaDB + phpMyAdmin
  4. 配置 MySQL root 用户权限

SiPy 扩展板 2.0 设置

  1. 安装 SiPy 模块 (复位键朝 USB 口)
  2. 固件升级 (选对 RCZ 区域,避免 ID/PAC 全 F)
  3. 安装 VS Code + Pymakr + Node.js
  4. 通过 FTP (FileZilla) 管理闪存文件

Sigfox 后台注册

运行代码获取 Device ID 与 PAC 号,在 Sigfox 后台注册设备,选择正确国家区域。

云端完整配置流程

  1. IFTTT 创建 Webhooks → Email 报警链
  2. ThingSpeak 建立私有/公共双通道
  3. 配置 React 触发 MATLAB 分析脚本
  4. MATLAB 脚本合并温度值、写入公共通道、判断发热触发 IFTTT

核心代码

Arduino Nano (C/C++)


/* 90% 原创 by Aden (https://www.astero.me) */
/* RFID 库参考 ryand1011 / miguelbalboa */
/* MLX90614 库参考 Adafruit */

#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Adafruit_MLX90614.h>

#define RST_PIN 9
#define SS_PIN 10
#define BUZZER_PIN 7
#define LED_PIN 6
#define DIST_SENSE_PIN A0

MFRC522 mfrc522(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
SoftwareSerial unoSerial(2, 3);

boolean tapped = true;
boolean confirmation = false;

String GetUID() {
  String uid = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    uid += String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    uid += String(mfrc522.uid.uidByte[i], HEX);
  }
  String noSpace = "";
  noSpace += uid[1]; noSpace += uid[2];
  noSpace += uid[4]; noSpace += uid[5];
  noSpace += uid[7]; noSpace += uid[8];
  noSpace += uid[10]; noSpace += uid[11];
  return noSpace;
}

void setup() {
  Serial.begin(9600);
  while (!confirmation) {
    Serial.println("ARDUINO");
    confirmation = Serial.readString() == "RAPI";
    delay(1000);
  }
  SPI.begin();
  mfrc522.PCD_Init();
  mlx.begin();
  unoSerial.begin(9600);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  lcd.init(); lcd.backlight();
}

void loop() {
  boolean readySignal = Serial.readString() == "READY";
  if (readySignal) { tapped = true; Serial.println("RECEIVED"); }

  if (tapped) {
    digitalWrite(BUZZER_PIN, 0); digitalWrite(LED_PIN, 0);
    lcd.clear();
    lcd.setCursor(0,0); lcd.print(" Please tap");
    lcd.setCursor(0,1); lcd.print(" your card.");
    delay(500);
    tapped = false;
  } else {
    if (!mfrc522.PICC_IsNewCardPresent()) return;
    if (!mfrc522.PICC_ReadCardSerial()) return;
    
    String card_UID = GetUID(); card_UID.toUpperCase();
    Serial.print(card_UID); Serial.print("\n");
    
    String rawData = Serial.readString();
    int commaPos = rawData.indexOf(',');
    String userInitial = rawData.substring(0, commaPos);
    int userID = rawData.substring(commaPos + 1).toInt();
    
    lcd.clear();
    if (userID != 0 && userInitial != "0") {
      lcd.setCursor(0,0); lcd.print("Welcome, ");
      lcd.setCursor(0,1); lcd.print(userInitial);
      
      int dist = analogRead(DIST_SENSE_PIN);
      byte temp_H = 0, temp_L = 0;
      float meas_temp = 0;
      delay(2000);
      
      while (dist < 170 || dist > 200) {
        dist = analogRead(DIST_SENSE_PIN);
        lcd.setCursor(0,0); lcd.print("Please take");
        lcd.setCursor(0,1); lcd.print("your temperature.");
      }
      
      digitalWrite(BUZZER_PIN, 1); digitalWrite(LED_PIN, 1); lcd.clear();
      meas_temp = mlx.readObjectTempC();
      temp_H = floor(meas_temp);
      temp_L = (meas_temp - temp_H) * 100;
      
      String sMeasTemp = String(userID) + "," + temp_H + "," + temp_L;
      Serial.println("TEMP"); Serial.println(meas_temp);
      
      if (meas_temp >= 28 && meas_temp <= 42) {
        unoSerial.print(sMeasTemp);
        lcd.setCursor(0,0); lcd.print("Temperature: ");
        lcd.setCursor(0,1); lcd.print(" " + String(meas_temp));
      }
      
      rawData = Serial.readString();
      commaPos = rawData.indexOf(',');
      userInitial = rawData.substring(0, commaPos);
      if (userInitial == "0") {
        lcd.clear();
        lcd.setCursor(0,0); lcd.print("Error!");
        lcd.setCursor(0,1); lcd.print("Invalid Temperature.");
      }
    } else {
      lcd.setCursor(0,0); lcd.print("Error!");
      lcd.setCursor(0,1); lcd.print("Invalid User.");
    }
    Serial.println("STANDBY");
    delay(1000);
    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
  }
}

Raspberry Pi (Python)


''' Coded by Aden for Hackster.io Sigfox Competition '''
import mysql.connector, serial, os, time

host = "localhost"; user = "root"; password = "password"; db = "smartTemp"
comPort = 'ttyUSB0'; baudRate = 9600

ser = serial.Serial('/dev/' + comPort, baudRate, timeout=0)
print("Confirming USB Serial Port...")

# 确认串口
connected = False
for x in range(2):
    time.sleep(2)
    ser.write("RAPI")
    if not connected:
        if ser.readline().strip() == "ARDUINO":
            connected = True
            comPort = 'ttyUSB0'
        else:
            comPort = 'ttyUSB1'
            connected = True
    print(comPort)
ser = serial.Serial('/dev/' + comPort, baudRate)
print("COM PORT confirmed: " + comPort)

countFile = open("count.txt", "a++")
cursor = mysql.connector.connect(host=host, user=user, passwd=password).cursor(buffered=True)

try:
    cursor.execute("CREATE DATABASE " + db)
    print("Database created.")
except:
    print(db + " exists.")

cursor.execute("CREATE TABLE IF NOT EXISTS `userInfo` (id int, cardID VARCHAR(9), userID VARCHAR(4), userInitial VARCHAR(8))")
cursor.execute("CREATE TABLE IF NOT EXISTS `tempData` (id int, userID VARCHAR(4), dateMeas date, timeMeas time, tempMeasure decimal(5,2))")

while True:
    cursor = mysql.connector.connect(host=host, user=user, passwd=password).cursor(buffered=True)
    cursor.execute("USE " + db)
    
    cardID = str(ser.readline().strip())
    cursor.execute("SELECT * FROM userInfo WHERE cardID = '" + cardID + "'")
    items = cursor.fetchone()
    
    if items:
        userID = str(items[2])
        userDetails = str(items[3] + ", " + items[2])
        currentDate = time.strftime("%Y-%m-%d")
        currentTime = time.strftime("%H:%M:%S")
        ser.write(userDetails.encode())
        
        tempSignal = False
        while not tempSignal:
            tempSignal = ser.readline().strip() == "TEMP"
            tempData = float(ser.readline().strip())
            print(tempData)
            
            if 28 <= tempData <= 42:
                cursor.execute("INSERT INTO `tempData` VALUES (%s, %s, %s, %s, %s)",
                               (count, userID, currentDate, currentTime, tempData))
                conn.commit()
                count += 1
                countFile = open("count.txt", "w")
                countFile.write(str(count))
            else:
                ser.write(b"0, 0")
    else:
        ser.write(b", 0")
        print("Nothing found")
    
    readySignal = ser.readline().strip() == "STANDBY"
    while readySignal:
        ser.write(b"READY")
        if ser.readline().strip() == "RECEIVED":
            readySignal = False
    cursor.close()

SiPy MicroPython


''' 100% coded by Reginald '''
from machine import UART
from network import Sigfox
import binascii, socket, time, pycom, sys

pycom.heartbeat(False)
sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ4)  # 亚洲区
uart1 = UART(1, baudrate=9600)
uart1.init(9600, bits=8, parity=None, stop=1, pins=('P3','P4'), timeout_chars=20)

while True:
    try:
        recv = uart1.readline()
        if recv:
            print(binascii.hexlify(sigfox.id()))
            print(binascii.hexlify(sigfox.pac()))
            
            sk1 = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
            sk1.setblocking(False)
            sk1.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False)
            
            dataList = recv.decode("utf-8")
            split_val = dataList.split(",")
            userID = int(split_val[0])
            temp_H = int(split_val[1])
            temp_L = int(split_val[2])
            
            bData = [userID, temp_H, temp_L]
            meas_temp = temp_H + temp_L * 0.01
            print("Temp: %.2f" % meas_temp)
            
            sk1.send(bytes(bData))
            sk1.close()
            time.sleep(5)
    except KeyboardInterrupt:
        sys.exit()

ThingSpeak MATLAB 脚本


%% by Aden for Hackster.io Sigfox Competition
readChannelID = 870479;
webhookTrigger = 'https://maker.ifttt.com/trigger/student_fever/with/key/...';
readAPIKey = 'QGHINBPNJQKULBH2';
writeChannelID = 870482;
writeAPIKey = 'R6NJIM8NT5A42R9N';

wholeNumber = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 1);
decimalNumber = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 2) / 100;
userID = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 3);

analyzedData = wholeNumber + decimalNumber;
thingSpeakWrite(writeChannelID, 'Fields', [1,2], 'Values', {analyzedData, userID}, 'WriteKey', writeAPIKey);

if analyzedData >= 38:
    webwrite(webhookTrigger, 'value1', analyzedData, 'value2', userID)
end

团队分工

制造工艺

  1. 树莓派专业温度监测:基于 DS18B20 传感器的完整指南
  2. 树莓派精准监测机柜温度:DS18B20 多点部署实战
  3. DIY 家酿温控系统:Arduino 监测与调节发酵温度
  4. K30 CO₂ 传感器:室内空气质量实时监测
  5. 智能窗帘:基于Arduino与太阳能的自动光控系统
  6. 非接触体温筛查闸机:Arduino MKR1000 + 红外测温 + 舵机控制
  7. Arduino UNO + WiFi 盾板:串口实时推送温度到网页绘图
  8. Arduino 8 位并行 IO 端口库:一行代码实现 8 位数字读写
  9. 智能手语手套:柔性传感器 + 加速度计 + 蓝牙将手势转文字/语音
  10. Arduino 64 键原型键盘矩阵:用移位寄存器打造全自定义键盘
  11. Health Band 智能健康手环:基于 Infineon DPS310 的老人跌倒/步数/体温监护系统
  12. 智慧农业:物联网全维监测开启未来农业新纪元