前回の記事 (DMXkingのLeDMX4MAXとNode-REDを使ってSPI-LEDの制御をする方法 その1)では、主に動きのない制御を行ってきましたが、今回は動きのある制御を行います。
CASE5 : 光が流れる演出
SPIのLEDの特長はなんといっても1個単位で操作できること。
まずは、ライン状のLEDを順番に動かすフローを作成しました。
フローはこんな感じ。
フローを起動したときに、LEDの情報を読み込みます。
Changeノードには、numberOfLEDsにSPILEDの素子の数、numberOfSeriesには、流れる一連のLEDの数を設定します。
たとえば、SPI LEDが徐々に明るくなって、同じようなことを繰り返すときに、それがLED何個分なのかを、numberOfSeriesの数量として入力します。
こちらのフローでは時間ごとのLED制御をしています。
Injectノードでは0.1秒間隔でタイムスタンプが送信されます。
その後のCalculate Elapsed Timeというfunctionノードでは、最初にフローを起動してからの時間をelpasedTimeという値に設定します。
ちなみに、この後のフローは1秒ごとに変化するようになっていますが、ここでelpasedTimeを10倍などにすることで、LED制御のスピードを変化させることができます。
ここが今回悩んだ点。LEDの演出をかけるときに始点と終点があり、そのデータをここで持たせています。
上記でLEDの始点と終点が設定できれば、ここで明るさを設定できます。
テスト的にRGBがすべて同じ調光値になっていますが、色を決めた後に調光する比率のコードをかけば解決します。
[{"id":"db3b67f99efec451","type":"inject","z":"dbd1ec4c56b673f8","name":"Trigger every 0.1 seconds","props":[{"p":"payload"}],"repeat":"0.1","crontab":"","once":true,"onceDelay":"0.5","topic":"","payload":"","payloadType":"date","x":280,"y":280,"wires":[["f3923a08c7393bac"]]},{"id":"f3923a08c7393bac","type":"function","z":"dbd1ec4c56b673f8","name":"Calculate Elapsed Time","func":"let startTime = flow.get(\"startTime\") || msg.payload;\nflow.set(\"startTime\", startTime);\n\nlet elapsedTime = (msg.payload - startTime) / 1000.0; // in seconds\nmsg.elapsedTime = elapsedTime;\n\n//スピードが変わる\n//msg.elapsedTime = elapsedTime * 10;\n\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":360,"wires":[["e7c3c1261d490779"]]},{"id":"f4339206fafed860","type":"inject","z":"dbd1ec4c56b673f8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":60,"wires":[["6fd7c18579c7f0d3"]]},{"id":"6fd7c18579c7f0d3","type":"change","z":"dbd1ec4c56b673f8","name":"","rules":[{"t":"set","p":"startTime","pt":"flow","to":"","tot":"num"},{"t":"set","p":"numberOfSeries","pt":"global","to":"10","tot":"num"},{"t":"set","p":"numberOfLEDs","pt":"global","to":"60","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":140,"wires":[["d4b501fd37d59ddb"]]},{"id":"d4b501fd37d59ddb","type":"debug","z":"dbd1ec4c56b673f8","name":"debug 9","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":480,"y":200,"wires":[]},{"id":"e7c3c1261d490779","type":"function","z":"dbd1ec4c56b673f8","name":"LED番号ごとの順番-1","func":"// グローバルパラメータ\nconst elapsedTime = parseInt(msg.elapsedTime);\n\n//const numberOfSeries = 10;\nconst numberOfSeries = global.get(\"numberOfSeries\");\n\n// const numberOfLEDs = 60;\nconst numberOfLEDs = global.get(\"numberOfLEDs\");\n\n// LEDの配列初期化\nlet arrayLED = new Array(numberOfLEDs).fill(0);\n\n// LEDのステータスと順番を計算\nconst LEDStatus = Math.floor(elapsedTime / numberOfSeries);\nconst LEDOrder = elapsedTime % numberOfSeries;\n\n// 先頭のLED番号を計算\nconst topLEDNumber = numberOfSeries * LEDStatus + LEDOrder;\n\n// 先頭LED番号のシリーズ内の位置\nconst topLEDPosition = topLEDNumber % numberOfSeries;\n\n// 各LEDの明るさを計算\nfor (let i = 0; i < numberOfLEDs; i++) {\n const currentLEDPosition = i % numberOfSeries;\n let brightness;\n\n if (topLEDPosition >= currentLEDPosition) {\n brightness = topLEDPosition - currentLEDPosition + 1;\n } else {\n brightness = numberOfSeries + topLEDPosition - currentLEDPosition + 1;\n }\n\n // 先頭LED番号が現在のLED番号より小さい場合は明るさを0に設定\n if (topLEDNumber < i) {\n brightness = 0;\n }\n\n arrayLED[i] = brightness;\n}\n\n// 結果をメッセージに設定して送信\nmsg.payload = {\n \"LEDStatus\": LEDStatus,\n \"LEDOrder\": LEDOrder,\n \"topLEDNumber\": topLEDNumber,\n \"arrayLED\": arrayLED\n};\n\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":440,"wires":[["85f10195319a342e"]]},{"id":"38d4c78d7b21a7d5","type":"debug","z":"dbd1ec4c56b673f8","name":"debug 12","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":800,"y":360,"wires":[]},{"id":"589d291a2686d71e","type":"sACN","z":"dbd1ec4c56b673f8","server":"32222a9fe48c7238","universe":"","channel":"","transition":"instant","transitionRate":50,"transitionTime":1000,"name":"","x":700,"y":580,"wires":[]},{"id":"85f10195319a342e","type":"function","z":"dbd1ec4c56b673f8","name":"sACN-DATA作成","func":"// arratLEDをsACNにおくる\nvar arrayLED = msg.payload.arrayLED;\n\nconst numberOfLEDs = global.get(\"numberOfLEDs\");\nvar sACNarray = [];\nvar DMXNumber;\n\n\n// arrayLEDのデータからRGBに変更\nfor (let i = 0; i < numberOfLEDs; i++) {\n\n DMXNumber = i*3;\n\n // 1アドレス\n sACNarray[DMXNumber] = arrayLED[i] * 10;\n sACNarray[DMXNumber+1] = arrayLED[i] * 10;\n sACNarray[DMXNumber+2] = arrayLED[i] * 10;\n\n // LED Seriesの数がここの倍率に影響\n\n}\n\n\n// 結果をメッセージに設定して送信\nmsg = {\n topic: \"1/1\",\n payload: sACNarray\n}\n\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":520,"wires":[["38d4c78d7b21a7d5","589d291a2686d71e"]]},{"id":"32222a9fe48c7238","type":"sacn-config","hostOrUniverse":"192.168.1.83","port":"5568"}]
まとめ
DMXコントローラーなどを使えば簡単に動きのある演出プログラムを作成することができますが、ユニバースが増えれば増えるほどコントローラーの金額も上がってきてしまうので、インスタレーションや建築に使うような常設タイプのDMXプログラムは、Node-REDを使って組むことができれば便利です。
引き続き、CASEを増やしていきます。