#実装
LEDパターンの制御 pic.twitter.com/8uuUXgosau
— マコてん (@juin9_mako) February 16, 2019
#準備
ハードウェア
-Arduino Uno * 5台
https://www.switch-science.com/catalog/789/
-NeoPixels 1m * 4本, 2m * 4本
https://www.switch-science.com/catalog/1399/
-細径3心並列線(必要な分だけ)
https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=4A8P-MDLY
-ACアダプター * 4本
https://www.amazon.co.jp/gp/product/B075132TRK/ref=ppx_yo_dt_b_asin_title_o00__o00_s01?ie=UTF8&psc=1
ソフトウェア
-Max8 (8.0.0)
-Arduino (1.8.8)
-ArduinoOsc (0.2.1)
-Adafruit NeoPixel (1.1.8)
#プログラムの概要
1.ArduinoOSC
Max-MSPとArduino間でSerial通信を行い、Maxからの値をArduinoに受け渡します。ファイルの保存場所は注意が必要で、jsonやjsファイルも同じファイルに入れておく必要があります。
2.I2C通信
master_writerとslave_receiverの関係のI2C通信を用いて、Arduino1台(master)の指令をArduino4台(slave)に渡します。
上記の黒、黄色、緑のワイヤーがI2C通信になります。masterにはパソコンから電源供給を行い、slave一つ一つは5V2AのACアダプターを接続します。
1台のArduinoから1mのNeoPixelsと2mのNeoPixelsの二つに指令を与えます。5V電力とGNDはそれぞれ1mのテープと2mのテープに分岐させ接続します。
#プログラムの流れ
Max-MSP -> Serial通信 -> Arduino -> I2C通信 -> Arduino -> NeoPixels制御
Maxで受け取った数値をArduino(master) -> Arduino(slave)へ受け渡していくプログラムになっています。最終的には数値によってLEDの点灯パターンが変化します。それぞれのArduinoには前もってプログラムを書き込んでおき、ACアダプターから電源をもらって稼働させます。
#プログラム
###Max
MaxからSerial通信で"/light1 0"の形でArduinoにメッセージを送ります。たまに調子が悪い時があり、その時はserialオブジェクト(serial d 9600)のportのアルファベットを一度変更してから行うと良さそうです。
###Arduino(master)
Maxからラベル付けされて来る数値を各SlaveのArduinoへ送ります。
/light1 -> slave1(I2C通信のDevice_Id1)
/light2 -> slave2(I2C通信のDevice_Id2)
/light3 -> slave3(I2C通信のDevice_Id3)
/light4 -> slave4(I2C通信のDevice_Id4)
#include <ArduinoOSC.h>
#include <Wire.h>
// Wire ID
#define DEVICE_ID1 1
#define DEVICE_ID2 2
#define DEVICE_ID3 3
#define DEVICE_ID4 4
OscSerial osc;
void setup() {
Serial.begin(9600);
osc.attach(Serial);
osc.subscribe("/light1", callbackLight1);
osc.subscribe("/light2", callbackLight2);
osc.subscribe("/light3", callbackLight3);
osc.subscribe("/light4", callbackLight4);
Wire.begin();
}
void loop() {
osc.parse();
}
void callbackLight1(OscMessage& m){
Wire.beginTransmission(DEVICE_ID1);
Wire.write(m.getArgAsInt32(0));
Wire.endTransmission();
}
void callbackLight2(OscMessage& m){
Wire.beginTransmission(DEVICE_ID2);
Wire.write(m.getArgAsInt32(0));
Wire.endTransmission();
}
void callbackLight3(OscMessage& m){
Wire.beginTransmission(DEVICE_ID3);
Wire.write(m.getArgAsInt32(0));
Wire.endTransmission();
}
void callbackLight4(OscMessage& m){
Wire.beginTransmission(DEVICE_ID4);
Wire.write(m.getArgAsInt32(0));
Wire.endTransmission();
}
###Arduino(slave)
masterから送られた値によってLEDの光るパターンを変更するプログラムです。1mと2mのLEDテープを9つのパターンで点灯させています。1mのLEDテープは6ピンで、2mのLEDテープは7ピンに接続をします。
slave2の場合はWire.begin(1)がWire.begin(2)になります。slave3、slave4も同じ要領で考えてください。
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN1 6
#define PIN2 7
#define NUMPIXELS1 60
#define NUMPIXELS2 120
Adafruit_NeoPixel pixels1 = Adafruit_NeoPixel(NUMPIXELS1, PIN1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels2 = Adafruit_NeoPixel(NUMPIXELS2, PIN2, NEO_GRB + NEO_KHZ800);
int pattern = 0;
int delayval = 20;
void setup() {
Wire.begin(1);
Wire.onReceive(receiveEvent);
Serial.begin(9600);
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
pixels1.begin();
pixels2.begin();
pixels1.setBrightness(100);
pixels2.setBrightness(100);
pixels1.show();
pixels2.show();
}
void receiveEvent(int howMany) {
pattern = Wire.read();
Serial.print(pattern);
}
void loop() {
switch (pattern) {
case 0:
//No Light
noLight(pixels1.Color(0, 0, 0), pixels2.Color(0, 0, 0), delayval);
break;
case 1:
//dualStraight
straight(pixels1.Color(255, 255, 255), pixels2.Color(255, 255, 255), delayval);
break;
case 2:
//Short Straight, Long No Light
straight(pixels1.Color(255, 255, 255), pixels2.Color(0, 0, 0), delayval);
break;
case 3:
//Short No Light, Long Straight
straight(pixels1.Color(0, 0, 0), pixels2.Color(255, 255, 255), delayval);
break;
case 4:
//dualReverse
reverse(pixels1.Color(255, 255, 255), pixels2.Color(255, 255, 255), delayval);
break;
case 5:
//Short Reverse, Long No Light
reverse(pixels1.Color(255, 255, 255), pixels2.Color(0, 0, 0), delayval);
break;
case 6:
//Short No Light, Long Reverse
reverse(pixels1.Color(0, 0, 0), pixels2.Color(255, 255, 255), delayval);
break;
case 7:
//Short Straight, Long Reverse
sSt_lRe(pixels1.Color(255, 255, 255), pixels2.Color(255, 255, 255), delayval);
break;
case 8:
//Short Reverse, Long Straight
sRe_lSt(pixels1.Color(255, 255, 255), pixels2.Color(255, 255, 255), delayval);
default:
break;
}
}
void straight(const uint32_t& c1, const uint32_t& c2, uint8_t wait) {
for (int j = 0; j < 10; j++) {
for (int q = 0; q < 3; q++) {
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i + q, c1);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i + q, c2);
}
pixels1.show();
pixels2.show();
delay(wait);
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i + q, 0);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i + q, 0);
}
}
}
}
void reverse(const uint32_t& c1, const uint32_t& c2, const uint8_t& wait) {
for (int j = 0; j < 10; j++) {
for (int q = 0; q < 3; q++) {
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i - q, c1);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i - q, c2);
}
pixels1.show();
pixels2.show();
delay(wait);
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i - q, 0);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i - q, 0);
}
}
}
}
void sSt_lRe(const uint32_t& c1, const uint32_t& c2, const uint8_t& wait) {
for (int j = 0; j < 10; j++) {
for (int q = 0; q < 3; q++) {
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i + q, c1);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i - q, c2);
}
pixels1.show();
pixels2.show();
delay(wait);
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i + q, 0);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i - q, 0);
}
}
}
}
void sRe_lSt(const uint32_t& c1, const uint32_t& c2, const uint8_t& wait) {
for (int j = 0; j < 10; j++) {
for (int q = 0; q < 3; q++) {
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i - q, c1);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i + q, c2);
}
pixels1.show();
pixels2.show();
delay(wait);
for (uint16_t i = 0; i < pixels1.numPixels(); i = i + 3) {
pixels1.setPixelColor(i - q, 0);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = i + 3) {
pixels2.setPixelColor(i + q, 0);
}
}
}
}
void noLight(const uint32_t& c1, const uint32_t& c2, const uint8_t& wait) {
for (uint16_t i = 0; i < pixels1.numPixels(); i = ++i) {
pixels1.setPixelColor(i, 0);
}
for (uint16_t i = 0; i < pixels2.numPixels(); i = ++i) {
pixels2.setPixelColor(i, 0);
}
pixels1.show();
pixels2.show();
delay(wait);
}
#参考文献
ArduinoOSCの説明についてはこちらを参考にしました。(本家)
-https://qiita.com/hideakitai/items/f50f99e38b520a0ace37
Qiitaの記事からのアップデートもありましたので、下記のGithubもチェックしてください。
-https://github.com/hideakitai/ArduinoOSC
Node.jsのインストール方法等(brewインストール済みの場合)
-https://qiita.com/jaxx2104/items/2277cec77850f2d83c7a
I2Cの説明についてはこちらの方を参考にしました。
- https://qiita.com/MergeCells/items/20c3c1a0adfb222a19cd
- https://qiita.com/hikoalpha/items/7bf563ee286a59bfd2f4
NeoPixelsの購入方法や説明についてはこちらに記載されています。
-https://www.switch-science.com/catalog/1399/
#おわりに
質問やアドバイスがありましたら、ぜひコメントをください。