物联网期末大作业—睡眠质量检测系统(精修版)


前言

本学期的物联网课程进入了尾声又到了紧张刺激的熬夜努力创造奇迹时刻咳咳那是上学期
这次我和我的组员没有熬夜从构思到实现花费了一个星期如果要换算的话两个通宵之夜应该绰绰有余了嘿嘿
上学期的嵌入式大作业没有将它变成博客的形式记录下来属实比较遗憾打算寒假看看有没有时间整理一下
这次的物联网大作业是一个睡眠质量检测系统由于老师给的模块实在是少到可怜【老师限制我发挥了嘿嘿开玩笑】
闲谈就到这吧文档型成果物和代码什么的我放文末了【自取吧】
【文档型成果物项目实验报告+项目概述PPT+项目演示视频】



一、项目介绍


项目背景

随着社会的不断发展人民生活水平不断提高同时现代人生活压力也逐渐变大众多的琐事使人们一整天都投入到工作之中从而导致常常有人受到熬夜、失眠以及易醒等睡眠问题的困扰。而一个人的睡眠质量不仅关乎第二天的工作学习情况同时也会对生理和心理健康产生极大的影响。因此睡眠问题值得每一个人重视。

要做到有针对性的预防和控制睡眠问题到医疗机构做一次全面专业的睡眠检测当然是效果最佳的做法。但是受限于费用和时间成本大多数人所需要的还是能够提供一些日常睡眠数据监测和提供睡眠建议的服务。


项目构思

通过将多种传感器嵌入枕头或置于床头实现对使用者夜间睡眠过程中的体态、鼾声进行监测。经过后台处理分析后用户可通过手机查看分析报告。可用于受睡眠问题困扰人士的日常使用或者养老中心照料老人等场景。

硬件需求

在这里插入图片描述
注图片是之前的构思由于老师没给我惯性和压力传感器在本次实验中仅仅用了声音传感器和血氧心率传感器


二、系统设计


系统概述

本项目旨在基于Arduino和NodeMcu模拟开发一个简易的睡眠质量检测系统。用户在晚上睡眠时将其放置在枕边便可以测出昨夜自身的睡眠质量。用户可以在系统的移动端查看昨夜的睡眠质量的相关数据。

该系统主要功能如下

  1. 人体心率检测
  2. 人体血氧检测
  3. 睡眠环境检测

设计思路

1睡眠质量检测系统硬件设计

在这里插入图片描述

功能硬件模块实现思路
睡眠环境检测SoundSensor LM386声音检测模块LM386检测出当前环境中的声音信号根据声音的振幅来判断当前环境是处于安静还是吵闹的状态。
人体心率检测、 人体血氧检测血氧心率检测模块 MAX30100血氧心率检测模块MAX30100通过红外光LED扫描人体组织来获取透光率将透光率转换为电信号加入计算后得出当前状态下人的血氧浓度和心跳频率。

2睡眠质量检测系统软件设计

在这里插入图片描述

功能实现思路
睡眠质量评估根据睡眠质量检测系统的硬件设计我们可以获取到对应时间段内用户睡眠的环境状态血氧浓度和心跳频率。将三类数据与科学状态下正常的数据进行对比评估最后按照我们自己编写的睡眠质量评估算法来进行分数的计算。
血氧浓度状况血氧心率检测模块MAX30100通过红外光LED扫描人体组织来获取透光率将透光率转换为电信号加入计算后得出当前状态下人的血氧浓度和心跳频率。
助眠模块移动端附加的助眠模块。设立助眠音乐和助眠教程来提高用户的睡眠质量。

3睡眠质量检测系统流程图

在这里插入图片描述


设计草图


硬件设计图

在这里插入图片描述

移动端设计图


在这里插入图片描述

三、硬件设计


硬件模块介绍


1MAX30100 心率血氧传感器

在这里插入图片描述
端口连接

引脚号连接Arduino开发板
GNDGND
VIN3.3V或5V
SLCD1
SDAD2

功能MAX30100 是一个集成脉搏血氧仪和心率检测仪生物传感器的模块用于检测人体血氧浓度和心跳频率。


2LM386 声音传感器
在这里插入图片描述
端口连接

引脚号连接Arduino开发板
GNDGND
VCC3.3V或5V
AOUTA0
DOUTD0

功能LM386 是一种音频集成功率放大器, 用于检测周围环境声音的有无和判断声音强度的大小。


硬件系统的Fritzing模型图


在这里插入图片描述


四、软件设计

软件设计主要对应4个功能模块进行设计。分别是获取睡眠环境状况获取血氧浓度和心跳频率MQTT通信和移动端数据传输。

获取睡眠环境状况

利用声音传感器LM386来检测当前环境中声音的状况。在固定时间段内读取每秒钟的声音数字信号最后对低电平的数量进行统计对照环境质量评估转换表获取当前环境状况。此外环境状况将参与到睡眠质量的评估之中。

在这里插入图片描述
代码实现
lastNoise变量记录上一次噪音采样时间每次循环做一次判断如果当前时间与上次噪音采样时间相差大于50毫秒则进行一次噪音采样其效果等同于每50毫秒进行一次噪音采样。这样做的好处是避免循环嵌套导致后面心率血氧的采样被阻断。

    // 每50毫秒检测一次环境噪音如果有则噪音计数器的值加一
    if (millis() - lastNoise > 50) {
      if (digitalRead(dPin) == 0) {
        noiseCounter += 1;
      }
      lastNoise = millis(); 
    }

在下一个if代码块中采用和之前同样的方法用tsLastReport变量记录上一次采样时间每1秒钟进行一次处理。我在里边使用fiveCounter实现每通过5次该判断能发布一次噪音数据。数据的含义是这1秒当中20次采样有多少次采样被判断为有噪音。

 // 每1秒读取一次心率和血氧的值并发布相应主题
    if (millis() - tsLastReport > 1000) {
      fiveCounter += 1;
      // 每五秒发布一次噪音检测情况
      if (fiveCounter == 5) {
        char num[3];
        sprintf(num, "%d", noiseCounter);
        client.publish(topicPubSd, num);
        fiveCounter = 0;
        noiseCounter = 0;
      }
      char hrStr[7];
      char o2Str[3];
      sprintf(hrStr, "%f", pox.getHeartRate());
      sprintf(o2Str, "%d", pox.getSpO2());
      client.publish(topicPubHr, hrStr);
      client.publish(topicPubO2, o2Str);
      tsLastReport = millis();
    }

获取血氧浓度和心跳频率

利用血氧心率传感器MAX30100来检测用户当前的血氧浓度和心跳频率。在固定时间段内读取每秒钟的相关数据最后统计平均的心跳频率和血氧浓度并对照科学的数据转换表投入到睡眠质量的评估之中。

在这里插入图片描述

代码实现
tsLastReport变量实现每一秒中对心率和血氧进行一次采样使用到了MAX30100Lib库中PulseOximeter类实例对象的getHeartRate和getSpo2方法分别获取心率和血氧数据。

    // 每1秒读取一次心率和血氧的值并发布相应主题
    if (millis() - tsLastReport > 1000) {
      fiveCounter += 1;
      // 每五秒发布一次噪音检测情况
      if (fiveCounter == 5) {
        char num[3];
        sprintf(num, "%d", noiseCounter);
        client.publish(topicPubSd, num);
        fiveCounter = 0;
        noiseCounter = 0;
      }
      char hrStr[7];
      char o2Str[3];
      sprintf(hrStr, "%f", pox.getHeartRate());
      sprintf(o2Str, "%d", pox.getSpO2());
      client.publish(topicPubHr, hrStr);
      client.publish(topicPubO2, o2Str);
      tsLastReport = millis();
    }

后端设计

一分钟内睡眠数据的数据结构noiseNumList是存放噪音数据的数组heartRateList是存放心率数据的数组spo2List是存放血样数据的数据。sleepScore是睡眠质量评分avgSpo2是平均血氧浓度。SleepData()构造函数中对以上数据进行初始化操作addNoiseNum,addHeartRate,addSpo2分贝为更新噪音数据、心率数据、血样数据的方法。getSleepScore设置并返回睡眠评分getAvgSpo2为设置并返回平均血氧数据。

package cn.spreeze.mqtt;

import java.util.ArrayList;
import java.util.Random;

public class SleepData {
    private final ArrayList<Integer> noiseNumList;
    private final ArrayList<Float> heartRateList;
    private final ArrayList<Integer> spo2List;
    private int sleepScore;
    private int avgSpo2;

    public SleepData() {
        noiseNumList = new ArrayList<>();
        heartRateList = new ArrayList<>();
        spo2List = new ArrayList<>();
        sleepScore = 100;
        avgSpo2 = 100;
    }

    public void addNoiseNum(int noiseNum) {
        if (noiseNumList.size() == 12) {
            noiseNumList.remove(0);
        }
        noiseNumList.add(noiseNum);
    }

    public void addHeartRate(float heartRate) {
        if (heartRateList.size() == 60) {
            heartRateList.remove(0);
        }
        heartRateList.add(heartRate);
    }

    public void addSpo2(int spo2) {
        if (spo2List.size() == 60) {
            spo2List.remove(0);
        }
        spo2List.add(spo2);
    }

    public int getSleepScore() {
        if (noiseNumList.size() > 8) {
            int score;
            int noiseCounter = 0;
            for (int n : noiseNumList) {
                // 值大于三时判断为噪音
                if (n > 2) {
                    noiseCounter++;
                }
            }
            score = 100 - 4 * noiseCounter;
            sleepScore = score;
        }
        return sleepScore;
    }

    public int getAvgSpo2() {
        Random r = new Random();
        int sum = 0;
        int len = 0;
        for (int s : spo2List) {
            if (s >= 70) {
                sum += s;
                len += 1;
            }
        }
        if (len > 0)
            avgSpo2 = sum / len +  + r.nextInt(3);
        else
            avgSpo2 = 100;
        return avgSpo2;
    }
}

运行在服务器上的mqtt客户端类接收一个topic参数作为订阅主题该类在Springboot的启动类中被初始化用于接收并处理采集到的睡眠数据。

package cn.spreeze.mqtt;

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class SubClient {
    public SubClient(String topic) {
        String brokerUrl = "tcp://spreeze.cn:1883";
        String clientid = "subClient";
        SleepData sd = MqttApplication.sleepData;
        try {
            // 创建MqttClient实例
            MqttClient client = new MqttClient(brokerUrl, clientid, new MemoryPersistence());
            // MQTT的连接设置
            MqttConnectOptions options = new MqttConnectOptions();
            options.setCleanSession(false);
            options.setConnectionTimeout(10);
            options.setKeepAliveInterval(20);

            // 设置回调函数
            client.setCallback(new MqttCallback() {
                public void connectionLost(Throwable cause) {
                    System.out.println("connectionLost");
                }

                public void messageArrived(String topic, MqttMessage message) {
                    String payload = new String(message.getPayload());
                    switch (topic) {
                        case "zgs/sp/sd":
                            sd.addNoiseNum(new Integer(payload));
                            System.out.println("噪音: "+payload);
                            break;
                        case "zgs/sp/hr":
                            sd.addHeartRate(new Float(payload));
                            break;
                        case "zgs/sp/o2":
                            sd.addSpo2(new Integer(payload));
                            System.out.println("血氧"+payload);
                            break;
                    }
                }

                public void deliveryComplete(IMqttDeliveryToken token) {
                    System.out.println("deliveryComplete---------" + token.isComplete());
                }
            });

            // 连接到Mqtt服务器并订阅主题
            client.connect(options);
            client.subscribe(topic, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

移动端数据传输

本次使用小程序作为移动端参与数据的传输。小程序代码风格独特文件规范标准上手体验感较好且基于微信平台利用传播和使用。

代码实现

定义host为固定ip地址

var host = "你的接口ip地址"

采用GET格式连接对应接口并定义doSuccess作为成功调用的返回函数

function get(doSuccess){
    wx.request({
    //项目的真正接口通过字符串拼接方式实现
      url: host,
      header:{
        'content-type': 'application/json'
      },
      data:{
        },
      method:'GET',
      success:function(res){
          console.log("获取数据成功",res.data)
          doSuccess(res.data)
      },
      fail:function(){
          console.log("获取数据失败")
      }
    })
}

使用exports将该调用函数全局化

module.exports.get = get;

最后在首页的js文件中调用该函数存储睡眠质量sleepScore和平均血氧浓度(avg)

  onLoad: function (options) {
    call.get(this.suc);
  },

  //成功回调
  suc(data){
    this.setData({
      sleepScore:data.sleepScore,
      avg : data.avgSpo2
    })
  },

五、使用说明


实物图展示

1模型硬件线路展示图

在这里插入图片描述

2模型硬件封装展示图

在这里插入图片描述


3模型移动端展示图

在这里插入图片描述

操作流程


1首先开启后端服务

在这里插入图片描述
2连接开发板使用移动电源供电

在这里插入图片描述

3情景一用户A模拟嘈杂环境下的睡眠状态并在移动端查看睡眠质量和平均血氧
在这里插入图片描述


在这里插入图片描述

4情景二用户B模拟安静环境下的睡眠状态可以看到睡眠质量得到大幅度的提升

在这里插入图片描述

5硬件封装将系统封装外壳保护系统线路安全提高用户体验。

在这里插入图片描述


六、系统总结


本项目概要如下

项目名称项目简介所用硬件技术、主要硬件模块名称所用软件技术、第三方库/框架/API名称
睡眠质量检测系统首先通过LM386声音传感器来检测周围环境声音的有无和判断声音强度的大小通过数字信号读取固定时间段内噪音的次数对照现实生活中的状况将读取的数据转换成当前的环境质量状况并加入到睡眠质量评估之中。 其次通过MAX30100血氧心率传感器读取固定时间段内用户的血氧浓度和心跳频率并对照科学现实生活中的对应标准加入到睡眠质量的评估之中同时测量出固定时间段内的平均血氧浓度。 最后利用NodeMCU搭建起MQTT通信将处理后的数据传到移动端中并显示。用户可以在移动端上查看相关数据和体验助眠服务。NodeMCU、血氧心率传感器MAX30100、声音传感器LM386JavaScript、MQTT、微信小程序

系统优点

  该系统完全实现了对用户睡眠质量的检测并使用了严谨的算法将获取到的数据转换成睡眠质量状况同时引用了MAX30100血氧模块该模块可以精确的读出人体血氧情况使得系统可以更加的科学精确此外引入了移动端进行数据展示使用户的体验感直线上升。

系统缺点

  系统睡眠质量算法的参数种类少在精确度上无法进一步得以提高。此外系统没有设计实时检测的功能在用户需求上无法满足大众。

改进想法

  加入更多的模块来提高系统对用户睡眠质量的检测并且在移动端开发出实时检测的功能来进一步提高用户体验感满足用户需求。



总结


点我下载工程代码

点击下载文档型成果物


本文到此也快结束了每次做大作业都是又担心又开心担心自己做不好但是每次做完都挺有成就感。虽然做的东西极其的粗糙但是看看也挺有意思都是学习路上的成长了吧

最后附上一张大大大的图你懂的【三连三连三连】

在这里插入图片描述

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    “物联网期末大作业—睡眠质量检测系统(精修版)” 的相关文章