温度センサーIC LM19を使う

ここでは温度センサーIC LM19(National Semiconductor)を使ってRaspberry piで温度監視を行う事例を紹介します。

LM19仕様

  • パッケージ:TO-92
  • 動作電源電圧:2.4V~5.5V
  • 使用温度範囲:-30℃~+130℃
  • 精度:±2.5(@30℃)

接続例

スクリーンショット 2014-01-21 4.24.02
LM19からの出力はアナログ電圧のためRaspberry piでは直接扱うことができません。そこで一旦I2Cインターフェイス基盤でアナログ電圧を読み取り、その結果をI2Cをとおして取得することにします。
ICのデータシートを参考に出力には抵抗とコンデンサをつないでいます。

Python script


import i2cinterface99
ii = i2cinterface99.i2cinterface99()
state,value = ii.analogRead(0) #read A0 Pin
if state == True:
 volt = value / 1023.0*3.3 #3.3V電圧でインターフェイス基盤を動作している場合のAD変換式
 temp = (1.8641 - volt)/0.0117 #ボルトから温度への変換の式
 print "%d deg/C" %(temp) #摂氏表示
else:
 print "I2C error"

温度への変換式はICのデータシートに記載されている−10℃〜65℃における推奨式を元にしています。
上記スクリプトをsudo python ファイル名.py で実行します。
温度センサーの値を読み取った結果がコンソールに表示されるはずです。
I2Cインターフェイス基盤にLCDを接続していれば、LCD上に温度の値が表示されるようにしてもよいでしょう。

今回行った実験では、LM19の測定値が温度湿度センサーDHT11による測定値とほぼ同じであることが確認できました。

Raspberry piにshut downボタンを付ける

Raspberry piを停止する際はコンソールからshut downを行う必要が有ります.

pi@raspberrypi ~ $sudo halt

Raspberry piの仕様から端末に繋ぐことなくスタンドアロンで運用することも多いと思います.本体をちょっと移動したいとき電源を一時的に外さなくてはならないとき、いきなり電源をオフにしてしまえばSDメモリーカードの破損、破壊の恐れが出てきます.安全に電源を落とすためには確実にShut downを行わなければなりません。

そこでイーサネット越しにリモートログインしてshut downを行っても良いのですが、Raspberry pi単体でもShut down出来ないものかと。そこでここではGPIOの一つにshut downスイッチを設け、それを常に監視し、スイッチが押されたらShut Downシーケンスに入るものとします。

スイッチにaitendoで見つけたシートキーを使います.キーが4つ有りますのでシャットダウン以外にもそれぞれ機能を持たせる事ができます。
CIMG2384
Python用GPIOインストールしているものとして進めます.
インポートしているacm1602は外付けのLCDキャラクターディスプレイを制御するものです。
GPIOピンの22〜25にシートキーをプルダウン抵抗を介して接続しておきます。
いかサンプルコードを紹介します.


import time
import acm1602
import datetime
import subprocess
import RPi.GPIO as GPIO

def pushRedButtonLong():
        lcd.cls()
        lcd.putString("Shut Down?",0)
        lcd.putString("Y)Green,N)YellowL",1)
        while 1:
                if GPIO.input(pin_yellowBtnL) == 1 or GPIO.input(pin_yellowBtnR) == 1:
                        lcd.cls()
                        lcd.putString("Cancell",0)#LCDにshut downをキャンセルした事を表示
                        time.sleep(1)
                        return
                if GPIO.input(pin_greenBtn) == 1:
                        lcd.cls()
                        lcd.putString("sudo halt",0)#LCDにshut down処理を行っている事を表示
                        ret = subprocess.check_output(["sudo","halt"]);#システムにshut downを指示する
                        exit()
def pushRedButtonShort():
        lcd.cls()
        lcd.putString("Red Button",0)
        time.sleep(1)
def pushYellowButtonLeft():
        lcd.cls()
        lcd.putString("Yellow L Button",0)
        time.sleep(1)
def pushYellowButtonRight():
        lcd.cls()
        lcd.putString("Yellow R Button",0)
        time.sleep(1)
def pushGreenButton():
        lcd.cls()
        lcd.putString("Green Button",0)
        time.sleep(1)


print "start"
GPIO.setmode(GPIO.BCM)
pin_redBtn=25
GPIO.setup(pin_redBtn,GPIO.IN)
pin_yellowBtnL=24
GPIO.setup(pin_yellowBtnL,GPIO.IN)
pin_yellowBtnR=23
GPIO.setup(pin_yellowBtnR,GPIO.IN)
pin_greenBtn=22
GPIO.setup(pin_greenBtn,GPIO.IN)

lcd = acm1602.acm1602()
lcd.set_cursor('off')
try:
        redPushCount=0
        while 1:
                time.sleep(0.1)

               if GPIO.input(pin_redBtn) == 1:
                        redPushCount += 1
                        if redPushCount > 30:# 3秒長押し検出
                                pushRedButtonLong()
                                redPushCount = 0
                elif redPushCount > 0:
                        pushRedButtonShort() #短押しの場合
                        redPushCount = 0
                if GPIO.input(pin_yellowBtnL) == 1:
                        pushYellowButtonLeft()
                if GPIO.input(pin_yellowBtnR)==1:
                        pushYellowButtonRight()
                if GPIO.input(pin_greenBtn) == 1:
                        pushGreenButton()
except KeyboardInterrupt:
        print 'user terminated'
        GPIO.cleanup()

ここでは赤ボタンを長押ししたら、Shut downするかCancellするかどうかがLCDに表示されます.そこで緑ボタンを押せばShut down処理を始めます。
その他のキーの長押しはそのキーの名称をLCDに表示します.
ここまでで赤ボタン長押しし、そのあと緑ボタンを始めればShutDown処理に移行するようになりました。このようにユーザーの確認をワンクッション置く事で、間違ってShut downするのを防ぐことができます.
ここですぐに電源を抜いてしまうと、Shut down処理の途中ではSDメモリーカードにアクセスしていますので、アクセス中の電源断は運が悪ければSDカードの破損、再起動不能になってしまいます.
アクセスランプが消灯している事を確認してから電源を抜くようにしても良いのですが、筐体によってはボード上のLEDが見えない場合もあります。そこで接続してあるLCDにShut Down処理が完了したことを表示する事にします.

Raspberry pi(Raspbian)ではシャットダウン時に行うスクリプトを書くことができます.
/etc/default/halt
を編集してください.

# Default behaviour of shutdown -h / halt. Set to "halt" or "poweroff".
HALT=poweroff
/home/pi/shutDownLCD.py
/etc/default/halt

ここでは上のようにしました。ユーザーディレクトリに”shutDownLCD.py”というスクリプトを置いてます.これは単純にLCDに”Shut down”しましたよ〜という表示を行うだけのものです.LCDに表示する代わりに終了の音楽をならしても良いしLEDを明滅しても良いですし、ご自身の環境や趣味に合わせてスクリプトを用意してください.
厳密には電源を落としても大丈夫な状態になるのはここで指定したスクリプトが終わってからひと呼吸おいた後になるのですが、電源断のある程度の目安になる事でしょう.

今回は外部表示装置としてLCDキャラクターディスプレイACM1602を使いました。I2CインターフェイスをもつこのLCDはRaspberry piと接続したところ、ちょっと使いこなしが難しい点も幾つか見つかりました。(詳細は別記事にて)
I2Cインターフェイス基板LCD付きを使えばもっと簡単にLCDを制御できる事でしょう。

動体検出にPIRセンサーを

動体検出には幾つかの方法が有ります。まずカメラ画像の中から動いている物体を検出するものがあります。これは人でも車でもカメラが見ることのできる動いているものを検出します.カメラの性能にも依存しますので例えば暗い時のようにカメラの映像にノイズが入ってしまう場合にはご検出を頻繁に起こしてしまうでしょう。

赤外線の変化を検出して動体検出とするものが有り、これが焦電センサーまたはPIRセンサーで行うことができます。防犯ライトなどにも多く使われている一般的なセンサーです.人間や動物など熱を持つ物体は赤外線を放出しており、その赤外線をセンサーが検出します.赤外線の検出値に変化が有れば何らかの物体が動いたという事でセンサーからの出力を行います.カメラのように画像によることがありませんので暗闇でも検出することができます.一方風なども物体と捉える事が出来るため、風の強い日はその赤外線の変化さえも検出してしまいます.

ここでは安価に入手できるPIRセンサーを紹介します.
CIMG2383
PIR センサー A708-1H
AITENDOで購入
仕様概要:動作電圧0.8-8v、 出力電圧 h:3.3 l:0v、 検出距離5-7m
参考にRaspberry piで接続する場合の例を紹介します.
必要な回路部品はすべてセンサーモジュールに実装されています.接続はPIRの出力をRaspberry piのいずれかのGPIOにつなげるだけです.

スクリーンショット 2013-12-15 13.06.30
あえて書くまでもないかもしれませんが、一応サンプルコードを紹介します.
PythonのGPIOはインストールしている前提です.


#!/usr/bin/python3
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
io_pin=17
GPIO.setup(io_pin,GPIO.IN)
while True:
        gp17=GPIO.input(io_pin)
        if gp17 == 1:
                print ("Move!");
        else:
                print("No move");
        time.sleep(1)

電源電圧が3.3VであるRaspberry piはGPIOの入力電圧も電源電圧を超えないものとしなければなりません。このPIRセンサーの出力は3.3Vという事でそのまま接続できますので大変便利ですね。

IOError: [Errno 5] Input/output error

Raspberry piでデバイスとI2C通信をしている時に
IOError: [Errno 5] Input/output error
に出会う時が有ります.基本的な設定が済んでいるものとして、このようなエラーが出る場合はいくつかの原因が考えられます。

1)信号線が長い、ノイズの影響を受けているなどで、信号そのものの波形が劣化している場合

 この場合は具体的にはオシロスコープを使って波形を確認した方が良いでしょう。オシロスコープが無い場合は信号線を出来るだけ短くすること、プルアップ抵抗が適切なものが入っているか確認する事と通信スピードを落としてみるのも有効です。

2)相手が準備できていないのにコマンドを送っている、データをリクエストしている場合
 コマンドを送る前にWaitを入れることになります.デバイスによってはコマンドを受け付けた後にいくら処理に時間がかかってそのあとにリクエストを受け付けると言ったシーケンスを明記しているものも有ります。詳しくはそれぞれのデバイスのリファレンスを参照の上で最適化するようにします。

3)初期化シーケンスをコマンド送信ごとに送ってしまっている
 本来であればSPI通信を始める場合の初期化処理は一度で良いのですが、スクリプトになっていとそれを外から呼び出した時に何度も短い間隔で呼び出して気づかない事も有ります。初期化は誰がやっているか、どのタイミングでやっているか確認し、スクリプトの最適化を行います.

シリアルインタフェイス I2CとSPIの選択

センサーや表示装置などのデバイスモジュールは多くの種類があり小型になり、また手頃な価格で入手できるようになりました。これらをマイコンまたはRaspberry piなどの小型Linux機で扱うのに容易なシリアルインターフェイスで制御できるものも多く有ります.

シリアルインターフェイスにはUART,I2C,SPI,Single wireなどがあります。UARTは主に一対一の通信に用いられます.Raspberry piでRaspbianをOSとして使っている場合はこのUARTはシリアルコンソール用と割り当てられています。
SPI通信ではマスターとスレーブを定義し、一つのマスターに対して複数のスレーブを持つことができます.スレーブの切り替えはSS(Slave select、CS:chip select, CE:Chip enableとも呼ばれる)信号で行います.Raspberry piには二つのCE信号線が有ります。
I2C通信では二つの信号線、データ線SDAとクロック線SCLによって通信します。(この他にモジュールはVccとGNDも接続します )SPIではMOSI,MISO,SCLK,SSの信号線が必要だったのと比較して信号線が少なくて済みますね。I2Cも複数のモジュールをスレーブとしてつなげることができます.同時に複数のデバイスをつなげた場合はそれそののデバイスが持つアドレスによってデータのやり取りの相手を指定します.同じバスで使うデバイスの持つアドレスが競合しないように気をつけなければなりませんが、標準の7ビットアドレスモードで使う場合は最大で112個のデバイスを扱うことができるのです.

センサーモジュールによっては同じ機能のものでもI2C用とSPI用と2種類有るものや、一つのモデルで設定でI2CとSPIを切り替えられるものも有ります.またI2CのみまたはSPIのみに対応しているデバイスもあります。

自分が実現したい仕様に対して、用いるデバイスがどちらのインターフェイスを持っているか、それと制御するマイコンまたはLinuxボードのインターフェイスの制約条件とを勘案してよりベターな組み合わせを模索する必要が有ります