前の記事
カメラモジュールから画像を取得して任意のディレクトリに保存するまでを上記の記事で進めました。
目標
- 防水の温度計を使用して水温を取得できるようになること。
- 取得した値を読みやすいようにPythonで整形できるようになること。
必要なもの
Raspberry Pi
もちろんこれが必要。Zero Wを使用。
Raspberry Pi Zero W - ヘッダー ハンダ付け済み - ラズベリー・パイ ゼロ W ワイヤレス
- 出版社/メーカー: Raspberry Pi
- メディア: エレクトロニクス
- この商品を含むブログを見る
防水温度センサ (DS18B20)
水温を取得するために必要。
WINGONEER防水デジタルサーマルプローブまたはセンサーDS18B20
- 出版社/メーカー: WINGONEER
- メディア: Camera
- この商品を含むブログを見る
防水で無いもので同名のセンサもあります。(三脚のちっさいやつ)
今回は水槽内にほりこむ必要があるのでこのタイプを使用します。
線の色 | 役割 |
---|---|
赤 | VCC |
黄/白 | データ |
黒 | GND |
のようです。
ほかの各センサをオンラインで購入したい場合や、防水ではなくより小型のDS1820を購入するには、アールエスコンポーネンツのECサイトが便利です。検索時にIFが1Wire
やI2C
、実装方法に表面実装
またはTH実装
等、自分の開発環境に合わせたセンサを絞り込むことが簡単にできるので使いやすいです。
アールエスコンポーネンツはRaspberry Piの日本正規総代理店でもありますのでRaspberry Piを使っている人にはおなじみの企業で安心ですね。
ほか電子工作部品
- 半田こて一式
- ブレッドボード
- 抵抗1つ (4.7kΩ)
- リード線
を使用します。
DS18B20のデータシート上では4.7kΩの抵抗器が必要なようですが、手元になかったので5.1kΩ で作成しました。値はちゃんと取得できています。
こんな感じのセットになっている商品がお手軽に部品を集めることができます。
ELEGOO Electronic Fun キット Arduino用電子LearningキットE2
- 出版社/メーカー: ELEGOO
- メディア:
- この商品を含むブログを見る
LEDとかボタンもついているのでLチカとかも試せますね。
作業
温度センサの下準備
温度センサから出ている3本の線の皮膜を剥がし、中の銅線を露出させます。
皮膜を剥がすようの専用のニッパーのようなものもあるのですが、ハサミや普通のニッパーで丁寧にグルリと切り込みを入れてやれば、爪で千切ることもできます。
あまり力を入れすぎると中の銅線も一緒にちぎってしまいます。私は黒線でコレをやってしまいました(笑)
中には極細の銅線が数十本あります。ここにジャンパワイヤをはんだ付けしてブレッドボードに差し込めるようにします。そのままでは柔らかすぎて刺さりませんでした。
はんだ付けした部分にはビニールテープなんかで巻いておきましょう。
1-Wireを有効にする
DS18B20を使用するには、1-Wire
という規格のインターフェースを有効にする必要があります。
sudo raspi-config
を実行して、Interfacing Options > 1-Wire > Yes
で有効にできます。
実際には/boot/config.txt
に以下の一行が追加されます。
dtoverlay=w1-gpio
作業を進めていて気づいたのですが、さらにもうちょっと値を追加する必要があります。
sudo vim /boot/config.txt
で開いて以下のようにしてください。
dtoverlay=w1-gpio,pullup=on
pullup=on
によってプルアップ電圧を設定するというカンジでしょうか...
プルアップ電圧とは下記参考によると、特殊な処理を行うときに通常の電力よりも多くの電力を使用する、そんなときに必要となる電圧のようです。
(from: https://www.maximintegrated.com/jp/app-notes/index.mvp/id/4255)
書き込み終わったらRaspiを再起動させましょう。
配線
Fritzingというサービスを利用して回路を書いてみました。防水用のDS18B20のイメージがあれば良かったのですがありませんでした。
配線の色でそれぞれの線をどこに挿せばいいか確認してください。デフォルトではデータはGPIO4番のピンから受け取ることができるようです。
抵抗に関して、公式データシートや他の方の記事でも4.7kΩのものが使用されていましたが、手元になく5.1kΩのものを使用しました。
特に問題なく計れているようですが、もしかすると数値に若干狂いがあるかもしれません。
値を取得
それでは値を取得していきます。温度センサー本体にLEDとかついていなのでちゃんと動いてるかどうか心配ですね...(笑)
ちゃんと回路ができていて、値を取得できる状態にある場合、
以下の場所に28-
で始まるディレクトリが現れます。
表示されない場合は、config.txt
の内容と配線が正しいかどうか確認してみてください。
$ cd /sys/bus/w1/devices/ $ ls -la total 0 drwxr-xr-x 2 root root 0 May 5 02:09 . drwxr-xr-x 4 root root 0 May 5 02:09 .. lrwxrwxrwx 1 root root 0 May 5 02:10 28-0517c41aecff -> ../../../devices/w1_bus_master1/28-0517c41aecff lrwxrwxrwx 1 root root 0 May 5 02:09 w1_bus_master1 -> ../../../devices/w1_bus_master1
このディレクトリ名はセンサーに個別に振られている値のようで、再起動後や回路の再構築後にも同じディレクトリ名が現れます。
また複数個の同じセンサーをつなげても、このディレクトリ名で判別可能となるようです。
pythonなどの処理でディレクトリを決め打ちできるのでありがたい!
このディレクトリ内にあるw1_slave
というファイルにセンサーの取得した温度が格納されています。
$ cd 28-0517c41aecff $ cat w1_slave 50 05 4b 46 7f ff 0c 10 1c : crc=1c YES 50 05 4b 46 7f ff 0c 10 1c t=85000
t=85000
の値を1/1000したものが温度(℃)となります。
t=0となっている場合、温度センサーを指なんかで温めると反応し始める事があります。それでもダメな場合は回路を見直してみてください。
特に黄色のデータ線が正しく配線できているか確認してください。
t=85000?
。。。しかし85℃はおかしい(笑)指で温めても常に85℃となります(´・ω・`)
ダメ元で調べてみると、、ありました!!
要約すると、config.txtにpullup=onを追加すると大丈夫なようです!上の方にすでに追加したあの値ですね。
他にもRaspi側の電源供給のPINを変更したら治っただとかいろいろな情報が出てきました。詰まったときは検索すると意外とどうにでもなるもんです。
修正後の値取得
再度値を取得してみると...
$ cat w1_slave 9e 01 4b 46 7f ff 0c 10 8a : crc=8a YES 9e 01 4b 46 7f ff 0c 10 8a t=25875
ちゃんとそれっぽい温度(25.8℃)で取得できました!ちなみにこの値はすでに水槽の中にほりこんだ時の値です。
アナログな水温計は25℃付近を指していたので、よりヒーターの近い方に投げ込んだので概ね正しい値が取得できていそうです。
コリドラスたちが興味津々に近づいてきたので水面からちょっと浮かせて設置したほうが良さそうですね。あまりもふもふされると体に悪そう。。orz
この形...もしかして
温度センサーでこの形と来たらまさに体温計ですね(笑)
興味がてら体温も測ってみました(脇下で2分)
$ cat w1_slave 34 02 4b 46 7f ff 0c 10 5b : crc=5b YES 34 02 4b 46 7f ff 0c 10 5b t=35250
うーん、、どう頑張っても36℃を超えることはありませんでした(笑)
値をPythonで取得
Linux上のコマンドで値を取得することはできたので、今度はプログラムの中でも取得できるようにしましょう。
今回のスマート水槽構築に際しては、Pythonを使うという縛りで進めているのでいつものPHPは無しです。 DBに値を突っ込んでしまえば言語は関係ないですからね(゚∀゚)
こんな感じでコード書いてみました。ファイル名はget_water_temp.py
としました。
import sys import subprocess ### 定数 SENSOR_ID = "センサーのディレクトリ名(28-で始まるやつ)" SENSOR_W1_SLAVE = "/sys/bus/w1/devices/" + SENSOR_ID + "/w1_slave" ERR_VAL = 85000 def main(): res = get_water_temp() if res is not None: temp_val = res.split("=") if temp_val[-1] == ERR_VAL: print "Got value:85000. Circuit is ok, but something wrong happens..." sys.exit(1) temp_val = round(float(temp_val[-1]) / 1000, 1) print temp_val else: print "cannot read the value." sys.exit(1) def get_water_temp(): try: res = subprocess.check_output(["cat", SENSOR_W1_SLAVE]) return res except: return None if __name__ == "__main__": main()
エラー処理等かなり適当です。いい感じにブラッシュアップしてあげてください。
cat w1_slave
で取得した生データを=
で分割・配列に格納します。生データ内には=
は一つだけある(t=85000
)の部分だけなので、
いい感じに温度の値の部分だけを配列に格納できます。
pythonでは配列に格納されている値を後ろから取得することができます。val[-1]
と負数を指定すると後ろから取得できます。
-1
は最後尾に格納されている値を取得できます。
cat w1_slave
で生の値を取得できない時
(ディレクトリが存在しない(=回路が以上でセンサーを認識できない)時)- 取得できる値が
85000
の時
にエラーを出力します。
0
が取得できるときはエラーとはしていません。水温が0度になる可能性もなきにしもあらずなのですが、
いずれDB処理を追加するときに上記のエラーと合わせて有効フラグをfalseにする的な処理にします。
これでpython get_water_temp.py
をすると、小数部1桁(2桁目をround)した摂氏温度を取得できます。
$ python get_water_temp.py 23.3
以上で温度計が使えるようになりましたね!
最後に
プログラム内で値を取得することができるようになれば、データベースに格納してグラフ等を作成したり、 温度がある一定ラインを下回ったときに通知を飛ばす事ができるようになります。
この情報を使って水冷用のファンを回すとかやってみようと思います。