IoTで使うPython入門Step2-MQTT (6) A-Dコンバータ

 センサの多くはデータ収集間隔が比較的長いです。それは、温度などの情報は急激に変化しないからですし、電池の寿命もあるでしょう。そういうデータを扱うにはMQTTは適しています。けれど、Brokerは複数のPublisherからの通信を受けなければならないので、次の二つに問題があることに気が付きます。

  • どのくらいの時間データを保持してくれるのか。Subscriverが取りに行ったときにデータの欠落はないのか
  • 時間当たりのBrokerの処理能力はどのくらいなのか

 どちらも電子工作的には問題視するところではありませんが興味はあります。最初の問題点は、データが欠落してもよいように、全体の構成を考えればよいです。
 ものすごくたくさんのデータをBrokerに矢継ぎ早に送る実験をします。

データを高速に送るpublish側

 12ビットA-DコンバータのMCP3208を利用します。インターフェースはSPIです。こちらの記事で利用しているので、プログラムを流用します。データ転送速度は10MHzを指定しました。いままでこの周波数の指定はなくとも動いていましたが、2018年11月現在、必須になったのかもしれません。
 sleepの間隔は1msほどです。後半で、実際の発行間隔を調べました。

#coding:utf-8
import paho.mqtt.publish as publish
# channel 0 pin1-GND
import spidev
from time import sleep

Vref = 3.29476
topic = "raspberrypi-2/ADC/ch0"
host = 'raspberrypi.local'

spi = spidev.SpiDev()
spi.open(0, 0) # port 0,cs 0
spi.max_speed_hz = 10000000 # 10MHz

try:
while 1:
adc = spi.xfer2([0x06, 0x00, 0x00])
data = ((adc[1] & 0x0f) << 8) | adc[2]
ch0 = round(Vref*data/4096,3)
#print(adc[1], adc[0], str(ch0) + "V")
publish.single(topic, str(ch0), hostname=host)
sleep(0.001)
except KeyboardInterrupt:
print('\n end')
spi.close()


(2020/05/09)4095は間違いなので、4096に変更した。下記のスケッチも修正したが、実行結果は変更していない

接続

 MCP3208とはSPIバス0で接続します。今までで使ったI2Cバスの接続はそのままです。

MCP3208信号名 ラズパイのGPIO  
チップ・セレクト/CS(/SS)10番 24番 CE0 Chip Enable
 Din 11番 19番 データ出力MOSI Master Out Slave In
 Dout 12番 21番 データ入力MISO Master In Slave Out
 CLK 13番 23番 クロックSCLK Serial CLocK
電源3.3V 16番 1番 3.3V  
GND 9番、14番 6番 GND  
Vref 基準電圧入力 15番 1番  

Node-REDでSubscriver

 購読はNode-REDで行います。dashboardのchartを利用して折れ線グラフを描きます。

 プログラムです。

[{"id":"dd830347.bb351","type":"tab","label":"フロー 3","disabled":false,"info":""},{"id":"313a489a.15c6d8","type":"mqtt in","z":"dd830347.bb351","name":"","topic":"raspberrypi-2/lm75b-1/temp","qos":"2","broker":"2f14cba6.10af64","x":200,"y":120,"wires":[["a4d04e9d.4ecaa","ea252f15.367c9"]]},{"id":"a4d04e9d.4ecaa","type":"debug","z":"dd830347.bb351","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":490,"y":140,"wires":[]},{"id":"ea252f15.367c9","type":"ui_gauge","z":"dd830347.bb351","name":"","group":"3a0a99de.c91af6","order":0,"width":0,"height":0,"gtype":"gage","title":"LM75B-1","label":"℃","format":"{{value}}","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":480,"y":200,"wires":[]},{"id":"a73fa80.3293b58","type":"mqtt in","z":"dd830347.bb351","name":"","topic":"raspberrypi-2/lm75b-2/temp","qos":"2","broker":"2f14cba6.10af64","x":200,"y":260,"wires":[["b7d564e3.f93e28","231b42f0.6246be"]]},{"id":"b7d564e3.f93e28","type":"debug","z":"dd830347.bb351","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":490,"y":300,"wires":[]},{"id":"231b42f0.6246be","type":"ui_gauge","z":"dd830347.bb351","name":"","group":"3a0a99de.c91af6","order":0,"width":0,"height":0,"gtype":"gage","title":"LM75B-2","label":"℃","format":"{{value}}","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":480,"y":360,"wires":[]},{"id":"58bad8d8.5de088","type":"mqtt in","z":"dd830347.bb351","name":"","topic":"raspberrypi-2/sht31-1/temp","qos":"2","broker":"2f14cba6.10af64","x":190,"y":400,"wires":[["731d5087.50f1e","39a8ebc7.a83ef4"]]},{"id":"731d5087.50f1e","type":"debug","z":"dd830347.bb351","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":490,"y":440,"wires":[]},{"id":"39a8ebc7.a83ef4","type":"ui_gauge","z":"dd830347.bb351","name":"","group":"3a0a99de.c91af6","order":0,"width":0,"height":0,"gtype":"gage","title":"SHT31-1","label":"℃","format":"{{value}}","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":480,"y":500,"wires":[]},{"id":"84723db5.76b63","type":"mqtt in","z":"dd830347.bb351","name":"","topic":"raspberrypi-2/sht31-1/RH","qos":"2","broker":"2f14cba6.10af64","x":190,"y":540,"wires":[["df4cdecd.22cad","3130a4d2.e8585c"]]},{"id":"df4cdecd.22cad","type":"debug","z":"dd830347.bb351","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":600,"wires":[]},{"id":"3130a4d2.e8585c","type":"ui_gauge","z":"dd830347.bb351","name":"","group":"dbbc7f88.4e765","order":0,"width":0,"height":0,"gtype":"wave","title":"SHT31-humidity","label":"%","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":600,"y":660,"wires":[]},{"id":"a0383c9f.29476","type":"mqtt in","z":"dd830347.bb351","name":"","topic":"raspberrypi-2/ADC/ch0","qos":"2","broker":"2f14cba6.10af64","x":160,"y":720,"wires":[["1f5adca0.552693","f7c877a1.3332f8"]]},{"id":"1f5adca0.552693","type":"debug","z":"dd830347.bb351","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":470,"y":760,"wires":[]},{"id":"f7c877a1.3332f8","type":"ui_chart","z":"dd830347.bb351","name":"","group":"63478a9b.685c34","order":0,"width":"0","height":"0","label":"ch0","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"3.3","removeOlder":1,"removeOlderPoints":"100","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":450,"y":860,"wires":[[],[]]},{"id":"2f14cba6.10af64","type":"mqtt-broker","z":"","name":"ラズパイ・ゼロ","broker":"raspberrypi.local","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"3a0a99de.c91af6","type":"ui_group","z":"","name":"温度センサ","tab":"26923c63.690754","order":2,"disp":true,"width":"6","collapse":false},{"id":"dbbc7f88.4e765","type":"ui_group","z":"","name":"湿度センサ","tab":"26923c63.690754","disp":true,"width":"6","collapse":false},{"id":"63478a9b.685c34","type":"ui_group","z":"","name":"アナログ入力","tab":"26923c63.690754","disp":true,"width":"6","collapse":false},{"id":"26923c63.690754","type":"ui_tab","z":"","name":"ラズパイ2","icon":"dashboard"}]

 Analog Discovery2の発振器から1Hz 2V0-pを出力し、MCP3208のch0入力につないでいます。

 実行中の様子です。右のチャートch0がどんどん更新されていきます。いびつですが、サイン波に見えます。

 時々、数秒更新が止まることがありますが、動きつづけています。8時間ほどたって、発行側が止まりました。Brokerは問題なく動いています。発行側は、ほかの原稿でプログラムを動かしていたので、それが原因で止まったのかもしれません。

波形の観測

 Analog Discovery2のオシロスコープで波形を観測します。SPIのクロックは10MHzです。MCP3208のクロックの上限は2MHzですが、追随しています。

 データ転送の1サイクルは約400kHzです。

 各測定サイクルが空いていて、12msとか15ms間隔です。publish.single(topic, str(ch0), hostname=host)の実行に制限されています。

(※)paho-mqttのドキュメント paho.mqtt.pythonのソース