LEDMATRIXライブラリ: NeoPixel マトリックスライブラリ (MicroPython)

NeoPixelを使用したマトリックス表示

MicroPythonには標準でneopixelライブラリが搭載されており、NeoPixel(WS2812)タイプのカラーLEDを簡単に操作できるようになっています。カラーLEDを操作していると、数個のカラーLEDの点灯にとどまらず、やはり、縦横にマトリックス状にたくさん並べて色々と表示したくなってきますよね。

このような要求は皆さんが持つようで、それに応えるために、8x8,16x16,32x8など、様々なサイズのNeoPixelマトリックスが提供されています。

カラーLEDマトリックス

カラーLEDマトリックスは、8x8,32x8,16x16,など、様々なサイズのNeoPixelマトリックスが提供されています。

LEDMATRIX: カラーLEDマトリックスの表示ライブラリ

カラーLEDマトリックスが利用できるようになると、その一つ一つのピクセルを制御するのではなく、面的な制御が必要になりますよね。Arduinoでは、NeoPixelライブラリに続きNeoMatrixライブラリがAdafruit社から提供されており、だれでもがマトリクス状に配置されたカラーLEDを使用したスケッチを簡単に作成できるようになっています。一方MicroPythonでは、システムに標準でNeoPixelライブラリが組み込まれている一方で、マトリックス用のライブラリは見かけないようです。

ということで、カラーLEDマトリックス用の表示ライブラリLEDMATRIXを作成しましたのでご活用ください。Arduinoもそうですが、MicroPythonもオブジェクト指向プログラミングが可能なので、適切な基底クラスがあれば、それなりに充実した機能を持っクラス/ライブラリが簡単に作成できてしまいます。

LEDMATRIXは、マイクロファンが提供するMicroPythonファームウェアにはあらかじめ組み込まれているので、インストール作業などは必要ありません。。

https://www.microfan.jp/2023/09/micropython-firmware/

LEDMATRIXライブラリの機能概要

LEDMATRIXはssd1306などと同様に、FrameBufferクラスを継承して作成したクラス/ライブラリで、行数は多くないですが、文字列はもちろん、図形の表示もできる優れモノとなっています。

OLEDディスプレイ用のssd1306ライブラリと同様に、以下のような表示ができます。

  • 座標を指定して文字列を表示することができます。
  • 直線約計、楕円などを表示することができます。

また、ssd1306ライブラリと異なり、以下のような表示ができます。

  • 文字列や図形の表示に色やその明るさを指定することができます。
  • 電光掲示板のように指定した文字列を自動的に横にスクロールして表示させることができます。

NeoPixelで作成したカラーLEDマトリックスは、一般的にピクセル数が少ないので、表現能力や使用法に少し制約があります。しかしながら、文字表示や図形表示の操作が同じFrameBufferを基底クラスとするOLEDディスプレイと共通しているので、OLEDディスプレイを使用している方は、すぐにその操作法になれるのではないでしょうか。

また、LEDマトリックスの狭い表示領域を使用した文字列表示がしやすいように、文字列のスクロール表示機能も組み込んでいます。

LEDMATRIXライブラリのコード

以下にLEDMATRIXライブラリのコードを示しますので、開発ボードのlibディレクトリなどに格納してご利用ください。

"""
LEDMATRIX: WS2812B (NeoPixel) Matrix Display driver
for MicroPython
Version 1.0

Copyright 2023 K.Kakizaki

"""

from machine import Pin
import framebuf
from micropython import const
from neopixel import NeoPixel
import time

def LEDColor(r, g, b) :
    return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)

class LEDMATRIX(framebuf.FrameBuffer):

    RED = LEDColor(255, 0, 0)
    GREEN = LEDColor(0, 255, 0)
    BLUE = LEDColor(0, 0, 255)
    CYAN = LEDColor(0, 255, 255)
    YELLOW = LEDColor(255, 255, 0)
    PURPLE = LEDColor(255, 0, 255)
    WHITE = LEDColor(255, 255, 255)
    BLACK = LEDColor(0, 0, 0)

    SIMPLE=const(0x01)
    ZIGZAG=const(0x02)
    TOP=const(0x10)
    BOTTOM=const(0x20)
    RIGHT=const(0x40)
    LEFT=const(0x50)

    def __init__(self, pin, width, height, skip=0, link=SIMPLE):
        self._pin = Pin(pin, Pin.OUT)
        self._width = width
        self._height = height
        self._skip = skip
        self._link = link
        self._np = NeoPixel(self._pin, width * height + skip)
        self._brt = 10
        self.buffer = bytearray(self._height * self._width * 2)
        super().__init__(self.buffer, self._width, self._height, framebuf.RGB565)
        self.fill(0)
        for i in range(0, skip):
            self._np[i] = (0,0,0)
        self.show()

    def color(self, r, g, b):
        return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)

    def setPixelColor(self, n, r, g, b):
        self._np[n] = (r, g, b)

    def setBrightness(self, brt):
        if (brt > 255):
            brt = 255
        if (brt < 0):
            brt = 0
        self._brt = brt
        self.show()

    def getBrightness(self):
        return self._brt

    def showScrollText(self, text, color, bgcolor=0, y=0, dir=0, ms=50):
        text = str(text)
        for x in range(self._width,-8*len(text)-1,-1):
            self.fill(bgcolor)
            self.text(text,x,y,color)
            self.show()
            time.sleep_ms(ms)

    def setScrollText(self, text, color, bgcolor=0, y=0, dir=0, ms=50):
        self._text = str(text)
        self._color = color
        self._bgcolor = bgcolor
        self._sty = y
        self._stx = self._width
        self._stxe = -8*len(self._text)-1
        self._dir = dir
        self._ms = ms

    def runScrollText(self):
        if self._stx > self._stxe:
            self.fill(self._bgcolor)
            self.text(self._text, self._stx, self._sty, self._color)
            self.show()
            self._stx = self._stx - 1
            return True
        else:
            return False

    def size(self):
        return (self._width, self._height)

    def show(self):
        for x in range(0, self._width):
            for y in range(0, self._height):
                idx = x + y * self._width
                v1 = self.buffer[idx*2]
                v0 = self.buffer[idx*2+1]
                vr = (v0 >> 3) << 3
                vg = (((v0 & 0x7) << 3) | (v1 >> 5)) << 2
                vb = (v1 & 0x1F) << 3
                rate = self._brt/255
                if self._link == SIMPLE:
                    lidx = x + y * self._width
                else:
                    lidx = x * self._height
                    if x % 2 == 0:
                        lidx += y
                    else:
                        lidx += (self._height - y - 1)
                self._np[lidx + self._skip] = (int(vr*rate), int(vg*rate), int(vb*rate))
        self._np.write()

ライブラリの使用法

準備中、まずは、以下の使用例をご参照ください。

以下に、LEDMATRIXの基底クラスとして使用したFrameBufferの説明ページを示します。

このページの各種のメソッドが、LEDMATRIXで使用できます。

カラーLEDマトリックスの使用上の注意

カラーLEDマトリックスは、さほどピクセル数の多くない8x8ピクセルのパネルでも、64個のカラーLEDが組み込まれています。それぞれのカラーLEDは、白色で最高光度で表示させた場合で50-60mA程度使用します。あまり多くはないように思われるかもしれませんが、この電流にその個数の64を掛けると3.8A程度になります。したがって、32x8や16x16のLEDマトリックスが要求する最大の電流を想定すると、ちょっと恐ろしいですね。

ちなみに、PCのUSBから取得していい電流は、500mAから800mA程度です。3.8Aのような大きな電流を要求すると、安全装置が機能するかもしれませんが、PCや開発ボードが壊れる要因になります。また、それなりに明かる状態でカラーLEDマトリックスを表示させると、カラーLEDマトリックスの基板やそれで電力を供している開発基板が不安を感じるようなかなりの熱を持ちます。

このような問題が生じないように、カラーLEDマトリックスを利用する際には、以下のような点に注意してご利用ください。

  • 可能であれば、想定される最大の電流を余裕をもって流すことができる5V電源を別途確保し、カラーLEDマトリックスの電源として接続する。例えば、32x8や16x16のLEDマトリックスには、電源専用の電線がついているので、そこに5V電源を接続し、開発ボードからの信号線等の3線コネクタ部分には、GNDと信号線のみを接続するようにします。
  • 電流が確保できる場合には発熱量が大きくなるので、放熱対策を考慮する。
  • グラフィックス表示などで、カラーLEDすべてを点灯させるような表示はさける。
  • 文字表示の場合には、文字以外のバックグラウンドは基本的に黒色(無発色)で使用する。
  • 多くのカラーLEDを点灯させなければならない場合には、各カラーLEDの明るさをできるだけ小さく設定する。例えば、setBrightness()メソッドを使用して、カラーLEDマトリックス全体の明るさを低く設定する。setBrightness()では、最大で255を指定できますが、例えば10-20程度を指定します。これで電流を1/10-1/20にすることができ、また、多くの場合LEDは十分な明るさで点灯します。
  • カラーLEDマトリックスの全面表示など、多数のカラーLEDを点灯させる場合には、それぞれのLEDの発光色としてR,G,Bのどれか単色を指定し、同時にR,G,Bの複数のLEDに電流が流れないようにする。

LEDMATRIXライブラリの使用例

グラフィックス表示とテキスト表示

LEDMATRIXはframebufがスーパークラスになっているので、文字だけでなくグラフィックス表示も可能です。ESP8266とESP32-C3はellipse()メソッドが実装されておらず、楕円形を表示することができません。(このため、このデモではelipse()を使用していません。)

開発ボード上に3個のカラーLEDを装備しているESP32-S3-KEY-R2や1個のカラーLEDを装備しているSTM32-SLIMに、それらのカラーLEDと数珠つなぎで8x8ピクセルのカラーLEDマトリックスを接続して利用する方法を紹介します。

この様な開発ボードでLEDMATRIXを使用する場合には、カラーLEDマトリックスに先行して開発ボード等に取り付けられているカラーLEDの個数をLEDMATRIXのコンストラクタの第4引数に指定します。

ESP32-S3-KEY-R2と同様に基板上に3個のカラーLEDを装備している開発ボードには以下のようなものがあります。

  • RP2040-SLIM-PLUS
  • RP2040-UNO-PLUS
  • STM32-SLIM-PLUS
  • STM32-UNO-PLUS
  • ESP32-S3-KEY-R2
  • ESP32-C3M-TRY

STM32-SLIMと同様に基板上に1個のカラーLEDを装備している開発ボードには以下のようなものがあります。

  • RP2040-UNO
  • STM32-UNO
  • STM32-SLIM
from ledmatrix import LEDMATRIX
import time

# 8x8のカラーLEDマトリックスを使用
lmx = LEDMATRIX(2,8,8) # ESP8266-LEAF
# lmx = LEDMATRIX('RGB',8,8,3) # ESP32-S3-KEY-R2など開発基板上に3個のカラーLEDがあるもの

# lmx.setBrightness(50) # 暗いと思う場合にはコメントを外す

lmx.line(0,0,7,7,LEDMATRIX.BLUE)
lmx.line(0,7,7,0,LEDMATRIX.BLUE)
lmx.show()
time.sleep_ms(1000)
lmx.rect(0,0,8,8,LEDMATRIX.GREEN)
lmx.show()
time.sleep_ms(1000)
lmx.text('A',0,0,LEDMATRIX.RED)
lmx.show()

スクロール表示

showScrollText()メソッドで、指定された文字列をカラーLEDマトリックス上でスクロール表示する例です。8x8ピクセルと表示領域が小さくても、それなりの情報を文字で出力できます。

showScrollText()の引数には、数値やstr()で文字列化可能なオブジェクトを指定することができます。

from ledmatrix import LEDMATRIX
import time

# 8x8のカラーLEDマトリックスを使用
# lmx = LEDMATRIX(2,8,8) # ESP8266-LEAF
lmx = LEDMATRIX('RGB',8,8,3) # ESP32-S3-KEY-R2

# lmx.setBrightness(50) # 暗いと思う場合にはコメントを外す
lmx.showScrollText('LEDMATRIX', LEDMATRIX.GREEN, ms=100)
lmx.showScrollText(12.34, LEDMATRIX.BLUE) # 数値も出力可

lmx.setScrollText('MicroFan', LEDMATRIX.RED)
while lmx.runScrollText():
# スクロール中にブロックされると困る処理が書ける
    time.sleep_ms(50)

デモプログラム

ESP32-PIXELやESP32-KEY-R2, ESP32-SLIM等を対象として作成したLEDMATRIXのデモプログラムです。

LEDMATRIXコンストラクタの第一引数に、LEDの制御用に割り当てたピン番号を指定します。

from ledmatrix import LEDMATRIX
import time

color = [LEDMATRIX.RED, LEDMATRIX.GREEN, LEDMATRIX.BLUE, LEDMATRIX.CYAN, LEDMATRIX.YELLOW, LEDMATRIX.PURPLE, LEDMATRIX.WHITE]
brt = [0,1,2,3,5,10,20,30]

# lmx = LEDMATRIX(15,18,8) # ESP32-PIXEL
# lmx = LEDMATRIX(23,8,8) # LEDマトリックスパネル 8x8
# lmx = LEDMATRIX(23,32,8,link=LEDMATRIX.ZIGZAG) # LEDパネルマトリックスパネル 32x8
# lmx = LEDMATRIX(23,16,16,link=LEDMATRIX.ZIGZAG) # LEDパネルマトリックスパネル 16x16

if lmx.size()[0] <= 8:
    scrms = 80
elif lmx.size()[0] <= 20:
    scrms = 50
else:
    scrms = 20

lmx.setBrightness(0)
lmx.fill(LEDMATRIX.GREEN)
for n in brt:
    lmx.setBrightness(n)
    time.sleep_ms(200)
time.sleep_ms(1000)

lmx.fill(0)
lmx.setBrightness(10)
time.sleep_ms(1000)

if lmx.size()[1] == 18:
    str = 'ESP32-PIXEL LED LED MATRIX'
else:
    str = 'MicroFan, LED MATRIX'
    
lmx.showScrollText(str, LEDMATRIX.YELLOW, ms=scrms)
time.sleep_ms(1000)

for y in range(lmx.size()[1]+1,0,-1):
    lmx.fill_rect(0, 0, y*2, y, color[y%len(color)])
    lmx.show()
    time.sleep_ms(100)
time.sleep_ms(1000)

lmx.showScrollText('Temp,Hum,Press,Accel,Bright', LEDMATRIX.CYAN, ms=scrms)
time.sleep_ms(1000)

lmx.fill(0)
for y in range(lmx.size()[1],-1,-1):
    lmx.line(0, y, lmx.size()[0]-1, 0, color[y%len(color)])
    lmx.show()
    time.sleep_ms(100)
time.sleep_ms(1000)

lmx.showScrollText('MicroFan', LEDMATRIX.RED, ms=scrms)
time.sleep_ms(1000)

# ellipseはESP8266やESP32-C3では実装されていないようなので、このブロックは削除
for r in range(1,lmx.size()[0]//2):
    lmx.ellipse(lmx.size()[0]//2,lmx.size()[1]//2,r,r,LEDMATRIX.BLUE,True)
    lmx.show()
    time.sleep_ms(300)
time.sleep_ms(1000)

lmx.fill(LEDMATRIX.BLACK)
str = '> <'
x = lmx.size()[0]//2 - (8*len(str))//2
y = (lmx.size()[1] - 8) // 2
if lmx.size()[0] <= 8:
    lmx.text('#',0,0,LEDMATRIX.GREEN)
else:
    lmx.text(str,x,y,LEDMATRIX.CYAN)
    lmx.text('#',x+8,y,LEDMATRIX.GREEN)
for n in [0,1,1,1,2,2,3,5,7,10]:
    lmx.setBrightness(n)
    lmx.show()
    time.sleep_ms(300)

関連製品

カラーLEDマトリックス搭載

弊社の商品にも、WS2812タイプのカラーLEDをマトリックス状に配置して搭載している開発ボードESP32-PIXELがあります。ESP32-PIXELには、8x18ピクセルのカラーLEDマトリックスが装備されており、様々な用途にカラーLEDマトリックスを利用した応用を楽しむことができます。

ESP32-S3-KEY-R2はその基板上に3個のカラーLEDが装備されており、その開発基盤のみで、カラーLEDの操作や応用を楽しむことができますが、そのカラーLEDの信号出力が端子に出されているので、外部にカラーLEDマトリックスを接続することができます。

カラーLEDマトリックス接続機能

ESP32-S3-KEY-R2には、3個のカラーLEDが搭載され、その出力信号が取り出せるようになっており、外部にカラーLEDマトリックスなどを接続できるようになっています。

ESP8266-LEAF-R5には、カラーLEDを接続するための端子が用意されており、信号線はカラーLEDの使用に合致した5Vに変換されて出力されています。