サバフェス2016の課題をコリコリといじっております。いなばです。
会場でセンサーとしてTSL2561という照度センサーを頂いているので、これを使ったものを作りたいわけですが、ちょっとハマったところもあるので、メモがてらまとめておこうと思います。
TSL2561をラズパイ2につなぐ
まずはこれ。
Fritzing のパーツ画像がないので後で時間のあるときにでも作ってみますが、文字ベースで言うなら、
- ラズパイの1番からTSL2561の3vo
- ラズパイの3番からTSL2561のSDA
- ラズパイの5番からTSL2561のSLC
- ラズパイの6番からTSL2561のGND
にそれぞれ配線してあげればいいみたいです。
I2C関係
TSL2561とラズパイ2はI2Cという方法で接続します。I2Cについては、Wikipediaの説明をざっと見てみましたが、要するに複数のセンサーを繋いだりするときに簡単にできるやり方、というくらいの理解で良さそうです。
ラズパイ2でI2Cを使うにはいくつか準備が必要です。
ラズパイ2 本体の設定
「本体」という表現も語弊がありますが、要はラズパイのカーネルで、I2Cを有効にしてあげないと使えません。
色々方法はあるようですが、ここではターミナルで
sudo raspi-config
を実行し、「9 Advanced Options」から「A7 I2C」を選択してやるのが一番簡単そうです。
上記を実行したあと、再起動が必要なので、
sudo reboot
します。
再起動後、
lsmod
してやると、以下のように出力が出ると思います。
Module Size Used by cfg80211 407580 0 rfkill 16036 2 cfg80211 8192cu 519604 0 bcm2835_rng 1763 0 snd_bcm2835 19802 3 i2c_bcm2708 4920 0 snd_pcm 73474 1 snd_bcm2835 bcm2835_gpiomem 2860 0 snd_timer 18848 1 snd_pcm snd 50779 9 snd_bcm2835,snd_timer,snd_pcm uio_pdrv_genirq 2944 0 uio 7753 1 uio_pdrv_genirq i2c_dev 5671 0 fuse 80694 3 ipv6 338660 36
細かい出力は違うかもしれませんが、i2c_bcm2708とi2c_devが見えていれば良いようです。
接続と動作の基本的な確認
上記で一応カーネルモジュールが読み込まれたところまでは分かるのですが、やはり念のため通信して確認してみたいところです。
てことで、i2c-toolsというパッケージをインストールし、i2cdetectというコマンドで確認します。
sudo apt-get install i2c-tools sudo i2cdetect -y 1
出力はこんな感じになると思います。
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
こんな感じで、39番が見えていれば良いと思います。
Pythonから照度をとる
2016/3/21追記
一つ書き忘れていました。PythonからI2Cデバイスを使うにあたり、
sudo apt-get install python-smbus
が必要です。
2016/3/21追記ここまで
ここでちょっとハマりました。後述するように、TSL2561 からデータを取るための実装は複数あるようで、実装によって精度というかクセが異なるようです。
当初は、
でも紹介されている
を使ってみたのですが、どうもこちらではなかなかうまく行きませんでした。
上記のスクリプト(に手を加えたもの)で、連続して値を取ることはできるのですが、急激に明るさが変わるとそこからデータが不安定になるようで、例えば動作中に部屋の明かりを消す、であるとか、強い照明を当てる、といった刺激を与えると、その後、同じ明るさの状態に戻しても取得できる照度が異なったりしていました。
で、その辺りについても触れている
を参考にしてみたところ、うまい具合に行きました。
具体例は上記のサイトで公開されているとおりですが、念のためこちらにも手順を貼っておきます。
まず、
にあるものを使うので、zipファイルをwgetで入手しておきます。
wget https://github.com/janheise/TSL2561/archive/master.zip
次に、入手したzipファイルを展開します。
unzip master.zip
展開したディレクトリに移動して実行してみると…
cd TSL2561-master ./TSL2561.py
以下のように、quick2wireがない、と怒られます。
Traceback (most recent call last): File "./TSL2561.py", line 3, in <module> import quick2wire.i2c as i2c ImportError: No module named 'quick2wire'
ざっと調べてみたところ、quick2wire はI2Cデバイスをラズパイ上のPythonから扱うためのライブラリのようです。
で、さっそくquick2wireをインストールしてみます。
git clone https://github.com/quick2wire/quick2wire-python-api.git cd quick2wire-python-api/ sudo python3 setup.py install
これでOKです。参考にしたサイトでは、quick2wireのインストール時にsetup-toolsというパッケージのインストールが必要だったようですが、2016年3月時点の環境では不要でした。
さて、改めて先ほどのスクリプトを実行してみますが…
./TSL2561.py
今度は別の内容で怒られます。どうやら、/dev/i2c-0 がない、と怒っているようです。
Traceback (most recent call last): File "./TSL2561.py", line 300, in <module> with i2c.I2CMaster(0) as bus: File "/usr/local/lib/python3.4/dist-packages/quick2wire_api-0.0.0.2-py3.4.egg/quick2wire/i2c.py", line 48, in __init__ FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-0'
この問題についても、参考にしたサイトに記載されていたので恐れるに足らず、ということで、同じようにシンボリックリンクを張って対応してみます。
sudo ln -s /dev/i2c-1 /dev/i2c-0
3/21追記
上記の方法で作成したシンボリックリンクは、何故か再起動すると消えちゃってました。
なので、/etc/rc.local に上記のコマンドを記述しておいたところうまいこといっているようです。
3/21追記ここまで
さて、三度目の正直ということで、改めて実行してみます。
./TSL2561.py
お、なんかイイ感じに出力されてます。
0a b6 00 39 04 Full: 0439 Infrared: 00b6 Visible: 0383
念のため、上記のスクリプトを連続して呼んでみましたが、出力は安定しています。
この実装が大丈夫そうなことは確認できたので、同梱されているTSL2561.example.pyも試してみます。
./TSL2561.example.py
出力はこんな感じになります。
0a 79 00 98 03 Full: 0398 Infrared: 0079 Visible: 031f 0a Found sensor... Full luminosity value: 1048699 Full luminosity value: 0x10007b IR: 10 Full: 7a Visible: 0x6b Visible, calculated: 0x6a Lux: 1526
先ほどの出力結果と似ていますが、最後にLuxという形で照度らしきデータが数値化されているのがイイ感じです。
今回私が作ろうとしている課題では、明るさのデータを連続して取得できればいいので、TSL2561.example.pyを適当な名前のファイルにコピーしたうえで、以下のように編集してみました。
#!/usr/bin/env python3
from TSL2561 import *
import time
tsl = TSL2561()
if tsl.foundSensor():
#print("Found sensor...")
while 1:
tsl.setGain(tsl.GAIN_16X);
tsl.setTiming(tsl.INTEGRATIONTIME_13MS)
x = tsl.getFullLuminosity()
#print("Full luminosity value: %d" % x)
#print("Full luminosity value: %#08x" % x)
full = tsl.getLuminosity(tsl.FULLSPECTRUM)
visible = tsl.getLuminosity(tsl.VISIBLE)
infrared = tsl.getLuminosity(tsl.INFRARED)
#print("IR: %x" % infrared)
#print("Full: %x" % full )
#print("Visible: %#x" % visible )
#print("Visible, calculated: %#x" % (full - infrared) )
print("Lux: %d" % tsl.calculateLux(full, infrared) )
time.sleep(1.0)
else:
print("No sensor?")
クラス自体がデバッグ的にいくつか文字列を出力してしまいますが、とりあえずこれは後で対処するとして、出力はこんな感じになります。実行中の環境としては、最初の5秒は部屋の中の普通の灯りで、次の5秒は手でセンサー部分を軽く覆っています。その後、覆っていた手をどけて5秒後に、iPhoneのLEDでセンサー部分を照らしています。
0a 7b 00 ab 03 Full: 03ab Infrared: 007b Visible: 0330 0a Lux: 1571 Lux: 1566 Lux: 1566 Lux: 1551 Lux: 1566 Lux: 202 Lux: 156 Lux: 156 Lux: 156 Lux: 156 Lux: 1556 Lux: 1551 Lux: 1571 Lux: 1571 Lux: 1551 Lux: 13147 Lux: 15072 Lux: 15977 Lux: 16522 Lux: 16008 Lux: 1571 Lux: 1535 Lux: 1571 Lux: 1556 Lux: 1556
通常時が1500ルクス強、というのは、例えばこちらなどを参照すると、かなり明るすぎるのですが、私の自室がそんなに明るすぎる気はしていないので、照度センサが明るい方向に取りすぎているような気はします。ですが、今回の私の使い方では、明るさの変化さえ取れればいいので、その観点では、上記の出力は、明るい状態→暗い状態→明るい状態→すごく明るい状態→明るい状態ときちんと数字が推移しており、かなり安定しているように思えます。
ひとまず、ラズパイで明るさを取得する、ということについては、これで良いことにしようと思います。
コメント