Tanuki_Bayashin’s diary

電子工作を趣味としています。最近はラズベリーパイPicoというマイコンを使って楽しんでいます

【ラズベリーパイPico】カラーセンサの値を読み取る

※なにか気になる点がありましたらコメント欄からお伝えください。また、回路を製作する場合には電源を切るなど、注意を払って行うようお願いいたします。

もくじ

1.はじめに

 カラーセンサの値をラズベリーパイPico(以下Pico と記述) にて読み取り、thonny のシェルに表示してみたので、備忘録として書きとどておこうと思います。
 カラーセンサからの値はPicoより I2C通信により読み取っています。また、カラーセンサとのデータの処理を行う部分を、ライブラリとして管理しました。あくまで自分用です。

参考資料
ラズベリーパイPico:
www.raspberrypi.org

秋月電子通商
※このHPの検索欄にて、カラーセンサ「S11059-02DT」あるいは通販コード「K-08316」と入力すれば、カラーセンサの情報を得ることができます。
(2023/10/03 変更:秋月電子通商の意向により)
akizukidenshi.com

2.構成

図1 全体構成図


 全体構成図を図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 カラーセンサーを用いて光の成分を測定した

 実際にセンサーの値を測定しました(図2)。自然光が入るとデータがおかしくなると思い、カバーを付けました。結果は表1のようになりました。光が赤い状態でも、青や緑の成分を含んでいることが分かりました。




センサーの読み取り値 [lx]

R

G

B

IR

LED の色



560

96

78

208



87

771

612

205



65

443

1462

310
表1 カラーセンサーの読み取り値:単位 ルクス[lx]

これにより光センサの測定値(ルクス)からRGB値を求める式は
R = 255 ÷ 560 ×(光センサーのRの値)
G = 255 ÷ 771 ×(光センサーのGの値)
B = 255 ÷ 1462 ×(光センサーのBの値)
となるのではないかと思いました。(実際のところは分からないです。機会があったら勉強したいと思います)
ただし、LEDの色が緑のとき、Gの値は771で、このときのカラーセンサーからの生のデータは
771×85=65535
となり、値がマックスに達してしまっています。なので、本当なら光センサーの感度を落とさなければいけないのでしょうけれど、設定が少し難しそうなので、今回はここまでにしようかと思います。

6.まとめ

 以上、まとめると、

  • Neopixelを用いて光を発成させカラーセンサーの値を読み取り、ルクスの単位で測定することができた
  • また、その出力値から光のRGBの値を求めることを試みた
  • 実際に測定してみると、例えば赤い光を測定する場合、青や緑の出力も出てしまい、データをどのように処理すればよいかが分からなくなった。今後の課題としたいです。

(以上)