[ラズパイ] WS2812B LEDテープ(NeoPixel RGB)を使ってみる

さて、クリスマスも近づき、窓に演出するイルミネーションをLEDテープを探していたら、NeoPixelなるものを発見。これは、1つのラインで大量のフルカラーLEDを制御できる代物らしく、リングLED、テープLED、パネルLEDなど色々なものが発売されている

けっこうメジャーな製品らしい。NeoPixelはRaspberry Piでも制御できるようだ。ライブラリを探すと

For NeoPixels to work on Raspberry Pi, you must run the code as root! Root access is required to access the RPi peripherals.

このライブラリの注意は上にあるように、RPiにアクセスするのでsudoで実行させないと動かないということ。ラズパイとの接続は以下のサイトを参考にしたけど、3.3Vだと、どう考えても電流オーバーで5Vにつなげた。5Vすら電流が足りるのか、ちょっと怪しい、後で実測してみようと思う。

GPIO18に信号ラインをつなぐ。10、12、18、21のGPIOのいずれかじゃなければダメとのこと(多分ハードウエアPWM?)。ロジックレベルは3.3Vなので5Vに変換するために、いつも通りロジックレベルコンバーターを経由させる。ちなみに5VのままGPIOに接続する(ほんとはダメ!)と一応は点灯はするが、端のLEDの挙動があきらかにおかしかった。ロジックレベルコンバーターを挟むと、その症状は消えたためレベル変換はちゃんとしたほうがいい。ロジックレベルコンバーターは下の記事にも出で来るので参考にしてほしい。

サンプルコードをちょこっといじって、開始時間と終了時間指定でレインボー点灯させるようにした。それ以外は消灯させている。

# Simple test for NeoPixels on Raspberry Pi
import time
import board
import neopixel
import datetime


# Choose an open pin connected to the Data In of the NeoPixel strip, i.e. board.D18
# NeoPixels must be connected to D10, D12, D18 or D21 to work.
pixel_pin = board.D18

# The number of NeoPixels
num_pixels = 144

# The order of the pixel colors - RGB or GRB. Some NeoPixels have red and green reversed!
# For RGBW NeoPixels, simply change the ORDER to RGBW or GRBW.
ORDER = neopixel.GRB

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.5, auto_write=False,
                           pixel_order=ORDER)


def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        r = g = b = 0
    elif pos < 85:
        r = int(pos * 3)
        g = int(255 - pos*3)
        b = 0
    elif pos < 170:
        pos -= 85
        r = int(255 - pos*3)
        g = 0
        b = int(pos*3)
    else:
        pos -= 170
        r = 0
        g = int(pos*3)
        b = int(255 - pos*3)
    return (r, g, b) if ORDER == neopixel.RGB or ORDER == neopixel.GRB else (r, g, b, 0)


def rainbow_cycle(wait):
    for j in range(255):
        for i in range(num_pixels):
            pixel_index = (i * 256 // num_pixels) + j
            pixels[i] = wheel(pixel_index & 255)
        pixels.show()
        time.sleep(wait)
        
def clear_pix():
    for i in range(num_pixels):
        pixels[i] =(0,0,0)
    pixels.show()

def bright_pixs(wait):
    for j in range(255):
        for i in range(num_pixels):
            pixels[i] =(j,j,j)
        pixels.show()
        time.sleep(wait)
        
    for j in range(255):
        for i in range(num_pixels):
            pixels[i] =(255-j,255-j,255-j)
        pixels.show()
        time.sleep(wait)
        
        
def time_in_range(start, end, x):
    """Return true if x is in the range [start, end]"""
    if start <= end:
        return start <= x <= end
    else:
        return start <= x or x <= end


start_time = datetime.time(16,30, 0)
end_time   = datetime.time(23,59, 0)

try:

    while True:
        
        dt_now = datetime.datetime.now().time()
        
        if time_in_range(start_time, end_time, dt_now):
            print("{0:%H:%M:%S} Lighting!!".format(dt_now))
            rainbow_cycle(0.0)    # rainbow cycle with 1ms delay per step
        else:
            print("{0:%H:%M:%S} Out Of Time".format(dt_now))
            clear_pix()
            time.sleep(60)

except KeyboardInterrupt:
    
    clear_pix()
    print("Finish")

実際、ラズパイzeroでこのコードを動かしてみたけど、どうもマシンのパワーによるところが大きく、ちょっと負荷をかけると動きが鈍る。

結構明るいけど、電流量は大丈夫なのかちょっと不安。一応計測してみた。

ちょっとしたパリピ感が・・・w

とりあえず、900mA程度かなぁと思う。ちなみに brightness=0.5となってるけど、これを明るくすると当然、電流量も増える。ちなみに実際1200mAで10分ぐらいやってみたが、特にシャットダウンするとかおかしくなるような感じはなかった。ラズパイの5Vpinのトータル電流は500mAだとか750mAだとか色々なことを書いてあるサイトが多くよくわからない。5Vpinは入力電源に直結されてるみたいなのでACアダプタやUSBアダプタの出力が十分であれば大丈夫なのかな。でもやっぱり、別電源を用意してやったほうがイイのかもしれない。

人柱的な実験で1A出力USBとpiZeroとLEDテープでしばらく点灯させてみたけど、とくに問題なく動いてる様子。でも1AのUSBアダプタは点灯すると少し熱を持つ(40-50度くらい?)ので、それなりに電流量はあると思う。

後日、レインボーの感じがどうもノロいので早くするために、rainbow_cycle関数を下のコードに改変。

def rainbow_cycle(wait):
    for j in range(0,255,5):
        for i in range(num_pixels):
            pixel_index = (i * 256 // num_pixels) + j
            pixels[i] = wheel(pixel_index & 255)
        pixels.show()
        time.sleep(wait)

5個飛ばしでforループを早く回すことでレインボーを早くさせてみた。でも管理者権限で実行しないとダメなのでいちいちコンソールで実行するのめんどくさい・・・