×

可确定大气颗粒物的Raspberry Pi设备

消耗积分:0 | 格式:zip | 大小:0.24 MB | 2022-12-30

尚文清

分享资料个

描述

什么

本指南介绍了一种 Raspberry Pi 设备,该设备可确定大气颗粒物(空气污染的主要成分)在给定环境中的存在水平。

这里使用的传感器足够精确,可以根据公认的机构报告生成测量值它还包括一个集成环境传感器,可以测量温度、湿度和气压 (T/H/P)。

该设备运行以 Python 编写的以传感器为中心的定制数据流平台,可轻松用于任何类似 Debian 的 Linux 发行版。

该平台包括一个库和工具,用于配置和管理传感器并发布它们的数据,以及在数据基础设施的其他地方(即不在传感器设备上)使用的工具,以有用的方式转换、解释和保存生成的传感器数据流.

如何:硬件

我不会详细介绍如何设置 Raspberry Pi 在其上安装 Raspbian 启用 I²C 接口、在首次启动时启用 WiFi 或在首次启动启用 SSH,因为其他人已经很好地完成了这项工作的确。但是,在本指南的其余部分,您将需要所有这些。

Sensirion SPS30颗粒物传感器使用 JST 的ZH 型 1.5 毫米间距连接器数据表),为此在美国采购预制电缆组件被证明是一项重大挑战!

Sensirion 的支持团队竭尽全力提供帮助,但他们的建议只让我找到了裸露的母连接器,我既没有专业知识也没有材料可以将其变成可用的组件。幸运的是,我最终能够找到我需要的东西

我还想在设备中加入环境感应功能,最近我刚好在漂亮的分线板上订购了一些BME280传感器

为了促进设备之间的模块化和易用性,我更喜欢非永久性连接方法,例如公/母杜邦式接头和连接器,这就是我在这里使用的方法。

 
poYBAGOuNLmAFiLbAA_M8xNex2Q839.jpg
构建传感器组件,显示 BME280 分线和 JST ZH 5 针电缆组件。
 

所需的大部分结构非常简单:我将 BME280 焊接到一个小型永久原型板上,Raspberry Pi 的跳线进入该板 - 携带 3V3 和 5V 分别满足 BME280 和 SPS30 - 以及 ZH -5 组件(当然只携带 5V 电源)连接到 SPS30。

 
poYBAGOuNLyAbtIQAAD54H5OoUU750.png
眼尖的读者 ti-tipakorn 非常友善地提醒我这个图中的 SPS30 连接是反向的!引脚 5(GROUND)在外边缘,而不是它出现的引脚 1!请参阅数据表以了解最终的引脚输出,而不是我的图表。
 

(请注意上面标题中的重要更正:非常感谢ti-tipakorn提醒我!有时间我会更新 Fritzing 图。)

I²C 总线的主要优点之一设备寻址,它允许许多设备共享同一条物理总线,在这里我只需要为这两个设备将五个引线(5V3V3GNDSDA& SCL)带到我的板上。

以防图表没有完全清楚,Pi 的引脚连接如下(指向pinout.xyz的链接更多信息):

请务必注意,SPS30 是一种双模式设备,因此可以在UART (串行)或 I²C 模式下运行。因此,必须注意注意接口规范中突出显示的注释,正如我在上面通过将引脚45 连接到GND

 
poYBAGOuNL6AXv7WAAEbBhQD8sw491.png
请注意此评论,否则您将度过一段糟糕的时光!
 

我使用这块直接暴露 MicroUSB 电源和接地的小板,这样我就可以避免在 RPi 本身上使用 MicroUSB 电源连接器,这不会让它以所需的方向安装在外壳中。

(精明的读者可能会注意到这是一个更新:最初的构造使用的是 Adafruit Powerboost 1000C,因为我还没有可用的 MicroUSB 分线板。项目照片确实显示了“zed”,而是使用了 Powerboost 1000C。好眼力!)

说到外壳:我发现我当地五金店的户外电器部分类似于制造商的糖果店:每次我在那个过道上徘徊时都能找到灵感。

在这种情况下,我选择了一个2 出口防风雨电气导管盒,两个出口彼此相对(180 度):我希望这会产生通过外壳的被动气流。我还沿着两个出口之间的轴安装了 SPS30,直接沿着气流的路径(SPS30 的入口是绿色部分中的白色小矩形,就在黑色风扇罩下方)。

 
pYYBAGOuNMOAfM1GAAaRq85Jvew47.jpeg
从左起:MicroUSB 电源、SPS30 传感器、分支电缆上的 BME280、RPi 零 W(“zed”)。
 

所有东西都塞进了外壳,用一点管道和大猩猩胶带“固定”,并挂在天花板平面以下几英寸(或:“头部水平”以上几英尺)的墙上。

这种安装策略以及外壳有助于确保传感器尽可能少地受到外部环境短期变化的影响。

 
pYYBAGOuNMuAJ459AA2Djiied-c278.png
Zed 在墙上。
 

如何:软件

作为一名接触过大量硬件的软件工程师,我一直很欣赏硬件,但我自己从来没有做过太多的事情。今年,我开始着手改变这种状况,从我闲置多年的备用 RPi 开始。

那次小小的探索逐渐失控,哪里有软件可写,我自然而然地倾向于写它。这就是RPJiOS的由来

您可能会注意到,我已经省略了有关软件本身的许多细节:我正在雄心勃勃地计划一个完全基于此的单独项目指南!请继续关注(祝我好运)...

进入设置。以下所有命令都必须在 Raspberry Pi 本身上运行在首次启动时启用WiFiSSH很容易。

以下内容已经过测试可以正常工作 - 在William R确定并详细说明了对过程的关键修复之后,非常感谢!- 在 Pi Zero W 上全新安装Raspbian Stretch Lite 2018-11-13

  • 你需要git这个,所以如果你还没有安装它,请务必先安装它:
$ sudo apt install -y git
  • 克隆存储库:
$ git clone https://github.com/rpj/rpi.git
  • 克隆创建的新目录中,运行rpisetup.sh
$ cd rpi/
$ ./setup.sh

请不要超级用户 (root) 身份调用。setup.sh该脚本可能会请求sudo您访问所需实用程序的特定安装,但总的来说您不想以超级用户身份运行该脚本。

安装脚本可能需要一段时间,具体取决于安装的干净程度和设备的速度:在全新安装操作系统的零 W 上大约需要 20 分钟(标准住宅互联网连接)。

一旦设置成功(如果不成功,请联系并告诉我!):

  • 创建一个config.json启用 SPS30@0.5Hz 和 BME280@1Hz 的文件,如下所示:
{
  "redis_config": { "host": "localhost" },
  "sensors": [
    { 
      "name": "BME280",
      "config": { "frequency" : 1 }
    },
    {
      "name": "SPS30",
      "config": {
        "frequency": 0.5,
        "shared_object_path": "CHECKOUT_PATH/rpi/env/lib/python2.7/site-packages/rpjios/devices/libsps30.so"
      }
    }
  ]
}

重要:您必须替换为您最初将 git 存储库克隆到CHECKOUT_PATH封闭路径,例如。总有一天我会解决这个问题。 /home/pi

config.json还有许多未说明的其他选项,请参见此处的示例。

如果您在查找libsps30.so驱动程序库时遇到问题(我听说它可能没有像应该的那样由setup.sh构建),我已经为最近的 Raspbian 操作系统发布了二进制文件的预构建版本。只需下载该文件并将其放置在您如上配置的目录中(如果按照此示例进行操作),您就大功告成了!shared_object_path/home/pi/rpi/env/lib/python2.7/site-packages/rpjios/devices/

  • 激活 python 虚拟环境,设置你的路径REDIS_URLbin/sensors-src以你的config.json路径作为唯一参数运行。您会看到正在初始化的传感器:
$ source env/bin/activate
(rpjios venv) $ export REDIS_URL="redis://localhost"
(rpjios venv) $ ./bin/sensors-src config.json
* Loading configuration from config.json
* Using Redis configuration: {u'host': u'localhost'}
* Configured sensors: BME280, DS18S20 (disabled), NetInfo (disabled), SysInfo (disabled), TEPT5700 (disabled), LM335 (disabled), LM335 (disabled), Soil (disabled), DHTXX (disabled), SPS30
* Loaded 'BME280' type=BME280 channel=zed:sensor:BME280>:
{'name': 'BME280', 'hostname': 'zed', 'frequency': '1Hz', 'location': None, 'calibration_data': {'dig_H1': 75, 'dig_H3': 0, 'dig_H2': 332, 'dig_H5': 50, 'dig_H4': 400, 'dig_H6': 30, 'dig_P9': 5000, 'dig_P8': -12000, 'dig_T1': 27678, 'dig_T3': 50, 'dig_T2': 26477, 'dig_P1': 37060, 'dig_P3': 3024, 'dig_P2': -10666, 'dig_P5': -2, 'dig_P4': 6811, 'dig_P7': 12300, 'dig_P6': -7}, 'channel': 'zed:sensor:BME280', 'description': 'Bosch I2C low power pressure, temperature & humidity sensor'}
* Loaded 'SPS30' type=SPS30 channel=zed:sensor:SPS30>:
{'name': 'SPS30', 'hostname': 'zed', 'driver_version': '1.0.0-6-g836d5fc', 'frequency': '0.5Hz', 'location': None, 'serial_number': "'7B4242424242D1'", 'channel': 'zed:sensor:SPS30', 'description': 'Sensiron SPS30 particulate matter sensor'}
...
  • 要轻松验证数据是否按预期流动,请redis-cli在本地使用:
$ redis-cli
127.0.0.1:6379> PSUBSCRIBE *
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "*"
3) (integer) 1
1) "pmessage"
2) "*"
3) "zed:sensor:BME280"
4) "{\"source\": \"zed:sensor:BME280\", \"type\": \"VALUE\", \"ts\": 1546035881.156941, \"value\": {\"temperature\": 82.04924976702895, \"timestamp\": 1546035881.0, \"humidity\": 35.60792598092815, \"pressure\": 1018.030467350658}}"
...

您会在这里看到 RPJiOS 使用命名空间约定“ hostname:type:sensorname”作为它发布的键名。

  • 要轻松地将发出的传感器数据转换和/或转发到另一个redis实例,请使用该downsample工具。
  • 此示例仅将本地(选项)SPS30 传感器 ( ) 中的所有内容转发-i名为frank” ( ) 的主机上,频率为传感器发送数据 ( ) 的十分之一:-p-o-r
(rpjios venv) $ ./bin/downsample -i "redis://localhost" -o "redis://frank" -r 10 -p "*SPS30*"

downsample非常灵活,有多种使用模式,更多示例可以在 中找到README。但最终来源是您最好的信息来源。绝对是双关语。

  • 当然,您可能希望在虚拟环境之外运行这些命令,例如在启动时。没问题!虚拟环境中包含的 python 二进制文件使这变得简单:
(rpjios venv) $ which python
/home/pi/rpi/env/bin/python

使用此路径而不是系统 python 来调用上面讨论的任何工具,您将准备就绪。

守护进程留给读者作为另一个练习,因为根据您的需要,有多种方法可以实现它。

最后,稍后您会看到这些数据通过管道传输到ThingSpeak以进行聚合、可视化、分析和操作。

实现此目的的工具非常简单,并且在大约一个小时内完成编写,说明了将新功能附加到数据流的轻松程度。

要运行它,请确保您处于虚拟环境中(或使用适当的 python 二进制文件)并使用通道 ID 和写入 API 密钥作为仅有的两个命令行参数:

(rpjios venv) $ ./bin/thingspeak CHANNEL_ID WRITE_API_KEY

您可能已经注意到, RPJiOS 还支持许多其他传感器类型,包括一些不需要额外硬件的“虚拟”传感器,例如SysNet 。试试看吧!

教训

  • SPS30 非常灵敏!尽管我尽最大努力将它与日常人类活动隔离开来,但它非常清楚地知道我们何时忙碌和走动,无论我们在房子的哪个位置。非常令人印象深刻!
  • 在我多年单独使用 python 和 C 的过程中,我以前从未尝试过直接将 C 共享库与 python 集成。非常容易另一个喜欢 python 的原因
  • 可能需要的一切都可以在 eBay 或 AliExpress 上以非常便宜的价格获得,但您必须提前计划运输几乎总是最便宜和最慢的品种,所以虽然它(到目前为止)对我来说非常可靠,但它们也与较长的运输时间相当一致。

结果

RPJiOS.com将带您到 ThingSpeak 仪表板,获取由集成MATLAB 分析引擎生成的派生空气质量指数(基于此公式

此外,是原始 SPS30 数据通道和原始 BME280 环境数据的通道。

MATLAB 与 ThingSpeak 的集成还允许人们生成引人注目但有用的仪表板:

 
pYYBAGOuNM2AOQUWAADRITgwm5c931.png
空气质量仪表盘
 

 

 
pYYBAGOuNNCAU-TUAAHMbWcSquI634.png
SPS30 原始数据仪表板
 

(别担心,我已经知道我的时间戳已关闭。)

此外,ThingSpeak 的 React 引擎支持触发操作,例如当空气质量达到阈值水平时在 Twitter 上发出警告。整洁的!

回馈

受到欢迎和鼓励!请在这里发表评论或给我发消息,在 Twitter 上也在这里)与我联系在 GitHub 上提交问题社区让创客变得如此有趣!感谢您的关注!


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

评论(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.obk20.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:'可确定大气颗粒物的Raspberry Pi设备',//标题 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.obk20.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);