WICの中から

機構設計者が株式投資や育児に奮闘するblog

Raspberry Pi(ラズパイ)で温度測定してログを取ってみる

ちょっぴり多めに自分の時間が出来たのでラズパイを弄ってました。

やろうとしていたのは表題の通り温度測定です。モチベーションとしてはケーブルボックス内の温度計測です。嫁さんに言われて雑多なケーブルを下記のようにつっこんだんですが、電源系のアダプタがぎゅうぎゅうに詰め込まれているのは何となく怖くて。。。全て使用している時にどのくらい発熱するのか見ておこうかなーと思った次第です。

f:id:temcee:20170205213320j:plain

エントリーキットで部品をまとめて購入

モチベーションの話はこんな所にして、ラズパイでの温度測定です。

僕は電子工作の経験が無く、センサ類はもちろんジャンパー線もブレッドボードも持っていませんでした。そんなわけで手っ取り早くまとめて売っているものは無いかと探した所にエントリーキットに辿り着き、これ幸いと購入を決めました。

各種センサにジャンパー線やブレッドボードに抵抗、一通り揃っていていいですね。

「SPIインターフェースを使って温度・光を測ろう!」という一文が購買欲を刺激します。SPIインターフェースが何なのかよく分かりませんが、A/Dコンバータがそれを利用したものらしいです。

実際に組み立ててみると…線が足りない

キット内には説明書は付属されておらず、続きはWebで!といった案配です。

テックシェアストア(TechShareStore)

ここの「5.3温度を測ろう」というページにアクセスすると、早速回路図と配線図が表示されます。ガチ初心者の僕としてはそれぞれのパーツの役割だったり回路の考え方なりの解説が欲しい所ですが、分からない所は自分で調べるのがインターネッツで生きていくためのお作法です。とりあえず動いてからGoogle先生に聞いて理解するか、というスタンスでブレッドボードにブスブス刺していきます。

そうこうしていくうちに問題が起きました。

f:id:temcee:20170205213327j:plain

 ジャンパー線のオスーメスが足りない……?

配線図を見てみるとRaspberry PiのGPIOからは線が12本伸びていますが、キットの内容は10本だけです。もしかしてキットのお値段をケチってスタンダードではなくエコノミーを買ってしまった事が原因でしょうか…。

f:id:temcee:20170205213338p:plain

左はエコノミー、右がスタンダード。違いはサーボモータの取り付け用ICとUSBケーブルのみ、ということで普通にジャンパー線が足りない仕様なんですかね…?

どこかで線を揃えて…あれ、いらない?

とりあえず時間も時間なので本日はここでいったん中断となりました。続きはジャンパー線をネットなりアキバなりで揃えてから再挑戦か…、と思いましたが回路図を見る限りサーボモータとかブザーとか役割がよく分からないものがついてることに気がつきました。温度測定に関わりがありそうな所とは完全に独立しているように見えます。あれ、MCP3008とMCP9700の所だけあればいい感じそうじゃないですか。もしかして他の章で組んだものが残ってるだけだったり?

うーん、やりたい所だけいきなり試すのではなくて、きちんと順を追ってやった方が良かったかもしれません。まずはここで一度切り上げて時間がある時にちょこちょこページを読み込んでみます。部品の役割もきちっとさらっておきたいですしね。時間がある時にちょこちょこやっていきましょう。

(170207更新)回路簡素化とプログラムコピペ

f:id:temcee:20170207225643p:plain

赤枠の所だけ抜粋して組んでみました。ざっと見た感じ温度の測定だけならこれで問題ないでしょう。

f:id:temcee:20170207225749j:plain

ジャンパー線も減ってスッキリ!(ぐちゃぐちゃ)

回路が出来たら次はプログラムです。

僕はハード設計なのでプログラミングはさっぱりですが、サンプルプログラムが提示されていたのでそれとなくコピペさせてもらいます。コメントをつけてくれているので何となくやってることは分かります。

Raspberry Piを起動し、ターミナルで"nano rpi_bp_adc_ic1.py"を実行します。

nanoエディタが立ち上がるので下記コードをうちこんでいきます。

#!/usr/bin/env python

import spidev
import time

spi=spidev.SpiDev() # genarate spi instance
spi.open(0,0) # select ADC/MCP3008 : bus=0, CE=0

channel=0 # select CH0 : ADC/MCP3008

for i in range(10):

 buf = spi.xfer2([1,((8+channel)<<4),0]) # read adc data
 adResult = ((buf[1]&3)<<8)+buf[2] # select data
 volt= adResult * 3.3 / 1023.0 # converte data to Voltage
 print(volt)

 temp = (volt*1000.0 - 500.0)/10.0 # convertr volt to temp
 print(temp)

 time.sleep(1)
spi.close()
print ("ADC ic1 done")

"Ctrl+X"でエディタを終了し、続いて"y"で保存です。 

よーしできた!とここで一つ注意をば。

f:id:temcee:20170207231829p:plain

ConfigurationでSPIを有効にするのを忘れてはいけません。僕はこれで詰まりました。

(170207更新)無事に温度の取得に成功

SPIは有効にしました、回路も出来ました、プログラムもばっちりです。早速実行してみましょう。

"sudo rpi_bp_adc_ic1.py"をターミナルで実行します。すると…

f:id:temcee:20170218221217p:plain

一秒毎に電圧と温度を返してくれます。温度が高めなのはMCP9700を指で摘んで温度の変化を確認しているからで、きちんと温度上昇を反映してくれていることが確認できます。

温度を測定する、単純な事ですが自分でやったものがきちんと動いてくれると嬉しいです。次はこの温度のログを取ったり、スマホとかで監視できるように嬉しいかな。まだまだ調べる事は多そうです。 

(170307更新)温度ログを取ってtsvファイルで出力

ログを取ろうと思い、pythonのコーディングを調べるのではなく「誰か同じようなセンサーで同じようなことやってないかなー」と気軽に調べたところ、同じようなセンサーで同じような事をやっている記事を発見しました。

windvoice.hatenablog.jp

ありがたくコピペさせていただきます。コメントがきちんと書いてあって、何をやっているか分かりやすいです。僕は明度を測らないので、明度関係のところは削除しています。

#!/usr/bin/env python
# coding:utf-8

import spidev
import time
from collections import deque
import signal
import sys
import RPi.GPIO as GPIO
from datetime import date
from datetime import datetime

# センサーがつながっているMCP3008のチャネル
temp_channel  = 0

# キューに保存するデータの最大数
max_data = 60

# SPIバスへのアクセスを開く
spi=spidev.SpiDev()
spi.open(0,0)

def ReadChannel(channel):
  """
  MCP3008経由でアナログセンサからのデータを受け取る。
  channelはMCP3008の入力チャンネルで、0から7の値
  """
  adc = spi.xfer2([1,(8+channel)<<4,0])
  data = ((adc[1]&3) << 8) + adc[2]
  return data

def ConvertVolts(data, places):
  """
  MCP3008から受け取ったデジタルデータを、アナログセンサの
  出力電圧に変換する計算をする。placesは有効桁数
  """
  volts = (data * 3.3) / float(1023)
  volts = round(volts, places)
  return volts

def ConvertTemp(volts, places):
  """
  電圧をセンサーが検知した温度に変換する。
  """
  temp = ( 100 * volts ) - 50.0
  temp = round( temp, places )
  return temp
def exit_handler(signal, frame):
  """
  Ctrl+Cが押されたときにデバイスを初期状態に戻して終了する。
  """
  print("\nExit")
  spi.close()
  GPIO.cleanup()
  sys.exit(0)

#
# メインルーチン
#

# 終了時に処理するシグナルハンドラを準備
signal.signal(signal.SIGINT, exit_handler)

# データ保管用のキューを用意
queue = deque()

# ログファイルの用意
tsvfile = open('data'+datetime.now().strftime("%Y%m%d_%H%M%S")+'.tsv', 'a')
#tsvfile = open('data.tsv', 'a')
data_count = 0

while True:
  
  # 温度センサーを読む
  temp = ConvertTemp( ConvertVolts( ReadChannel( temp_channel ), 4), 4)

  # 平均値を出すためにデータを保存しておく
  # 一定の数データが溜まったら、古い物から削除
  queue.append(temp)
  if len(queue) > max_data:
    queue.popleft()

  # 平均値を求める
  sum1 = 0.0
  for d in queue:
        sum1 += d
  ave_temp = sum1 / len(queue)

  # コンソールへ結果を表示
  print "(温度)=(%6.2f) 平均 = (%6.2f)" % (temp, ave_temp)
  time.sleep(1)
  # 一定の回数ごとに平均値を記録
  data_count += 1
  if data_count == max_data:
    d = datetime.now()
    tsvfile.write("%s\t%6.2f\n" % (datetime.now().strftime("\"%Y/%m/%d %H:%M:%S\""), ave_temp))
    tsvfile.flush()
    data_count = 0

 早速ケーブルボックスの中に入れて実行してみましょう。

f:id:temcee:20170307000318j:plain

凄くざっくり入れてみた図。

f:id:temcee:20170307000545p:plain

お、ちゃんと走ってるみたいですね。せっかくなのでMacやスマホなどを全て充電している状態で、どう変化していくかも確認しました。時間の都合30秒だけですが、グラフ化したのが下記のものです。

f:id:temcee:20170307000548p:plain

開始直後は僕が触った直後だった影響があって高いので、デフォルト室温は20度弱くらいです。そこから、機器の充電を開始する事で徐々に温度が上がっている様子が見て取れます。これは雰囲気温度になるので、ある程度常識的な温度でサチっちゃうと思われますが、僕が懸念している温度はこの箱の中の最高温度です。恐らくMacのアダプタじゃ無いかと思うんですが、この温度を取るにはセンサを密着させる必要があります。いまのセンサはブレッドボードに直指しで自由に配置できないので、ちょっと厳しいかなー。熱電対があれば良いんですが。もしくは、温度が高くなると思われる所からヒートパイプで熱を引いてくるか…まだまだ試す事は尽きません。

こんな記事も書いています。

 

temcee.hatenablog.com

 セットアップとMacからのリモート設定の記事です。

ちなみに今回は回路組んでる最中にギブしたので、リモートの出番は未だです。