×

为活动姿势监测和警报可穿戴设备构建概念验证

消耗积分:0 | 格式:zip | 大小:0.22 MB | 2022-11-10

分享资料个

描述

概述

在 COVID19 之前,人们不得不在正常的生活活动中自愿或不自愿地进行一些体育锻炼。例如,他们必须通勤到学校、办公室或商业场所。在 COVID19 期间,许多人改变了生活方式。他们中的大多数人已经开始在家远程工作,身体活动受到限制。此外,在学校或办公室中,您必须保持坐姿,但在家里,您可以自由地以自己舒适的任何姿势坐下或躺着,或者在工作时出于懒惰。从长远来看,缺乏活动和不良姿势会造成严重的健康问题。主要问题是在办公椅上的不良坐姿引起的脊椎疼痛。在这个项目中,我为活动和姿势监测和警报可穿戴设备构建了一个概念验证,它告诉用户他们的活动或空闲情况,并及时提醒他们让他们活跃或要求纠正姿势。如果有人想重新创建项目,我会尽力提供分步说明。

设置开发环境

我正在使用 MacOS 进行开发。首先,我们需要从这里下载 nRF connect for Desktop:nRF Connect for Desktop 是一个跨平台工具,可以使用 nRF5340 进行测试和开发。请按照上面链接中的安装指南进行操作。安装后打开应用程序并单击工具链管理器以安装 nRF Connect SDK。

pYYBAGNonRSATdQVAACcUvqR66k423.jpg
 

默认情况下,它安装在 MacOS 的 /opt/nordic/ncs 中。由于我们将使用带有 nRF5340 DK 的 Adafruit display shield,Zephyr 中当前版本的 nrf5340 板文件不完全支持 Adafruit display shield 所需的 Arduino 定义。为了解决这个问题,我们需要应用补丁。请按照以下命令应用补丁。

$ cd /tmp
$ git clone https://github.com/NordicPlayground/ncs-display-ble-example.git
$ cd ncs-display-ble-example
$ cp nrf5340_display.patch /opt/nordic/ncs/v1.5.1/zephyr
$ cd /opt/nordic/ncs/v1.5.1/zephyr
$ git apply nrf5340_display.patch

此外,我们将在带有 nRF5340 DK 的 Adafruit shield 中使用内置的 microSD 卡。我们需要在 board/shields/adafruit_2_8_tft_touch_v2/adafruit_2_8_tft_touch_v2.overlay 文件中将 arduino_header 引脚定义从 12 更改为 11,如下所示。

<&arduino_header 11 GPIO_ACTIVE_LOW>; /* D04 */

环境设置完成后,我们必须通过执行以下命令来激活它。

$ source /opt/nordic/ncs/v1.5.1/zephyr/zephyr-env.sh

硬件设置

带显示屏蔽的 nRF5340 DK 用作 BLE 中央设备。连接到 ADXL345 加速度计的 nRF52840 加密狗用作 BLE 外设。连接图原理图可以在原理图部分找到。物理连接如下图所示。

pYYBAGNonRuAZD81AA2292kGyBI79.jpeg
 

我们需要在 BLE 外设应用程序中为 ADXL345 加速度计添加一个覆盖文件,该文件定义加速度计 I2C 引脚定义和从机地址。

&i2c1 {
  compatible = "nordic,nrf-twim";
  status = "okay";
  sda-pin = < 31 >;
  scl-pin = < 29 >;
  clock-frequency = ;
  adxl345@53 {
    compatible = "adi,adxl345";
    reg = < 0x53 >;
    label = "ADXL345";
 };
};

应用

为此,创建了 3 个项目的概念证明。

  • nrf52840_dongle_ble_peripheral_acc(作为数据节点)
  • nrf5340_dk_ble_central_acc(用于数据收集)
  • nrf5340_dk_ble_central_inf(用于模型推理)

所有项目的代码都可以在 Github 存储库中找到:https ://github.com/metanav/AdvancedWearables

数据采集

为 4 个类收集训练数据:

  • 跑步
  • 步行
  • 得好
  • 不好

BLE 外设(nRF52840 加密狗)以 25Hz 的采样率收集 3 轴加速度计数据。每秒它会通过 150 字节 [25 (Hz) x 3 (axis) x 2 (16 bit)] 有效负载通知连接的中央设备。一个易于使用的图形用户界面 (GUI) 是使用允许选择训练标签和存储数据的显示屏蔽设计的。BLE 中央设备从外围设备收集加速度计数据并将其保存到 SD 卡(内置在显示扩展板中)。3 轴加速度计数据保存为 CSV 文件格式,文件名作为标签与自动增量整数连接。示例如下所示:

Filename: Sitting_Bad.4.csv

-187,-937,218
-187,-937,218
-187,-937,218
-187,-906,218
-187,-906,218
-218,-906,218
-218,-906,218
-187,-937,218
-218,-906,218
-218,-906,218
-187,-906,218
-187,-906,218
-187,-906,218
-218,-906,218
-187,-906,218
-218,-906,218
-218,-906,218
-218,-906,218
-218,-906,218
-218,-906,218
-187,-906,218

为 nRF5340 DK 构建和刷新数据采集固件

使用 USB 电缆将 nRF5340 DK 连接到计算机并运行命令:

$ pip3 install -U west
$ git clone https://github.com/metanav/AdvancedWearables
$ cd AdvancedWearables/nrf5340_dk_ble_central_acc
$ source /opt/nordic/ncs/v1.5.1/zephyr/zephyr-env.sh
$ rm -rf build
$ west build -b nrf5340dk_nrf5340_cpuapp
$ west flash

nRF52840 Dongle 的构建和闪存固件

将 nRF52840 加密狗连接到计算机并运行命令:

$ cd AdvancedWearables/nrf52840_dongle_ble_peripheral_acc
$ rm -rf build
$ west build -b nrf52840dongle_nrf52840

我们不能用west来刷 nRF52840。我们将使用 nRF Connect > Programmer。首先按下加密狗上的重置按钮,然后从左上角的下拉菜单中选择设备。单击添加十六进制文件按钮>浏览...并选择 AdvancedWearables/nrf52840_dongle_ble_peripheral_acc/build/zephyr/zephyr.hex 文件并单击写入按钮。

poYBAGNonR6AYKRQAAG2JQ62qfA783.png
 

数据收集演示

 

数据采集​​演示(实时)

 

数据上传到 Edge Impulse Studio

Edge Impulse Studio 为 nRF5340 DK 创建的固件很方便,它会自动将来自 USB UART 连接的数据上传到 DK。但我想制作一款可用于现场数据收集和模型推理的可穿戴设备。走路或跑步时携带笔记本电脑采集数据不方便。此外,您可能在现场没有互联网连接。所以我创建了完全独立的设备,它通过 BLE 从外围设备捕获数据并保存到 microSD 卡中。捕获的数据被复制到计算机。我编写了一个脚本(如下),它将原始加速度计数据转换为 Edge Impulse 工作室训练所需的数据采集 JSON 格式。

import json
import time
import hmac
import hashlib
import os
import configparser

config = configparser.ConfigParser()
config.read('config.ini')
HMAC_KEY = config['edge_impulse']['hmac_key']

dir = 'raw_data'

for filename in os.listdir(dir):
    if filename.endswith('.csv'):
        prefix, ext = os.path.splitext(filename)
        outfilename = os.path.join('formatted_data', '{}.json'
                             .format(prefix))
        values = []
        with open(os.path.join(dir, filename)) as fp:
            for line in fp:
                line = line.strip()
                values.append([int(i) for i in line.split(',')])
                emptySignature = ''.join(['0'] * 64)
                data = {
                    "protected": {
                        "ver": "v1",
                        "alg": "HS256",
                        "iat": time.time()
                    },
                    "signature": emptySignature,
                    "payload": {
                        "device_name": "E1:01:2D:53:40:DA",
                        "device_type": "NRF5340DK",
                        "interval_ms": 40,
                        "sensors": [
                            { "name": "accX", "units": "m/s2" },
                            { "name": "accY", "units": "m/s2" },
                            { "name": "accZ", "units": "m/s2" }
                        ],
                        "values": values
                    }
                }   
                # encode in JSON
                encoded = json.dumps(data)
                # sign message
                signature = hmac.new(bytes(HMAC_KEY, 'utf-8'), 
                                msg = encoded.encode('utf-8'), 
                                digestmod = hashlib.sha256).hexdigest()
                # set the signature again in the message, and encode again
                data['signature'] = signature
                encoded = json.dumps(data, indent=4)
                with open(outfilename, 'w') as fout:
                    fout.write(encoded)

首先将 microSD 卡中的所有原始数据复制到计算机的 raw_data 目录中。您需要在 Edge Impulse 注册一个帐户并创建一个新项目来上传数据。

poYBAGNonSCAPmCCAAAjJ-Wb3XM324.png
 

此外,您需要 Edge Impulse Studio 项目的 HMAC 密钥来生成数据采集格式的签名。您可以从 Dashboard > Keys [tab] 复制 HMAC 密钥,如下所示。

pYYBAGNonSOAXNk4AABJ21e2iow395.png
 

使用您自己的 HMAC 密钥创建一个包含以下内容的config.ini文件。

[edge_impulse]
hmac_key = <your hmac key>

执行以下命令。

$ mkdir formatted_data
$ python3 data_aquisition_format.py

转换后的数据如下图所示。采样率为 25 Hz,因此 interval_ms 为 40ms,如果您的传感器采样率不同,可以在脚本中更改。

{
  "protected": {
    "ver": "v1",
    "alg": "HS256",
    "iat": 1623920716.465548
  },
  "signature": "19bec321f71e504460add5f453fc12d636153f06ebac2f3f6ba4a49813",
  "payload": {
  "device_name": "E1:01:2D:53:40:DA",
  "device_type": "NRF5340DK",
  "interval_ms": 40,
  "sensors": [
     { "name": "accX", "units": "m/s2" },
     { "name": "accY","units": "m/s2" },
     { "name": "accZ", "units": "m/s2" }
   ],
   "values": [
     [ -187, -906, 250 ],
     [ -218, -906, 250 ],
     [ -187, -906, 250 ],
     [ -187, -875, 250 ],
     // more values
    ]
  }
}

使用 Edge Impulse CLI 上传数据。请按照说明在此处安装 CLI:下面的命令用于上传所有 JSON 文件,这些文件会自动拆分为训练和测试数据集。

$ cd formatted_data
$ edge-impulse-uploader --category split *.json

我们可以在Data Acquisition页面看到上传的数据。

pYYBAGNonSeAGzwGAAFc5UWBD5U715.png
 

训练

转到 Impulse Design > Create Impulse 页面并单击Add a processing block并选择Spectral Analysis ,它非常适合分析来自加速度计的重复数据。它提取信号随时间变化的频率和功率特性。此外,在同一页面上单击添加学习块并选择从数据中学习模式的神经网络(Keras),并将其应用于新数据。它非常适合对运动数据进行分类。由于 Sitting 状态的运动识别需要更长的持续时间,因此对于时间序列数据块,我选择了 2000ms 窗口大小和 100ms 窗口增加。现在单击保存脉冲按钮。

pYYBAGNonSqAIHquAAD-CdB2NSc704.png
 

现在转到 Impulse Design > Spectral Features 页面并单击Save parameters按钮。我保留了对我来说看起来不错的默认值。

poYBAGNonS6AIeNPAAHCxPD-wiw271.png
 

单击“保存参数”按钮将重定向到另一个页面,我们应该单击“生成特征”按钮。完成特征生成通常需要几分钟。我们可以在 Feature Explorer 中看到生成的特征的 3D 可视化。数据似乎对步行和跑步有明确的划分,但坐姿有点接近。训练和学习模式并在类之间进行更好的分离将是神经网络的工作。

 

现在转到 Impulse Design > NN Classifier 页面并定义神经网络架构。我创建了具有 4 个密集(完全连接)层的模型,这些层非常适合频谱分析 DSP 模块的输出。训练周期数选择为 50。

poYBAGNonTCAZ20kAADtTPnSk2A430.png
 

现在单击开始训练按钮并等待几分钟,直到训练完成。我们可以在下面看到训练输出。该模型有 86.8% 的准确率,对于这么小的数据集来说还不错,我们还有改进的空间。此外,混淆矩阵清楚地显示了 Sitting_Good 和 Sitting_Bad 类具有误报,可以通过为这两个类收集更多数据来改进。对于这个概念验证项目,我们将使用这个模型。

pYYBAGNonTSAamPYAACfmLyisB8167.png
 

部署

Edge Impulse Studio 支持 nRF5340 DK 部署固件二进制文件,但对于这个项目,我们正在使用其他功能,例如连接到外围设备以获取数据并在 Adafruit 显示屏上显示结果。因此,在部署页面中,我们将选择创建库 > C++ 库选项。对于Select optimization选项,我们将选择Enable EON Compiler以减少模型的内存使用。此外,我们将选择未优化 (Float32) 模型,因为它比量化 (Int8) 模型具有更好的准确性。现在单击Build按钮,几秒钟后库包将下载到本地计算机。

对于推理,我创建了一个新的 nRF5340 DK 项目,它借用了数据收集项目中的大部分 BLE 和显示代码。由于推理库主要包含 C++ 代码库,我们需要在项目设置中更改一些内容。

  • 将数据采集项目复制的src目录下的所有*.c文件重命名为*.cpp
  • 在几个头文件中使用 extern "C"
  • 在 prj.conf 中添加 C++ 配置
CONFIG_CPLUSPLUS=y
CONFIG_LIB_CPLUSPLUS=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
CONFIG_FPU=y

现在解压缩并将以下文件移动到项目根目录。

  • CMakeLists.txt
  • 边缘脉冲 SDK
  • 模型参数
  • tflite 模型

构建并刷新 nRF5340 DK 的推理固件

使用 USB 电缆将 nRF5340 DK 连接到计算机并运行以下命令:

$ git clone https://github.com/metanav/AdvancedWearables 
$ cd AdvancedWearables/nrf5340_dk_ble_central_inf
$ source /opt/nordic/ncs/v1.5.1/zephyr/zephyr-env.sh
$ rm -rf build
$ west build -b nrf5340dk_nrf5340_cpuapp
$ west flash

推理演示

BLE Central (nRF5340) 从 BLE 外设收集 2000 毫秒的加速度计数据并运行推理。推理日志(下图)显示 DSP 时间为 8 毫秒,分类时间为 1 毫秒,这非常快。由于推理速度很快,因此每个推理周期的总滞后时间不超过 2 秒(用于从外围设备累积数据)。

Predictions (DSP: 8 ms., Classification: 1 ms., Anomaly: 0 ms.)

Features (8 ms.): 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 2.509764 0.793651 1.043532 3.571429 0.199363 0.000000 0.000000 0.128670 0.626574 0.175257 0.013350 

Running neural network...
Predictions (time: 1 ms.):
Running:.0.000000
Sitting_Bad:.0.226727
Sitting_Good:.0.773085
Walking:.0.000188
 

结论

该项目最初是作为测试 nRF5340 DK 机器学习可穿戴项目能力的应用程序而开始的。刚开始这似乎是一项艰巨的任务,但在花了一些时间学习 SDK 之后,它变得简单而令人满意。事实证明,nRF5340 DK 是一款功能强大的硬件,非常适合 TinyML。此外,Edge Impulse Studio 是一个易于使用的在线工具,可用于训练和部署机器学习模型以进行快速原型制作。我要感谢 Nordic Semiconductor 为我提供了本次比赛的免费硬件,并迫使我提高了我生疏的 C/C++ 技能。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.lene-v.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'为活动姿势监测和警报可穿戴设备构建概念验证',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.lene-v.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);