何回目なのやら覚えていませんけど、今回もLEDキャンドルを作って見ました。
「#4-6 LEDキャンドル」
「#11-6 LED暖炉」
「#14-6 暗くなったら蝋燭を灯して」
「#15-10 汎用16ビットタイマユニット」
※オリジナル16ビットCPUコアMoscoviumのデモとして、LEDキャンドルを作成。
ろうそくの炎とかもそうだけど、風等も含め、自然界の現象には1/fゆらぎになっているものが多いそうです。
そこで、1/fゆらぎ乱数列を使ってLEDの明るさを制御、明るさの変化がまるで炎が揺らめいているかのように見せるのが、LEDキャンドルです。
基本的には、「#4-6 LEDキャンドル」で作成した1/fゆらぎ乱数列が肝となっています。1/fゆらぎ乱数列を作る(生成する)のは少し大変でしたが、一度乱数列を作成してしまえば、それをデータ(定数)としてプログラムに埋め込んで使うだけなので、色々な場面で作ってきました。
今回もLEDキャンドルを作るのですが、今回使うのは、RGB LEDパネル(下図)です。
このRGB LEDパネルを縦に使って、8個あるピクセルを下から順番に光らせます。光らせるピクセルの数で炎の大きさを表現すると共に、フルカラーRGB LEDを活用して炎の色も表現しようと思います。
今回使用するRGB LEDパネルには、8個のWS2812B(RGB LEDチップ)が並んでいます。
WS2812Bの制御方法については、「#11-2 円形配置RGB LED(WS2812B)を使う」に解説がありますので、参照して見てください。
WS2812BはR,G,B各0〜255の256段階で設定可能なので、一応、フルカラーRGB(2563≒1,677万色)と言うふれ込みになっています。ところが、WS2812Bはとても明るくて、4〜8段目(/255段階)で光らせても、既にロウソクとしては明るすぎるくらいの明度なのです。
そこで、「#19-1 デジタルPWM」で解説したデジタルPWMを使って暗く光らせると共に、1/fゆらぎ乱数に従った明度調整を組み合わせて、見た目もろうそくの炎に近づけてみようと思います。
8ピクセルが縦に並んでいるので、光らせるピクセルの数で炎🔥の大きさを表現します(下図)。
炎の大きさは、1/fゆらぎ乱数列を使って変動させます。
フルカラーRGB LEDなので、色合いも、ロウソクの炎っぽい色に調整しています。炎の色合いは、予めそれらしく見えるような値を配列変数(cdl_patn[ ])に保持しておきました。
// fire pattern: (R,G,B)
PROGMEM const uint8 cdl_patn[3*cdl_SIZ_PATN]=
{
187,34,0, // bottom
255,51,0,
255,68,0,
255,85,0,
255,102,17,
255,102,17,
255,119,17,
255,119,17,
255,102,17,
255,102,17,
255,102,17,
255,85,0,
255,68,0,
255,51,0,
204,34,0,
119,17,0 // top
};
RGB LEDパネルのピクセル数8個に対して、cdl_patn[ ]のパタン数16個と多めなのは、1/fゆらぎ乱数列で決定した光らせるピクセル数Nから16パタンにマッピングした時、パタン間の補間効果を適応するためです。
見た目の発光ピクセル数と、全体の明るさ(ロウソクの瞬き)には、同じ1/fゆらぎ乱数値R1Fを使っています。
シリアルモニタ無しで自立する様、電源投入・リセット解除後、デフォルトでLEDキャンドルモードを有効にしてあります。以下に完成したプログラムをリンクしておきます。
完成プログラム:led_candle_ws2812b.ino
コンパイルしてArduino UNOに書き込むと、シリアルモニタから以下のコマンドを受け付けています。
シリアルモニタコマンド仕様:
基本的にすべてデバッグ用のコマンドなので、シリアルモニタ無しで自立します。
と言っても、繋ぐだけです(1^^;)。電源とノイズ設計には注意が必要です。
WS2812Bは明るく光る分、電流を大量に消費します。デジタルPWMで明るさを抑えているので、平均電流はそれなりに小さいはずです。
デジタルPWMは、時分割で明るく光らせる時間と消灯している時間のデューティを制御して、平均的な明るさを調整する技術です(「#19-1 デジタルPWM」)。
WS2812B自体は、光る時は明るく光っているので、その瞬間の電流値はとても大きいです。また、短時間でON/OFFを繰り返すため、ノイズ(EMI、EMS共)も大きくなります。
UNOの5VピンソケットからRGB LEDパネルに給電してしまうと、瞬間的に電流が足りなくなって誤動作したり、UNOのリセットがかかってしまったりする場合があります。
どうしてもUNOの5Vピンソケット(等、電流容量の小さい電源)から電源供給したい場合は、最大輝度値(プログラム内のrgb_MAX_LUM定数値等)を小さく抑えるなど、対策を講じてください。
実際、当方の実験中でも、UNOがハングアップしてしまうことがありました。おそらく、RGB LEDパネルからのノイズ回り込みによる誤動作だと考えられます。どういう状態なのか、再起動することもなく、シリアルモニタの反応が無くなってしまいました。当方の実験では、リセットスイッチを押したら回復しました。
※USB⇔UART変換チップATmega16U2の方がスタックしてしまったのかな?
恐らく、電源・ノイズ設計の問題なので、UNOがハングアップする確率が高い場合には、電流を抑える、ノイズ対策を強化する、などの対策を実施してください。
可能ならば、フォトカプラなどを使って、RGB LEDパネルとUNOの電源線を分離しておくと、ノイズ(EMS)の影響を受け難くすることができます。ですが、WS2812Bとの通信信号はとても高速なので、この信号が通過できる高速なフォトカプラが存在するかどうか?不明です。
UNOにプログラム(led_candle_ws2812b.ino)を書き込んだら、以下の様に接続して、電源を供給してください。
Arduino UNO | 接続 | RGB LEDパネル | 接続 | 電源モジュール |
4-7VDC | ← | 5V | ||
GND | ⇔ | GND | ⇔ | GND |
D3(OC2B) | → | DI |
以下、実験中の様子です。
電源を投入すると、既にLEDキャンドルとして、RGB LEDパネルが発光しているはずです。
以下、LEDキャンドルを表示している様子です。
撮影スペースの関係でドアップですが、もう少し遠目で観た方が、それらしく見えるかも?
今までLEDの明るさだけで表現していたLEDキャンドルですが、今回の物は光らせるピクセル数で炎の大きさも制御してみました。少し引いて遠目に見たらそれっぽく見えると思いますよ。