Raspberry Pi PicoでLED方向幕のルーレットを作ってみよう!

2023/5/1, 7M4MON




1.ハードウェア

Maker Faire Tokyo2022 にて あせら さんのLED方向幕を拝見し、その完成度の高さに触発されて自分も作ってみることにしました。
調べてみると、あせらさんの他、STM32を使用した作例もありましたが、どちらも単体では動作せず、ホストPCが必要のようでした。
過去の経験(WS2812B)から、こういうガジェットは単体で動作することが望ましいと感じていたので、使用デバイスの選定から行うことにしました。
実は、HUB75のLEDマトリックスを扱うのは初めてではなく、 Arduino Nano (ATMega328P) を使って、32x16のLEDで、 タクシーのスーパーサイン を作ったことがありました。
このプロジェクトでは 512 LEDsでATMega328PのRAM(2kB)を使い切っていたので、少なくともその4倍のRAMサイズのマイコンが必要と予測されました。
できれば画像の保存先は内蔵ストレージだと便利だよなぁ・・・と調べてみると、Raspberry Pi Pico でLED Matrixを利用した作例があり、これで行くことにしました。

Raspberry Pi Pico RP2040 の主な仕様

LEDパネルはAliexpressから 64x32, P2.5 の物を2枚取り寄せました。


あせら さんのプログラムで動作確認をしたところ、このパネルは青と緑の配列が一般的なパネルと逆になっているようでした。
そこで、あせらさんのプログラムに青と緑を逆にするオプションを追加し、プ ルリクエストをかけてマージしていただきました。
パネル側は5Vで動いていて、RPi PicoのIOは3.3Vなので、レベル変換モジュールを入れてあります。
パネルのサイズは1枚当たり160 x 80 (mm) でしたので、2枚で 320 x 80 (mm) のサイズになります。
ケース(?)はアクリルEX板 EX530スモーク透明(全光透過率19%)でLEDパネルをサンドイッチすることにしました。
サイズSSは180x320mmなので、横幅はピッタリです。2枚買ってきて、卓上丸ノコで2枚とも100mmのところで切断します。
で、イラストレーターで穴位置図を作ってセブンイレブンでA3に印刷してドリルで加工しました。


(pdfにリンク)

千石電商で手に入る最長の六角スペーサーは55mm(ASB-355E)でした。パネルの厚みは15mmでしたので、パネルの固定は方雄ネジの40mm(BSB-340E)を使用しました。

LEDパネル2枚すべてに白を表示した場合、消費電流は6A程度です。手持ちの5V/4AのACアダプタでは電流不足で白が多めの表示だと落ちてしまうようでした。
アマゾンから5V/10AのACアダプタを購入して落ちることはなくなりましたが、コネクタや線の太さが電流に対し不十分なので電圧降下が大きめです。(0.7V程度低下)
電源スイッチ用のPch FETは、定番の2SJ681では不十分で、30V40AのMTP4835I3にしました。

スイッチ類は、表示時間設定用のDIPロータリースイッチ(1)とフォルダ選択用のDIPロータリースイッチ(2)と押しボタンスイッチです。
押しボタンスイッチはコネクタ経由で外部のアーケードボタン(30mm)に接続し、ルーレットモードで気分を盛り上げます。

外観図およびブロック図は以下の通りです。

  


2.ソフトウェア

2.1 Circuit Python

先行事例では開発環境として Circuit Python を使用していましたので、踏襲します。
詳しくは Circuit Python のページに記載されていますが、特徴を箇条書きにすると…

といった感じです。

特にはまったのは

というところです。

どういうことかというと、

x = 0

def add_x():
        x += 1
        return x


これは変数を宣言する前に値を入れた系のエラーNameError: local variable referenced before assignmentになります。希望の動作をするには

x = 0

def add_x():
        global x
        x += 1
        return x

とします。ちなみに、参照することはできてしまうので、global宣言をしなくても print(x) は普通に表示されます(ので特にハマった)。

プログラムを書込んだときに内蔵ストレージの残り容量は約950kBでした。
LEDの表示画像はおよそ5.5kBでしたので、170枚をストレージに保存することが出来ました。


2.2 プログラムの仕様

プログラムは以下の二種類を作成しました。
① 【インオーダータイプ】
  2階層下のフォルダを順次アクセスして保存された画像を順番に表示

② 【ルーレットタイプ】
  1階層下のフォルダにすべての画像を保存しておいて、ランダムに(ルーレット)表示、ボタン押下で停止。アタリなら効果音が変わる。


① インオーダータイプ

bmp/ 以下に列車の種類ごとに保存したフォルダを準備しておき、そのフォルダに順次アクセスして中のBMPファイルを表示していきます。
DIPロータリースイッチ(1)は次の画像表示するまでの時間を決定します。スイッチの読み込みタイミングは画像が表示されたときです。
DIPロータリースイッチ(2)は初回に表示するフォルダを決定します。数字がフォルダより多い場合は、0番目のフォルダを表示します。
ボタン押下しながら電源ONでランダムなフォルダのランダムなファイルを選びますが、フォルダの中のファイル数によっては表示する
画像に偏りが出るので(例えば0のフォルダに50個の画像、1のフォルダに1個の画像があるとすると、
1のフォルダの画像は0のフォルダの画像より50倍表示されやすい)、②のプログラムを作ることにしました。

② ルーレットタイプ

bmp/ 以下にすべての画像ファイルを保存しておき、その中からランダムなファイルを表示します。
ボタンを押下すると押したタイミングの画像で止まります。
ファイルには“アタリ判定”があり、リストに登録された画像が表示されると圧電スピーカーからアタリの効果音が鳴ります。
ボタン押下しながら電源ONで、ボタン押下する度にファイルを順次表示します。
DIPロータリースイッチ(1)は次に切り替わるまでの時間を決定します。DIPロータリースイッチ(2)は未使用です。

プログラムは github に公開してあります


3.画像の作成

LED Matrixに表示する画像は、LED再現ギャラリー様の画像を利用しました。(掲示板にて作品で使うことを承諾済み)
そのままではLEDパネルに表示できませんので、以下の処理で 128x32 / 256色のBMP画像にします。

  1. 複数の画像が1枚のGIFになっているものはPNGに分解します。
    (自前でPython Scriptを組みましたがフリーソフトでもOK)

  2. PNGからリサイズ&減色したBMPファイルを作成します。
    画像は3ピクセル毎にLEDの輝点が当たるように構成されているので、初期オフセット値から3ピクセル毎に色を取得し、
    減色してBMPファイルにするPythonプログラムを作成しました。
    減色する際は、単に減色しただけだと色の再現性が微妙(例えば、オレンジに青成分が含まれているため白っぽく表示される)なので、
    カラーパレットの近似色を選ぶか、各色サンプル階調に計算で丸め込むか選べるようにしました。


    このプログラムは github に上げてあります

  3. 減色したBMPは24bitカラーなのですが、そのままでは Pico LED Matrix に表示することはできませんので256色に減色します。
    Windows標準のペイントを使って1枚1枚256色で保存してもよいのですが、面倒なのでJTrimで一括変換しました。


4.かかった費用

 7000円くらい


5.感想

 子供たちの反応は上々でしたので作った甲斐がありました。