ラズパイを使って、シリアルLEDを制御する

8 min read読了の目安(約7800字

ラズパイを使って、シリアルLEDを制御するメモです。
シリアルLED(WS2812B)とは、マイコンやArduino等からSPIで簡単に制御できるRGBのドットマトリックスLEDパネルです。

デモ

最終的に作るものは、以下となります。

https://twitter.com/tw_kotatu/status/1390605793809113090

※16x16のLEDパネルを4つ使って32x32ドットの表示を行います。
 32x32のパネルであれば、もっと簡単に実現できます。

システム図

image

機材一覧

no 部品名 個数 備考
1 ラズベリーパイ 1 今回は4Bで確認
2 シリアルLED(16x16) 4 BTF-LIGHTING WS2812B ECO RGB合金ワイヤー 16X16cm 265ピクセル LED
3 ACアダプター 5V 4A 1 ACアダプター 5V 4A出力プラグ外径5.5mm 3A以上は必須
4 DCジャック変換プラグ 1 DCジャック変換プラグ
5 ジャンパー線 適量 -

開発環境

  • ラズベリーパイ
    • Linux rpi 5.10.17-v7l+ #1403 SMP Mon Feb 22 11:33:35 GMT 2021 armv7l GNU/Linux
  • Python
    • Python 3.7.3 (default, Jan 22 2021, 20:04:44)

接続

全体図

  • 正面から見たシリアルLED
    • image
  • 背面から見たシリアルLED(接続)
    • image

接続表

ws281x 接続先 備考
[A]①3pin - 5V - つながない
[A]①3pin - GND ラズベリーパイ-GND -
[A]①3pin - DIN [pi]① ラズベリーパイ-[PHY]12([BCM]18) [PHY]は物理ピン, [BCM]はプログラムで指定
[A]②2pin - 5V 外部電源-5V DCジャック変換プラグを介して、ACアダプタに接続
[A]②2pin - GND 外部電源-GND DCジャック変換プラグを介して、ACアダプタに接続
[A]③3pin - 5V ws281x - [B]③3pin - 5V 専用のコネクタで接続する
[A]③3pin - GND ws281x - [B]③3pin - GND 専用のコネクタで接続する
[A]③3pin - DOUT ws281x - [B]③3pin - DIN 専用のコネクタで接続する
[B]④3pin - 5V ws281x - [C]④3pin - 5V 専用のコネクタで接続する
[B]④3pin - GND ws281x - [C]④3pin - GND 専用のコネクタで接続する
[B]④3pin - DOUT ws281x - [C]④3pin - DIN 専用のコネクタで接続する
[C]④3pin - 5V ws281x - [D]④3pin - 5V 専用のコネクタで接続する
[C]④3pin - GND ws281x - [D]④3pin - GND 専用のコネクタで接続する
[C]④3pin - DOUT ws281x - [D]④3pin - DIN 専用のコネクタで接続する
  • 専用コネクタは、シリアルLEDに付属されている

ラズベリーパイの接続部分

準備

シリアルLEDの使い方

adafruit-circuitpython-neopixelというをライブラリを使用することで、シリアルLEDを制御することができます。
本モジュールを使用する場合は、sudo権限が必要です。

インストールが紹介されている公式サイトは、下記となります。

環境の構築

  • シリアルLEDを動かすには以下
$ python3 -m venv env_sled
$ source env_sled/bin/activate
(env_sled) $ pip install adafruit-circuitpython-neopixel
(env_sled) $ sudo ./env_sled/bin/python
  • デモ用コードではopencvを使用しているので以下を追加
(env_sled) $ pip install opencv-python

シンプルなサンプルコード

下記のコードは、⚪🔵🟢🔴([RED][GREEN][BLUE][WHITE])を点灯→消灯します。

  • コード
(env_sled) $ sudo ./env_sled/bin/python
Python 3.7.3 (default, Jan 22 2021, 20:04:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> import board
>>> import neopixel
>>> 
>>> pixel_pin = board.D18
>>> num_pixels = 64 # 64のLEDを制御
>>> 
>>> ORDER = neopixel.GRB
>>> 
>>> pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.010, auto_write=False, pixel_order=ORDER)
>>> 
>>> # 0番目をRED指定
>>> pixels[0] = (255, 0, 0)
>>> # 1番目をGREEN指定
>>> pixels[1] = (0, 255, 0)
>>> # 2番目をBLUE指定
>>> pixels[2] = (0, 0, 255)
>>> # 3番目をWHITE指定
>>> pixels[3] = (255, 255, 255)
>>> # LEDの状態を更新(ここで点灯)
>>> pixels.show()
>>> 
>>> # num_pixelsのLEDにBLACK(消灯)指定
>>> pixels.fill((0, 0, 0))
>>> # LEDの状態を更新(ここで消灯)
>>> pixels.show()
>>> 

  • 結果

image

  • 注意事項
    • LEDの順番は、奇数行と偶数行ことなります
    • 以下がデータの並びです
    • image

デモの説明

以下の画像を読み込んで、水平方向に1dotずつシフトする画像を表示します。

image_zenn

※画像は、200x32となっています

コード

ポイントや注意事項は、コメントを参照してください。

scroll_moji.py
import board
import neopixel
import time
import numpy as np
import cv2

IMG_PATH = "image_zenn.png"

# シリアルLEDの初期化
pixel_pin = board.D18
num_pixels = 32*32
ORDER = neopixel.GRB

# brightnessをあげると光が強くなりますが、極端に上げるとほぼ白く見える
# auto_writeをTrueにすると、pixels[]にアクセスした時点でLEDが点灯(/消灯)する
pixels = neopixel.NeoPixel(
    pixel_pin, num_pixels, brightness=0.010, auto_write=False, pixel_order=ORDER
)

def show32x32_pixel(np_rgb):
    """今回のシステム用の並べ替え
    """
    global pixels

    for cnt in range(32):
        if cnt%2 == 0:
            # [D],[C]エリア - 偶数行の並べ替え
            for scnt, val in enumerate(np_rgb[cnt,:16,]):
                pixels[1023 - cnt*16 - scnt] = (val[0], val[1], val[2])
            # [A],[B]エリア - 偶数行の並べ替え
            for scnt, val in enumerate(np_rgb[cnt,16:,]):
                pixels[cnt*16 + 16 - 1 - scnt] = (val[0], val[1], val[2])
        else:
            # [D],[C]エリア - 奇数行の並べ替え
            for scnt, val in enumerate(np_rgb[cnt,:16:,]):
                pixels[1024 - (cnt+1)*16 + scnt] = (val[0], val[1], val[2])
            # [A],[B]エリア - 奇数行の並べ替え
            for scnt, val in enumerate(np_rgb[cnt,16:,]):
                pixels[cnt*16 + scnt] = (val[0], val[1], val[2])
    pixels.show()
    return


def main():
    # 消灯
    pixels.fill((0, 0, 0))
    pixels.show()

    cap = cv2.VideoCapture(IMG_PATH)
    while True:
        ret, frame = cap.read()
        if ret == False:
            break

        h, w, _ = frame.shape
        # スクロール表示
        for srt in range(w-32):
            show32x32_pixel(cv2.cvtColor(frame[:,srt:srt+32,:], cv2.COLOR_BGR2RGB))

    time.sleep(0.1)

    # LED消灯
    pixels.fill((0, 0, 0))
    pixels.show()



if __name__ == "__main__":
  main()

実行の仕方

$ sudo ../env_sled/bin/python scroll_moji.py

DEMOの動作になればOKです🎊。

最後に

今回は、スクロールで表示しましたが、gifなどのアニメーションを渡すことで、
アニメーションを表示することもできます。

https://twitter.com/tw_kotatu/status/1390598536371208192