※なにか気になる点がありましたらコメント欄からお伝えください。また、回路を製作する場合には電源を切るなど、注意を払って行うようお願いいたします。
もくじ
1.はじめに
カラーセンサの値をラズベリーパイPico(以下Pico と記述) にて読み取り、thonny のシェルに表示してみたので、備忘録として書きとどておこうと思います。
カラーセンサからの値はPicoより I2C通信により読み取っています。また、カラーセンサとのデータの処理を行う部分を、ライブラリとして管理しました。あくまで自分用です。
参考資料
ラズベリーパイPico:
www.raspberrypi.org
秋月電子通商
※このHPの検索欄にて、カラーセンサ「S11059-02DT」あるいは通販コード「K-08316」と入力すれば、カラーセンサの情報を得ることができます。
(2023/10/03 変更:秋月電子通商の意向により)
akizukidenshi.com
2.構成
全体構成図を図1に示します。カラーセンサーからはI2Cにより、Pico側にデータを送っています。そのため、カラーセンサーの SDA と SCL の端子には2.2KΩのプルアップ抵抗を接続してあります。あと電源(2.25~3.63V、ここでは3.3V)とグランドも接続してあります。
Pico側はmicroUSB を接続すると電源が供給されます。(プログラミングしながらだとUSBに接続しなければならないし、単体で動かすことまでは考えていないので、電源はUSBより取っています)
カラーセンサーからのSDA と SCL の信号線は、それぞれPico の1番ピン(GP0)と2番ピン(GP1)に接続します。最後にカラーセンサーへの電源を供給するため、Pico 側の36番ピンより 3.3vをブレッドボードのプラス側に、GND(全部で8本ある)をブレッドボードのGND側へ接続しています。(GNDが多いほうが動作が安定すると思います)念のため、0.1μFの積層セラミックコンデンサを、電源のノイズをとるために、プラスとGNDの間に接続しています。
3.カラーセンサーのライブラリ
3.1 ライブラリのコード
ライブラリというほどでもないですが、Python の学習もかねてカラーセンサー関係の処理を一つのファイルにまとめました。(リスト1)なお、カラーセンサーの初期化やRGBの値の取り方は、秋月電子通商の資料を参考にしました。
リスト1 ファイル名:Class_ColourSenSor.py
import machine # クラスの定義 class ColourSensor: # __init__() の定義 def __init__(self): self.i2cport = 0 self.sda = 0 self.scl = 1 self.freq = 400000 # カラーセンサーと接続している端子の設定。 # (カラーセンサーのインスタンスを得ている) def init_ColourSensor(self, sda, scl, freq): self.i2cport = i2cport self.sda = sda self.scl = scl self.freq = freq sda_real = machine.Pin(self.sda) scl_real = machine.Pin(self.scl) self.i2c = machine.I2C(self.i2cport, sda = sda_real, \ scl = scl_real, freq = self.freq) # カラーセンサーの初期化 def set_ColourSensor(self): self.i2c.writeto(42, b'\x00\x80') # i2c adrress: 42(10進), ADC部リセット self.i2c.writeto(42, b'\x00\x0b') # 動作開始、Highゲイン、固定時間モード # 積分時間:179.2[msec] # カラーセンサーから値をとる関数 def get_ColourSensor(self): # センサーからの値を入手 data = self.i2c.readfrom_mem(42, 3, 8) # adrress 0x03 より 8bytes 入手 R = data[0] * 255 + data[1] G = data[2] * 255 + data[3] B = data[4] * 255 + data[5] IR = data[6] * 255 + data[7] # ルクス[lx] に換算 Rf = R / 117.0 Gf = G / 85.0 Bf = B / 44.8 IRf = IR / 30.0 return Rf, Gf, Bf, IRf
3.2 解説
1行目: ライブラリをインポートしています。
4行目: クラスColourSensor() の定義
7~11行: 変数などを初期化する関数__init()__の定義
15~22行目: カラーセンサーをI2C にて接続する手続きをしています。
machine モジュール内の I2C()というメソッドにより、I2Cの制御がとても楽になっています。
25~27行目: カラーセンサーにデータを送ってカラーセンサーを初期化しています。
初期化の内容~42はカラーセンサーのアドレス(10進)です。
次の b'\x00\x80' はアドレス0x00 へ0x80 を指示。(ADCリセット、動作開始)
その次の b'\x00\x0b' はアドレス0x00 へ 0x0bを指示。(動作開始、Highゲイン、
固定時間モード、積分時間:179.2[msec])
(要は感度最大、その分AD変換の時間設定は長めでよろしく、ということ)
31~46行目: アドレス 0x03 より 8bytes 入手。
(2バイトずつR、G、B、IR(赤外線)のデータを得る)
35~38行目:R、G、B、IRのカウント値を計算しています。
41~44行目:カウント値からルクスの計算。秋月の資料を参照してください。
(代表とする波長からの換算値なので、実際とは異なっていると思われます)
46行目:return 文により戻り値を返しています。(単位:ルクス)
4.実行ファイル
4.1 実行ファイルのソースコード
上のライブラリを使ってカラーセンサーの出力を測定するための実際のソースコードを以下に示します。光源はNeopixelを用いました。Neopixelに関してはここの記事を参考にしてください
リスト2
import utime from Sep_2021 import Class_ColourSensor from Oct_2021 import Class_ws2812b_Ver2 # カラーセンサーのインスタンスを得ている i2c = Class_ColourSensor.ColourSensor() # カラーセンサーの初期設定 # I2C1 を用い、SDAはGP18(#24pin) # SCLはGP19(#25pin),周波数は400KHz i2c.init_ColourSensor(1, 18, 19, 400000) # i2c adrress: 42(10進) # ADC部リセット、動作開始、 # Highゲイン、固定時間モード、積分時間:179.2[msec] i2c.set_ColourSensor() # WS2812B Setting # Configure the number of WS2812 LEDs. NUM_LEDS = 16 # Create the StateMachine with the ws2812 program, outputting on Pin(0). ws = Class_ws2812b_Ver2.Class_WS2812B() # StateMachine(0, ws2812, freq=8000000, sideset_base=Pin(16)) ws.init_ws2812b(0, 8000000, 16, NUM_LEDS) # 変数の設定 Red-GP13, Green-GP14, Blue-GP15 Red_On = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_DOWN) Green_On = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN) Blue_On = machine.Pin(15, machine.Pin.IN, machine.Pin.PULL_DOWN) count = 0 if __name__ == '__main__': # Process arguments print('Press Ctrl-C to quit.') try: while True: if count >= 33: count = 0 # R, G, ,B ,IR(赤外線)単位[lux]を取得 R, G, B, IR = i2c.get_ColourSensor() print('R, G, B, IR:', R, G, B, IR) utime.sleep(0.01) count += 1 if Red_On.value() == 1: ws.ar_color_all(255, 0, 0) # 赤 utime.sleep(0.01) if Green_On.value() == 1: ws.ar_color_all( 0, 255, 0) # 緑 utime.sleep(0.01) if Blue_On.value() == 1: ws.ar_color_all( 0, 0, 255) # 青 utime.sleep(0.01) except KeyboardInterrupt: #### clear ws2812b ws.clear_all() print('program is finished')
4.2 解説
1~3行目:ライブラリをインポートしている。自作のはファイルごとに保存場所が違っています
5~16行目:この部分でカラーセンサーが使えるようにしています。
18~24行目:この部分でNeopixelが使えるようにしています。
27~29行目:押しボタンswのピンへの割り当てを行っています。赤、緑、青と3つあります。
31行目:制御に使う変数count の初期設定です。
33,37,60行目:メイン処理のフレーム(?)です。Ctrl-C を押すとメインの部分から抜け出します。
38~58行目:メインルーチンです。変数count により約1秒に1回、カラーセンサーからの値を読み取っています。それ以外の時間は押しボタンswのうち、どれを押したかでNeopixelの色が変わります。
61~63行目:Ctrl-C が押されるとここに処理が移ります。Neopixelを消し、コンソール(?)に文字を出力し、プログラムを終了します。
5.実測
実際にセンサーの値を測定しました(図2)。自然光が入るとデータがおかしくなると思い、カバーを付けました。結果は表1のようになりました。光が赤い状態でも、青や緑の成分を含んでいることが分かりました。
センサーの読み取り値 [lx] |
|||||
---|---|---|---|---|---|
R |
G |
B |
IR |
||
LED の色 |
赤 |
560 |
96 |
78 |
208 |
緑 |
87 |
771 |
612 |
205 |
|
青 |
65 |
443 |
1462 |
310 |
これにより光センサの測定値(ルクス)からRGB値を求める式は
R = 255 ÷ 560 ×(光センサーのRの値)
G = 255 ÷ 771 ×(光センサーのGの値)
B = 255 ÷ 1462 ×(光センサーのBの値)
となるのではないかと思いました。(実際のところは分からないです。機会があったら勉強したいと思います)
ただし、LEDの色が緑のとき、Gの値は771で、このときのカラーセンサーからの生のデータは
771×85=65535
となり、値がマックスに達してしまっています。なので、本当なら光センサーの感度を落とさなければいけないのでしょうけれど、設定が少し難しそうなので、今回はここまでにしようかと思います。
6.まとめ
以上、まとめると、
- Neopixelを用いて光を発成させカラーセンサーの値を読み取り、ルクスの単位で測定することができた
- また、その出力値から光のRGBの値を求めることを試みた
- 実際に測定してみると、例えば赤い光を測定する場合、青や緑の出力も出てしまい、データをどのように処理すればよいかが分からなくなった。今後の課題としたいです。
(以上)