#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统 原创 精华

梅科尔工作室陈泓利
发布于 2022-8-30 20:41
浏览
6收藏

@TOC

一、项目简介

  本项目是一个将大数据与物联网和现代医疗相结合的基于华为云OpenHarmony的帕金森病症多数据融合监测系统。该系统可以帮助帕金森轻症患者在家完成手颤抖动、手指弯曲、肌电信号等数据的采样,及时发现帕金森病情恶化趋势,实现疾病的早诊断、早治疗,提高了诊断效率,降低了医疗机构评估工作强度,减轻了患者经济与心理负担。<br>
  该项目基于华为云IoT的端侧规则引擎技术,通过IoTDA设置联动规则,基于SQL语句的规则引擎云端一键下发给设备,在设备之间通过OpenHarmony的分布式软总线,直接在端侧完成设备间的联动,降低网络质量的依赖,提高整体设备联动效率。此外将特征提取算子、滤波算子等云端算子一键下发至传感设备中,在端侧设备上就能完成无效数据的过滤和屏蔽。该项目通过华为云IoT设备接入云服务,不仅仅实现设备通过物模型的极简上云,还让设备具备主动“思考”的能力,从而大幅降低帕金森项目的开发工作量。<br>

#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图1-1 设备实物演示

:::

视频展示链接:https://www.bilibili.com/video/BV17B4y1R7Az?spm_id_from=333.337.search-card.all.click

二、项目痛点

  目前市面上的对帕金森病检测的设备很少,且功能单一。不能结合医疗实现医生对患者日常运动状态的监控。已有的评估方案是对帕金森病的运动障碍评估,这种评估基于病史信息、患者自述和神经科医师的临床检查,并且借助统一帕金森评估量表、改良的运动迟缓评估量表进行评估。此类方法虽然简单易用,全面地反映患者的病情变化,但是也存在着一些不足。第一,准确性差,因为通过医师等评估,依赖主观经验。第二,及时性差,临床评估只能针对患者的当前状态,日常状态无法反映。<br>
  此外还有基于计算机视觉的方法,主要是利用摄像机和光学运动捕捉系统记录患者的运动过程,计算运动学参数,虽然精度较高,但是主要应用于临床试验。关于惯性传感器采集患者的运动信号,从而对症状进行分析和评估。但是存在数据的单一,造成误判等情况。<br>
市面上帕金森疾病检测产品,存在以下痛点:
(1)检测过程复杂
  市面上已存在的帕金森设备存在检测不灵敏、检测过程复杂等问题,且对于患者的检测周期较长。<br>
(2)前期症状不明显
  社会上的帕金森患者在早期的帕金森病表现状况不够明显,也没有相应的日常检测设备。<br>
(3)患者线下数据收集难
  随着互联网医疗体系的完善,医生对患者数据的管理与分析变得迫切。与互联网医疗配套的家用医疗器械缺乏,患者数据无法第一时间向医生反馈。<br>
我们团队在开发时遇到的挑战:
(1)私有协议开发
  自行开发私有协议,并且需要在硬件端和后台同时部署,开发周期达3.5人月,不利于产品的快速开发。<br>
(2)数据量庞大冗余
  针对目前帕金森场景下,每次上传的数据量达到1000条,急需将部分滤波、降维算子进行下发到端侧,减少冗余无用的数据。<br>
(3)场景数据杂乱
  对帕金森场景下的数据获取,没有统一的物模型;涉及30多项设备属性、数据类型和数量大小的确定,后期移植困难。<br>
(4)多设备的数据联动
  针对多个帕金森评估设备之间的信息传输和联动,存在数据传输过程复杂,更新不及时的问题。<br>
  基于以上我们团队结合自身的技术力量,针对上述的问题,使用华为云IoT端侧规则引擎,实现联动规则云端下发、端侧快速执行,提高设备联动效率,提出了一套基于OpenHarmony结合物联网、数据交叉融合算法等技术构建的可穿戴帕金森病症多数据融合监测系统。和市面上相比,我们产品可以实现对帕金森患者的手部震颤加速度数据、肌电信号、手指弯曲的信号和压力数据进行多数据采集,并且采用数据融合技术,实现高准确率的评估。而且在后期,我们可以实现日常情况的随时检测和评估,方便患者的日常使用。<br>

三、项目架构

  帕金森病运动迟缓量化测评系统主控方面是由BearPi-HM Nano组成。通过MPU6050(小熊派套件E53_SC2模块)、弯曲传感器、肌电传感器以及压力传感器采集手部数据。结合华为云IoT平台ModelArts深度学习平台进行交叉验证分析,在预测数据集上取得最好性能的患者模型。并结合UPDRS、H&Y量化评估制定了帕金森全定评估量表,对患者病情程度进行判断。将数据以MQTT协议通过WiFi传输到华为云IoT平台,结合物联网技术以及数据交叉算法,进行数据融合。数据传递到IoT平台后,通过Django后台存储数据到数据库,并提供给前端调用的接口,实现将数据发送到手机或平板终端,实现智能化设计。通过鸿蒙App实现患者日常状态的数据记录和展示,能够及时分析病情并及时调整。项目的架构如图:
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图3-1 项目架构

:::

  该项目基于华为云IoT的端侧规则引擎技术,通过IoTDA设置联动规则,基于SQL语句的规则引擎云端一键下发给设备,在设备之间通过OpenHarmony的分布式软总线,直接在端侧完成设备间的联动,降低对网络质量的依赖,提高整体设备联动效率。此外将特征提取算子、滤波算子等云端算子一键下发至传感设备中,在端侧设备上就能完成无效数据的过滤和屏蔽。该项目通过华为云IoT设备接入云服务,不仅仅实现设备通过物模型的极简上云,还让设备具备主动“思考”的能力,从而大幅降低项目的开发工作量。<br>
  帕金森数据采集模块可以实现对帕金森手部的相关数据进行采集,包括手部禁止性震颤、手指弯曲情况、手部肌电信号以及手指压力等数据,实现无线远程采集。在患者日常生活中,可以使用采集设备进行日常采集和评估。内部由加速度MPU6050(小熊派套件E53_SC2模块)、弯曲传感器以及肌电传感器组成,主控方面是由BearPi-HM Nano组成,穿戴节点为手腕、手指以及手臂,用多个传感器来采集全方位的数据,并且搭载WiFi模块,硬件具有无线传输、工作时间长、微负荷、便携等特点。<br>
  数据分析模块主要包括预处理和ModelArts平台自动学习分析。对于采集到的患者诸多手部数据中,加速度传感器采集数据特征较为显著,因为我们着重分析加速度等数据,并且进行预处理。在处理过程中,我们通过加速度传感器、肌电传感器、弯曲传感获取手部震颤数据以及表面肌电信号等特征数据使用IIR滤波器进行滤波去除异常数据、滤波滤趋势、滤掉重力加速度,进行点积运算,对数据进行归一化处理,采用分布式容合的数据处理方式,最终获得真正有代表性的数据。本团队不仅对数据进行预处理和日常的数据记录,而且还使用深度算法挖掘更深的信息,包括患者的病情预估。在本项目中,团队使用华为AI平台ModelArts作深度学习训练的平台,利用自动学习功能,对数据进行自主分析。<br>
  数据展示部分主要是通过鸿蒙App和网页端实时分析并展示分析结果。获得待推送给用户的数据,实时分析数据并得出当前病情状态分析结果。再结合患者历史数据,基于大数据综合分析,第一时间分析并推送科学的疗养方案和就医建议。从而使用户居家也可以通过鸿蒙App实时了解自己的病情状态,及时获得疗养方案和就医建议,在日常中根据给出对应的训练方案来延缓病情的发展。解决不能及时发现病情变化导致病情快速发展,和医生不能全面了解患者病情状态导致诊断偏差的情况。<br>

四、项目开发部分内容展示

  北向开发:基于润和DAYU200开发板,采用Windows11系统和DevEco Studio 3.0.0.991版本与OpenHarmony 3.1Release操作系统进行开发。<br>
  首先,在DevEco Studio 3.0.0.991版本创建新项目
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图4-1 创建新项目

:::

下面以主页面的实现为例,首先要编写登录页面hml代码,代码如下:

<div class="container">
    <refresh class="refresh" refreshing="{{ isRefreshing }}" onrefresh="Pull_Down">
        <div class='container-top'>
            <div class="titleDiv">
                <text class="title">
                    首页
                </text>
            </div>
        </div>

        <div class="input1">/*搜索服务*/
            <search class="search" hint="智慧医疗" searchbutton="搜索" @search="search"></search>
        </div>

        <div class="assessDiv">
            <div class="assessRowDiv">
                <stack class="circle-progress">
                    <progress class="minProgress" type="eclipse" percent="{{ progressPercent }}" style="color: {{progressColor}};"></progress>
                    <div class="textDiv">
                        <text class="minProgressFont">
                            {{ grade }}级
                        </text>
                        <text class="last_update">
                            {{ last_update }}
                        </text>
                    </div>
                </stack>
            </div>
        </div>

        <div class="gridDiv">
            <div class="action1Div" onclick="action1Div">
                <text class="cardUpText">
                    手指捏合
                </text>
                <div class="cardImgDiv">
                    <image class="cardImg" src="../../common/images/home_finger.png"></image>
                </div>

                <div class="cardDownDiv">

                    <text class="numText">
                        {{ kneading }}
                    </text >
                    <text class="cardDownText">
                        级
                    </text >

                    <text class="cardDownText">
                        10次/5s
                    </text>

                </div>
            </div>

            <div class="action1Div" onclick="action2Div">
                <text class="cardUpText">
                    手指伸展
                </text>
                <progress class="cardImgDiv" type="arc" percent= "25"></progress>

                <div class="cardDownDiv">
                    <text class="numText">
                        {{stretch}}
                    </text >
                    <text class="cardDownText">
                        级
                    </text >

                    <text class="cardDownText">
                        角度90°
                    </text>
                </div>
            </div>

            <div class="action1Div" onclick="action3Div">
                <text class="cardUpText">
                    手掌震颤
                </text>

                <div class="zhenchanDiv">
                    <chart class="chart-data" type="line" ref="linechart" options="{{lineOps}}" datasets="{{lineData}}"></chart>
                </div>
                <div class="cardDownDiv">
                    <text class="numText">
                        {{tremble}}
                    </text >
                    <text class="cardDownText">
                        级
                    </text >
                    <text class="cardDownText">
                        幅度2.1cm
                    </text>
                </div>
            </div>

            <div class="action1Div" onclick="action4Div">
                <text class="cardUpText">
                    手臂肌电
                </text>

                <div class="cardImgDiv">
                    <image class="cardImg" src="../../common/images/home_jidian.png"></image>
                </div>

                <div class="cardDownDiv">
                    <text class="numText">
                        {{muscle}}
                    </text >
                    <text class="cardDownText">
                        级
                    </text >
                    <text class="cardDownText">
                        峰值
                    </text>
                </div>
            </div>
        </div>

    </refresh>

</div>

编写主页面js代码,代码如下:

import router from '@system.router';
import prompt from '@system.prompt'
import http from '@ohos.net.http'

export default {
    data: {
        title: 'World',
        progressPercent: 20,
        progressColor: "#00ff00",
        bgColor: "#669966",
        percent: 90,
        grade: '',
        kneading:'3.5',
        stretch:'2.6',
        tremble:'2.1',
        muscle:'3.4',
        last_update: '',
        returnContent: '',
        isRefreshing: false,
        lineData: [
            {
                strokeColor: '#0081ff',
                fillColor: '#cce5ff',
                data: [763, 550, 551, 554, 731, 654, 525, 696, 628, 344, 545, 654, 632, 753, 325, 632, 754, 980],
                gradient: true,
            }
        ],
        lineOps: {
            xAxis: {
                min: 0,
                max: 20,
                display: false,
            },
            yAxis: {
                min: 0,
                max: 1000,
                display: false,
            },
            series: {
                lineStyle: {
                    width: "2px",
                    smooth: true,
                },
                headPoint: {
                    shape: "circle",
                    size: 5,
                    strokeWidth: 5,
                    fillColor: '#ffffff',
                    strokeColor: '#007aff',
                    display: true,
                },
                loop: {
                    margin: 2,
                    gradient: true,
                }
            }
        },
    },

    onInit(){
        if(this.progressPercent>0 && this.progressPercent<=20){
            this.progressColor = "#da25ca25"
        } else if (this.progressPercent>20 && this.progressPercent<=40){
            this.progressColor = "#80c8ff00"
        } else if (this.progressPercent>40 && this.progressPercent<=60){
            this.progressColor = "#80ffd500"
        } else if (this.progressPercent>60 && this.progressPercent<=80){
            this.progressColor = "#80ff7700"
        } else if (this.progressPercent>80){
            this.progressColor = "#80ff0000"
        }

        this.refreshButton();

        setTimeout(() => {
            prompt.showToast({
                message: "已加载"
            })
        }, 500)
    },


    refreshButton(){
        let httpRequest = http.createHttp();
        // 创建一个http,里面包括发起请求、中断请求、订阅/取消订阅HTTP Response Header 事件。
        // 每一个HttpRequest对象对应一个Http请求。如需发起多个Http请求,须为每个Http请求创建对应HttpRequest对象。
        //返回一个HttpRequest对象,里面包括request、destroy、on和off方法。

        let url = "http://49.4.115.226:8000/get_end_data?date=04-28";

        httpRequest.request(url, {
            // 注意请求方法:http.POST
            method: 'POST',
        }, (err, data)=> {  // 判断是否请求成功
            if (!err) {  // 请求成功
                this.returnContent = JSON.parse(data.result);  //JSON.parse(字符串)——将字符串转换成json数据格式
                this.grade = this.returnContent.results[0].data.grade
                this.kneading = this.returnContent.results[0].data.Kneading
                this.stretch = this.returnContent.results[0].data.stretch
                this.tremble = this.returnContent.results[0].data.tremble
                this.muscle = this.returnContent.results[0].data.muscle
                this.last_update = this.returnContent.results[0].last_update
            } else {  // 请求失败
                prompt.showToast({
                    message: data.result,
                    duration: 3000,
                });
            }
        })
    },

    Pull_Down: function(e) {
        this.isRefreshing = e.refreshing;

        this.refreshButton();
        setTimeout(() => {
            this.isRefreshing = false;
            prompt.showToast({
                message: "刷新成功"
            })
        }, 1500)
    },

    action1Div(){
        router.push({
            uri:'pages/kneading/kneading', // 指定要跳转的页面
        })
    },

    action2Div(){
        router.push({
            uri:'pages/bend/bend', // 指定要跳转的页面
        })
    },

    action3Div(){
        router.push({
            uri:'pages/accel/accel', // 指定要跳转的页面
        })
    },

    action4Div(){
        router.push({
            uri:'pages/muscle/muscle', // 指定要跳转的页面
        })
    },
}


编写主页面css代码,代码如下:

.container {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-direction: column;
    background-color: #f2f3f5;

}

.input1{
    margin-top: 20px;
    margin-bottom: 5px;
    margin-right: 15px;
    margin-left: 15px;
    height: 50px;
}

.search {
    background-color: white;
}

.container-top{
    margin-top: 10px;
    width: 100%;
    flex-direction: row;
    height: 34px;
    justify-content: space-around;
}

.titleDiv {
    width: 90%;
}

.top-text{
    margin-left: 100px;
    font-size: 20px;
    flex-weight: 800;
}

.top-img1{
    margin-left:20px;
    width: 30px;
    height: 30px;
    object-fit:fill;
}

.top-img2{
    margin-right: 20px;
    width: 30px;
    height: 30px;
    object-fit:fill;
}

.title {
    font-size: 25fp;
    font-weight: 600;
}

.timeDiv {
    height: 20px;
}

.assessDiv {
    border:0.4px  #85929292;
    border-radius: 10px;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 180px;
    border-radius: 10px;
    background-color: #ffffff;
    flex-direction: column;
    margin-bottom: 10px;
    margin-right: 15px;
    margin-left: 15px;
}

.assessTitle{
    align-items: center;
    height: 50px;
    border-top-right-radius: 10fp;
    border-top-left-radius: 10fp;
    justify-content: center;
    width: 100%;
    background-color: #355bff;
    margin-bottom: 20px;
    color: white;
    font-size: 25fp;
}

.assessRowDiv {
    justify-content: space-between;
}

.circle-progress {
    height: 160px;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.textDiv {
    justify-content: center;
    align-items: center;
    flex-direction: column;
}

.minProgress {
    width: 180px;
    height: 180px;
}

.minProgressFont {
    margin-top: 10px;
}

.last_update {
    font-size: 20fp;
    color: dimgray;
}

.circleDiv {
/*    radius: 50fp;*/
    width: 150fp;
    height: 150fp;
    align-items: center;
    justify-content: center;
    margin-right: 15fp;
}

.progressDiv {
    margin-top: 10px;
    margin-bottom: 10px;
    width: 80%;    
}

.progress{
    stroke-width: 6fp;
}

.gridDiv {
    margin-left: 2%;
    margin-right: 2%;
    display: grid;
    grid-template-columns: 1fr  1fr;
    grid-template-rows: 180px  180px;
    height: 400px;
}

.action1Div {
    border:0.4px  #85929292;
    border-radius: 10px;
    flex-direction: column;
    background-color: #ffffff;
    width: 93%;
    height: 93%;
    border-bottom-right-radius: 15fp;
    border-bottom-left-radius: 15fp;
    border-top-left-radius: 15fp;
    border-top-right-radius: 15fp;
    justify-content: space-between;
    align-items: center;
/*    justify-content: center;*/
}

.cardUpText {
    margin-top: 10px;
    margin-left: -60px;
    font-size: 17fp;
    font-weight: 600;
}

.zhenchanDiv {
    justify-content: center;
    align-items: center;
}

.chart-data {
    width: 200px;
    height: 100px;
}

.cardImgDiv{
    width: 70px;
    height: 70px;
    stroke-width: 10px;
}

.cardImg{
    object-fit: cover;
}

.cardDownDiv {
    font-size: 20fp;
    justify-content: center;
    align-items: flex-end;
    margin-bottom: 10px;
}

.numText {
    font-weight: 600;
    font-size: 30fp;
    margin-bottom: -5px;
}

.cardDownText {
    font-size: 14fp;
    color: dimgray;
}

效果展示,如图4-2所示。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图4-2 主页面

:::

  南向开发:基于BearPi-HM_Nano开发板,采用Windows11+Ubuntu18.04 OpenHarmony 2.0操作系统.<br>
  关于南向开发环境的搭建,可以参考下方文档。
https://gitee.com/bearpi/bearpi-hm_nano/blob/master/applications/BearPi/BearPi-HM_Nano/docs/quick-start/BearPi-HM_Nano十分钟上手.md<br>
帕金森设备数据上报mqtt模块代码编写如下

static void deal_report_msg(report_t *report)
{

    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t muscle;
    oc_mqtt_profile_kv_t pressure;
    oc_mqtt_profile_kv_t accel_x;
    oc_mqtt_profile_kv_t accel_y;
    oc_mqtt_profile_kv_t accel_z;
    oc_mqtt_profile_kv_t gyro_x;
    oc_mqtt_profile_kv_t gyro_y;
    oc_mqtt_profile_kv_t gyro_z;
    oc_mqtt_profile_kv_t bend_1; // 弯曲传感器 1
    oc_mqtt_profile_kv_t bend_2; // 弯曲传感器 2
    oc_mqtt_profile_kv_t bend_3; // 弯曲传感器 3

    if(g_app_cb.connected != 1){
        return;
    }

    // 帕金森物模型
    service.event_time = NULL;
    service.service_id = "帕金森&传感器";
    service.service_property = &muscle;
    service.nxt = NULL;

    muscle.key = "Muscle"; // 肌电传感器:峰峰值、频带能量
    muscle.value = &report->mus;
    muscle.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    muscle.nxt = &pressure;

    pressure.key = "Pressure"; // 压力传感器:捏合次数
    pressure.value = &report->kneading;
    pressure.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    pressure.nxt = &accel_x;

    accel_x.key = "Accel_x"; // x轴加速度传感器:手部震颤频率
    accel_x.value = &report->acc_x;
    accel_x.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    accel_x.nxt = &accel_y;
    
    accel_y.key = "Accel_y"; // y轴加速度传感器:手部震颤频率
    accel_y.value = &report->acc_y;
    accel_y.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    accel_y.nxt = &accel_z;

    accel_z.key = "Accel_z"; // z轴加速度传感器:手部震颤频率
    accel_z.value = &report->acc_z;
    accel_z.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    accel_z.nxt = &gyro_x;

    gyro_x.key = "Gyro_x";
    gyro_x.value = &report->gr_x;
    gyro_x.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    gyro_x.nxt = &gyro_y;

    gyro_y.key = "Gyro_y";
    gyro_y.value = &report->gr_y;
    gyro_y.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    gyro_y.nxt = &gyro_z;

    gyro_z.key = "Gyro_z";
    gyro_z.value = &report->gr_z;
    gyro_z.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    gyro_z.nxt = &bend_1;

    bend_1.key = "Bend_1";
    bend_1.value = &report->bd_1;
    bend_1.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    bend_1.nxt = &bend_2;

    bend_2.key = "Bend_2";
    bend_2.value = &report->bd_2;
    bend_2.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    bend_2.nxt = &bend_3;

    bend_3.key = "Bend_3";
    bend_3.value = &report->bd_3;
    bend_3.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    bend_3.nxt = NULL;

    oc_mqtt_profile_propertyreport(NULL,&service);
    return;
}

//use this function to push all the message to the buffer
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t *msg)
{
    int    ret = 0;
    char  *buf;
    int    buf_len;
    app_msg_t *app_msg;

    if((NULL == msg) || (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)){
        return ret;
    }

    buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
    buf = malloc(buf_len);
    if(NULL == buf){
        return ret;
    }
    app_msg = (app_msg_t *)buf;
    buf += sizeof(app_msg_t);

    app_msg->msg_type = en_msg_cmd;
    app_msg->msg.cmd.request_id = buf;
    buf_len = strlen(msg->request_id);
    buf += buf_len + 1;
    memcpy(app_msg->msg.cmd.request_id, msg->request_id, buf_len);
    app_msg->msg.cmd.request_id[buf_len] = '\0';

    buf_len = msg->msg_len;
    app_msg->msg.cmd.payload = buf;
    memcpy(app_msg->msg.cmd.payload, msg->msg, buf_len);
    app_msg->msg.cmd.payload[buf_len] = '\0';

    ret = queue_push(g_app_cb.app_msg,app_msg,10);
    if(ret != 0){
        free(app_msg);
    }

    return ret;
}

<br>
帕金森设备指令执行模块代码如下

///< COMMAND DEAL
#include <cJSON.h>
static void deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;
    cJSON *obj_cmdname;
    cJSON *obj_paras;
    cJSON *obj_para;
    cJSON *obj_para_low, *obj_para_high, *obj_para_in_min, *obj_para_in_max, *obj_para_out_min, *obj_para_out_max;

    int cmdret = 1;
    oc_mqtt_profile_cmdresp_t cmdresp;
    obj_root = cJSON_Parse(cmd->payload);

    if (NULL == obj_root)
    {
        printf("EXIT_JSONPARSE!");
        goto EXIT_JSONPARSE;
    }

    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname)
    {
        goto EXIT_CMDOBJ;
    }

    /* 
    * 根据不同的指令判断:进入对应的处理模块
    * 指令1:手指捏合 Kneading
    * 指令2:手指弯曲 Bend
    * 指令3:震颤 Tremor
    * 指令4:肌电 Muscle
    */

    // 指令1:手指捏合 Kneading
    if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Kneading"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (NULL == obj_paras)
        {
            printf("EXIT_OBJPARAS!");
            goto EXIT_OBJPARAS;
        }

        obj_para = cJSON_GetObjectItem(obj_paras, "kneading_control");
        if (NULL == obj_para)
        {
            printf("EXIT_OBJPARA!");
            goto EXIT_OBJPARA;
        }
        ///< 打开压力传感器 here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.flag_kneading = 1;
            // Light_StatusSet(ON);  // 此处可以添加LED灯,提示目前对应传感器正在操作中
            printf("压力传感器 On!");
        }
        ///< 关闭压力传感器
        else
        {
            g_app_cb.flag_kneading = 0;
            // Light_StatusSet(OFF);
            printf("压力传感器 Off!");
        }
        cmdret = 0;
    }
    // 指令2:手指弯曲 Bend
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Bend"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "bend_control");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the Motor here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.flag_bend = 1;
            // Motor_StatusSet(ON);
            printf("弯曲传感器 On!");
        }
        else
        {
            g_app_cb.flag_bend = 0;
            // Motor_StatusSet(OFF);
            printf("弯曲传感器 Off!");
        }
        cmdret = 0;
    }

    // 指令3:震颤 Tremor 加速度传感器MPU6050
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Tremor"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "tremor_control");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the Motor here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.flag_tremor = 1;
            // Motor_StatusSet(ON);
            printf("MPU6050 On!");
        }
        else
        {
            g_app_cb.flag_tremor = 0;
            // Motor_StatusSet(OFF);
            printf("MPU6050 Off!");
        }
        cmdret = 0;
    }

    // 指令4:肌电 Muscle
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Muscle"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "muscle_control");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the Motor here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.flag_muscle = 1;
            // Motor_StatusSet(ON);
            printf("肌电传感器 On!");
        }
        else
        {
            g_app_cb.flag_muscle = 0;
            // Motor_StatusSet(OFF);
            printf("肌电传感器 Off!");
        }
        cmdret = 0;
    }

五、设计思路

5.1 基于OpenHarmony的帕金森数据采集模块<br>

  帕金森数据采集模块可以实现对帕金森手部的相关数据进行采集,包括手部禁止性震颤、手指弯曲情况、手部肌电信号、手指捏合压力等数据,实现无线远程采集。在患者日常生活中,可以使用采集设备进行日常采集和评估。内部由加速度MPU6050(小熊派套件E53_SC2模块)、弯曲传感器、肌电传感器以及压力传感器组成,主控方面是基于OpenHarmony系统开发,穿戴节点为手腕、手指以及手臂,用多个传感器来采集全方位的数据,并且搭载WiFi模块,硬件具有无线传输、工作时间长、微负荷、便携等特点。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图5-1 数据采集模块

:::

5.2 数据管理和后台模块<br>

(1)帕金森康复数据传输和标注物模型设定<br>
  采用海思的Hi3861V100作为主控芯片基于OpenHarmony操作系统,通过华为云IoTDA设备接入服务实现数据的传输,采用MQTT协议,将加速度数据、弯曲传感器数据、肌电传感器数据和压力数据打包成json格式WiFi传输到华为IoT平台上。<br>
在华为云平台上实现帕金森康复手套的物模型建立。实现了平台的二次开发和一键导入。本项目的物模型包括加速度、角速度、压力、弯曲角度、肌电信号、训练时长等。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图5-2 标准物模型

:::

  使用华为云IoT云平台的数据转发服务,实现数据转发到华为云ECS服务器,服务器端使用的是基于Django的Web应用框架,实现从数据采集到传输至云平台,再到ECS服务器,实现数据的持久化存储。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图5-3 数据转发

:::

(2)命令下发和算法下发实现
  通过平板调用华为云IoT平台下发和算子下发的API接口,实现手指弯曲、手指捏合、手指震颤、手臂弯曲等范式动作的控制命令,并通过对应的传感器获取数据,另外将原先部署在云端的滤波算法下发到端侧设备中,实现了远程更新端侧算法和参数等。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图5-5 命令下发与算子下发

:::

5.3 数据分析模块<br>

(1)数据预处理算法
  对于采集到的数据在端侧进行预处理。在处理过程中,我们将加速度传感器、肌电传感器、弯曲传感获取手部震颤数据以及表面肌电信号等特征数据使用IIR滤波器进行滤波去除异常数据、滤波滤趋势、滤掉重力加速度,进行点积运算,对数据进行归一化处理,采用分布式容合的数据处理方式,最终获得真正有代表性的数据。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图5-6 数据预处理算法

:::

(2)基于ModelArts平台的数据交叉融合算法
  本团队不仅对数据进行预处理和日常的数据记录,而且还使用深度算法挖掘更深的信息,包括患者的病情预估。在本项目中,团队使用华为AI平台ModelArts作深度学习训练的平台,使用BP神经网络作为训练模型,对数据进行自主分析。<br>
并且在输入的数据是多传感器交叉的多维数据,以及对应的每条数据对应的评估标准,最终数据帕金森患者疗效预估评分。因为本项目主要是对帕金森患者病情的评估,团队基于UPDRS量化评估表、H&Y逻辑定量表与帕金森医师评估,制定了帕金森全定评估量表。所以将最终所得评估结果与医生的评断以及全定量化评估表进行比较,获取评估的准确性。
#物联网征文# 基于OpenHarmony的帕金森病症多数据融合监测系统-鸿蒙开发者社区
::: hljs-center

图5-7 数据交叉融合算法

:::

  在具体的评估中,需要结合量化的评估标准。团队从行业权威的UPDRS评估量表和H&Y分级定量表出发,和河南省中医院的医师合作制定全定评估量表,实现量化评估。<br>

5.4 范式动作测试方法

  由于设备在采集数据时,受到各种因素影响,如采集的环境、不同人群等,此类因素可能会造成数据集质量不高以及数据分析时造成不准确的情况。因此团队和河南省中医院展开合作,基于帕金森患者实际的症状表现情况分析,制定适用于60岁以上人群的范式动作测试方法,并且和本团队设计的可穿戴硬件相结合,实现在家庭环境下,进行数据采集和分析。<br>
  范式动作测试方法将根据每一个范式动作进行检测,按照手指弯曲检测、手指捏合检测、手部震颤检测、手臂弯曲的肌电信号检测为顺序执行整个范式动作。<br>

六、实现原理

  产品基于OpenHarmony与华为云IoT端侧规则引擎,实现联动规则云端下发。通过使用华为云IoT的端侧规则引擎能力,将设备间的联动规则直接通过云端一键下发给设备,在设备之间通过OpenHarmony的分布式软总线,直接在端侧完成设备间的联动,降低网络质量的依赖,提高整体设备联动效率。<br>
  另外本产品是基于ModelArts自动学习结合全定评估量表的方式,实现帕金森病的康复情况监测,提出当前的就医建议,并且将结果实时展示给用户。并且设备结合物联网技术,使用WIFI和4G模块,实现了无线远程数据传输。此外我们对本产品的数据收集,设计了一套标准的范式动作测试方法,可以准确实现高质量数据采集。<br>
  通过压力传感器、弯曲传感器、加速度传感器以及肌电传感器,对帕金森手臂和手部的数据同时采集,并通过多源异质融合算法实现对帕金森病情的异常数据进行排查,如当帕金森患者的震颤频率小于4Hz,触发肌电传感器二次识别患者是否处于静止性震颤状态。<br>

七、功能介绍

  (1)基于多传感器融合数据采集模块可以实现对帕金森患者手部的相关数据进行采集,包括手部禁止性震颤、手指弯曲情况、手部肌电信号、手指捏合压力等数据,实现无线远程采集。<br>
  (2)可以将数据发送到手机或平板终端,实现智能化设计,并通过鸿蒙App页面实现患者日常状态的实时分析和结果展示。实时分析数据并得出当前病情状态分析结果。再结合患者历史数据,第一时间分析并推送科学的疗养方案和就医建议。实现医生与患者之间跨越时间空间的交流,医生及时获得患者实时状态数据,能够及时分析病情并给出建议。<br>
  (3)我们基于UPDRS量化评估表、H&Y逻辑定量表与帕金森医师评估,制定了帕金森全定评估量表,并通过多源异质融合算法实现对帕金森病情的异常数据进行排查。所以我们会将最终所得评估结果与医生的评断以及全定量化评估表进行比较,获取评估的准确性。<br>
  (4)本产品基于小型化和轻量化的思路设计,可以方便患者在家庭中进行自主检测。整套设备重量200g,工作时间可以达到5天,并且采用手套穿戴式设计,便于患者使用。<br>
  (5)使用华为云IoT云平台的数据转发服务,实现数据转发到华为云ECS服务器,服务器端使用的是基于Django的Web应用框架,实现从数据采集到传输至云平台,再到ECS服务器,实现数据的持久化存储。

八、应用场景

  目前帕金森患者无法对自身的病情进行有效的预防和监控。在日常生活中,只能到医院进行相关检查才能够给获取自行的病情。那么如何快速有效的获取帕金森患者的病情以及后期预控是迫切解决的问题。<br>
  此外,医护人员需要借助互联网进行数据收集、传输、分析,给予患者以相对持续、无创便携的病情监控,提高医护人员的工作效率,节约了时间和成本。而且如果出现了问题,还可以直接反馈给医生进一步降低医疗成本,释放传统医疗资源。<br>
  因此使用穿戴式传感器设备,通过多传感器多方面检测患者运动状态数据,将得到的传感器数据送往数据处理中心进行交叉分析验证,并结合量化评估表达到对患者病情程度进行判断。从而在一定程度上可以预测以及监控帕金森病的具体发展情况。并且结合物联网,将数据推送到鸿蒙APP中,提供给患者以及医护人员随时查看。

(1)患者居家
  作品聚焦于65岁以上前中期帕金森患者,而且主要面向居家患者。对帕金森患者可以通过医疗辅助器材商店或者网上购买本产品,使用产品设备每天一到三次,按照我们自主设计的范式测量方法进行简短时间的数据采集,可以实时通过鸿蒙APP查看病情状况和分析及科学的疗养方案。<br>
(2)医院
  医生面对新就诊患者时,本产品检测病情程度的功能,可以辅助医生准确判断患者当前病情情况;医生面对复查病情的患者时,可以参考产品记录患者的日常数据、分析的结果,及实时检测的结果对患者进行准确的病情状态把握,有利于准确诊断。并且和河南省中医院等省市级医院达成合作后,通过省市级医院的辐射作用推广到下级医院。<br>
(3)社区康养中心
  作品将推广到社区康养中心,实现区域化推广和销售。患者可以在康养中心的专业人员指导下使用,更加专业和科学。<br>
(4)医疗科研机构
  对于各大高校,研究机构等,需要相关的软硬件作为数据采集终端,本作品将面向科研人员进行推广售卖。<br>

九、产品价值

  本作品主要用于采集帕金森患者日常运动状态数据并记录方便医生了解患者病情情况并及时给予康复建议。并且主要的客户来源是中老年人帕金森患者,并且有一定时间的患病经历。目的旨在解决早发现帕金森病的前驱症状,实现疾病的早诊断、早治疗。以及医生与患者突破时间,空间限制的交流,实现帕金森患者居家获得及时的医生康复建议。<br>
  市面上帕金森疾病检测产品,存在以下痛点:
(1)检测过程复杂
  市面上已存在的帕金森设备存在检测不灵敏、检测过程复杂等问题,且对于患者的检测周期较长。<br>
(2)前期症状不明显
  社会上的帕金森患者在早期的帕金森病表现状况不够明显,也没有相应的日常检测设备。<br>
(3)患者线下数据收集难
  随着互联网医疗体系的完善,医生对患者数据的管理与分析变得迫切。与互联网医疗配套的家用医疗器械缺乏,患者数据无法第一时间向医生反馈。<br>

  基于以上我们团队结合自身的技术力量,针对上述的问题,使用华为云IoT端侧规则引擎,实现联动规则云端下发、端侧快速执行,提高设备联动效率,提出了一套结合物联网、数据交叉融合算法等技术构建的基于可穿戴传感器的帕金森病运动迟缓量化测评系统。和市面上相比,我们产品可以实现对帕金森患者的手部震颤加速度数据、肌电信号、手指弯曲的信号和压力数据进行多数据采集,并且采用数据融合技术,实现高准确率的评估。而且在后期,我们可以实现日常情况的随时检测和评估,方便患者的日常使用。<br>
【本文正在参加物联网有奖征文活动】,活动链接:https://ost.51cto.com/posts/14758

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
6
收藏 6
回复
举报
9条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

看过了文章和展示的视频后,更加佩服楼主的事业了。

回复
2022-8-31 11:14:03
带带小老弟
带带小老弟

久闻帕金森大名,如果能防患于未然肯定是非常好的

回复
2022-8-31 17:00:20
麻辣香锅配馒头
麻辣香锅配馒头

多数病情往往因为早期难以排查而耽误最佳治疗时期,能有简单准确的诊断机器肯定是要支持的。

回复
2022-9-1 17:16:30
真庐山升龙霸
真庐山升龙霸

希望能在鸿蒙生态看到更多类似案例

回复
2022-9-2 12:00:56
有故事的王同学
有故事的王同学

这算是"医疗+物联网"了

回复
2022-9-2 14:27:55
青舟321
青舟321

希望商业化后看病成本不要太高

已于2022-9-2 16:19:10修改
回复
2022-9-2 16:19:04
梅科尔工作室陈泓利
梅科尔工作室陈泓利 回复了 带带小老弟
久闻帕金森大名,如果能防患于未然肯定是非常好的

早发现,早控制

回复
2022-9-5 17:49:13
梅科尔工作室陈泓利
梅科尔工作室陈泓利 回复了 真庐山升龙霸
希望能在鸿蒙生态看到更多类似案例

会的,会的,支持OpenHarmony!

回复
2022-9-5 17:50:09
梅科尔工作室陈泓利
梅科尔工作室陈泓利 回复了 有故事的王同学
这算是"医疗+物联网"了

对的,物联网+智慧医疗

回复
2022-9-5 17:51:39
回复
    相关推荐