1. ex-01
みんな笑顔 pic.twitter.com/8V9mVpzEES
— tueks (@tueks3) May 5, 2022
2022/5/3~5に開催されていたSICF23 exhibition部門@スパイラルホールで展示を行ったex-01の技術記事を書きました。主にシーケンス回りを公開します。ハードウェア展示にすこしだけソフトを組み込むと、上動画のようにみんな笑顔になります。とっても楽しかったです!
【ex-01】
新作のBTワイヤレススピーカーです。見た目からは想像もできない強い音が鳴ります。今回はこちらの新作のデモをSICFで行いました。
【SICF】
SICFとは10年以上の歴史がある公募型アートフェスティバルで、若手クリエイターの発掘を目的としたイベントになります。
https://www.sicf.jp/about/
自分でやりたいと思って出展しましたが、バブルの頃から時代の最先端を象徴するスパイラルホールのイベントに自分が出ることに正直ビビりまくりでした。皆さん美大卒/在学中という方が多く、公募型美術展の中でも相当にレベルが高かったのではないかと思います。あろうことか電気エンジニアの私も紛れ込んでしまったわけです。。。
2.会場の風景
デザインの発想と分解ゾーン。左から右に行くに向かって物が完成していく様子を演出しました。 来場者から中身が見えることやアイデアノートの公開が反応よかったです。デザインアイデアノートを公開。お手に取ってご覧いただけます。 pic.twitter.com/KfLJiGz8Le
— tueks (@tueks3) May 5, 2022
メイン展示、ex-01のデモ音源再生の様子。古くからの友人のyuigot(@ygt_jpn)君にスピーカの特性を見ながら2曲書き下ろして頂き、小さい音量でも存分に響き渡る素敵なアンビエントで展示を彩りました。最終日だしちょいちょい公開してくぜ pic.twitter.com/bmsvBHYcWd
— tueks (@tueks3) May 5, 2022
キャプション。一番頑張ったといってもいいくらいデザインに気を使いました。wirelessの文字を間違ってwierlessとして発注していたためカッティングシートを人力補正しました泣
基板。みんなも基板のアートワーク気になるよね!訪れた方々にエンジニアアピールすることができました。
全体。フォントを合わせ、白基調の部屋にしたところ統一感のある素敵な空間になりました。
3.SICF事前準備
SICFは公募型美術展のため2月下旬までに審査資料を送る必要がありました。具体的には展示空間のイメージ図とアピール資料があります。私は絵が描けないので3DCADを2週間ほどで習得して展示空間図面を描きました(スゴイ‼)。所定の書式を無視して描いたのですが誠意を受け取っていただき、出展が決まった際は本当に嬉しかったです。
展示イメージ。CADで図面を書いておくと寸法が出るので設営がしやすかったです。
アピール資料の一部。本作品に込められた思いが描かれているので興味ある人は読んでみてください。
4. 展示用仕掛けの機能概要
展示にあたり2つの機能を付けました。以下2つの機能をArduino NANOを2つ使って作りました。これらの技術解説、コードが本記事のメインとなります。
1. 人がブースにいる間だけデモ音源を流す
超音波センサーを使って人を検知し、音楽を流します。超音波センサを普段は壁に向けて距離を測り、人が来た時に反射して検出距離が短くなったとき、または服に乱反射して検出距離が異常に長くなった時に音楽を流す信号を送る動作をしています。
2. キャプションを押すと萌え声による説明と共にex-01と来場者のスマホがBT接続可能になる
スイッチを押したときに割り込み制御が入るようにしました。本当はex-01のアンプ部にあたるBT-03のAUX端子を活用したかったのですが、相性が悪くハムノイズが消えない問題に悩まされたので、BT接続時と、萌え声&デモ音源再生時はリレーでパワーアンプの出力を切り替えるという手間がかかっています。
機械音ではなく萌え声で接続方法の説明をすることで興味を持ってBT接続してくれる方が沢山いました。(冒頭の動画参照)あずきうい(@_AZKUI_)さん、素敵なボイス提供ありがとうございました。
5.ハードウェアの接続
回路図を示します。Arduino NANOを2台で制御しています。一台(A1)は超音波センサに接続して距離を測り、もう一台(A2)はDFPlayerというモジュールに接続され、SDカードに保存した音楽を再生します。
デモ音源再生時はパワーアンプモジュールを使用し、BT接続時はリレーによって切り替えてBT-03を使用します。ペアリングモードにするためにBT-03のペアリングボタンをフォトカプラによって制御しています。
— tueks (@tueks3) April 26, 2022
試作風景。超やってる。超やってる pic.twitter.com/2oDwHW48RX
— tueks (@tueks3) April 28, 2022
最終的にはユニバーサル基板にはんだ付けして運搬に耐えられるようにしました。
あえて中身が見えるようにしています。
6.コード
コード1:超音波センサで距離を測る(回路図シンボルA1のコード)
参考:https://deviceplus.jp/arduino/entry016/
#define echoPin 10 // Echo Pin
#define trigPin 11 // Trigger Pin
double Duration = 0; //受信した間隔
double Distance = 0; //距離
int DistMin=100;//この距離(m)以下で信号出力
int DistMax=200;//この距離(m)以上で信号出力
void setup() {
Serial.begin(9600);//Arduino Unoは9600,ESPで試す場合はは115200
pinMode( echoPin, INPUT );
pinMode( trigPin, OUTPUT );
pinMode( 3, OUTPUT );
digitalWrite(3, LOW);
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite( trigPin, HIGH ); //超音波を出力
delayMicroseconds( 10 ); //
digitalWrite( trigPin, LOW );
Duration = pulseIn( echoPin, HIGH ); //センサからの入力
if (Duration > 0) {
Duration = Duration / 2; //往復距離を半分にする
Distance = Duration * 340 * 100 / 1000000; // 音速を340m/sに設定
Serial.print("Distance:");
Serial.print(Distance);
Serial.println(" cm");
if (Distance > DistMax) {
digitalWrite(3, HIGH);
delay(1000);
}
else if (Distance < DistMin) {
digitalWrite(3, HIGH);
delay(1000);
}
else if (Distance < 300) {
digitalWrite(3, LOW);
}
}
delay(500);//取得間隔1秒
}
全然難しいことはやっていないです。服に超音波が当たった際の測定距離バグを考慮して検出閾値を現地調整しました。
コード2:DFPlayerで音楽再生、BT-03の制御(回路図シンボルA2のコード)
参考:https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int volumeue);
int volume = 21; //Set volume volumeue. From 0 to 30
int voice_vol = 28;
int US_SENSORE = 7;
int EX01_OUT = 4;
int EX01_STATE = 6;
int RELAY = 5;
int num = 1;
volatile int state = LOW;
volatile int state2 = LOW;
void setup()
{
mySoftwareSerial.begin(9600);
Serial.begin(115200);
Serial.println();
Serial.println(F("DFRobot DFPlayer Mini Demo"));
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while (true);
}
Serial.println(F("DFPlayer Mini online."));
myDFPlayer.volume(volume); //Set volume volumeue. From 0 to 30
pinMode(EX01_OUT, OUTPUT);
pinMode(EX01_STATE, OUTPUT);
pinMode(RELAY, OUTPUT);
attachInterrupt(0, azukiui, RISING);//0 means digitalRead(2) is interrupu pin.
}
void loop()
{
if (myDFPlayer.available()) {
printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
//状態の読み取り、シリアル通信から確認
}
if (digitalRead(US_SENSORE) == HIGH & state2 == LOW ) {
state2 = HIGH;
myDFPlayer.play(num);
num = num + 1;
}
if (state == HIGH) {
myDFPlayer.volume(voice_vol);
myDFPlayer.play(5);
delay(21000);
digitalWrite(EX01_OUT, HIGH);
digitalWrite(EX01_STATE, HIGH);
digitalWrite(RELAY, HIGH);
delay(3000);
digitalWrite(RELAY, LOW);
delay(2000);
digitalWrite(EX01_OUT, LOW);
digitalWrite(EX01_STATE, LOW);
delay(18000);
digitalWrite(RELAY, HIGH);
delay(178000);
myDFPlayer.volume(29);
digitalWrite(EX01_OUT, HIGH);
digitalWrite(EX01_STATE, HIGH);
delay(2800);
digitalWrite(RELAY, LOW);
delay(1000);
digitalWrite(EX01_OUT, LOW);
digitalWrite(EX01_STATE, LOW);
delay(30000);
state = LOW;
myDFPlayer.volume(volume);
}
}
void printDetail(uint8_t type, int volumeue) {
switch (type) {
case TimeOut:
Serial.println(F("Time Out!"));
break;
case WrongStack:
Serial.println(F("Stack Wrong!"));
break;
case DFPlayerCardInserted:
Serial.println(F("Card Inserted!"));
break;
case DFPlayerCardRemoved:
Serial.println(F("Card Removed!"));
break;
case DFPlayerCardOnline:
Serial.println(F("Card Online!"));
break;
case DFPlayerPlayFinished:
Serial.print(F("Number:"));
Serial.print(volumeue);
delay(500);
Serial.println(F(" Play Finished!"));
state = LOW;
state2 = LOW;
if (num > 3) {
num = 1;
}
Serial.println(type);
break;
case DFPlayerError:
Serial.print(F("DFPlayerError:"));
switch (volumeue) {
case Busy:
Serial.println(F("Card not found"));
break;
case Sleeping:
Serial.println(F("Sleeping"));
break;
case SerialWrongStack:
Serial.println(F("Get Wrong Stack"));
break;
case CheckSumNotMatch:
Serial.println(F("Check Sum Not Match"));
break;
case FileIndexOut:
Serial.println(F("File Index Out of Bound"));
break;
case FileMismatch:
Serial.println(F("Cannot Find File"));
break;
case Advertise:
Serial.println(F("In Advertise"));
break;
default:
break;
}
break;
default:
break;
}
}
void azukiui() {
state = HIGH;
}
少々複雑です。特に3分間のBT接続のための萌え声案内ボイスとリレー切り替え&ペアリングスイッチ制御のタイミングはdelayでゴリ押ししました。RELAYとペアリングボタンを細かくON/OFFして機械と人の声のスムーズな連動を意識しました。また、超音波センサーが検知中があれば連続してデモ音源が流れ、キャプションスイッチが押された時の割り込み制御はDFplayerの音楽再生終了時のフラグとうまく組み合わせて実現できました。
7.終わりに
エンジニアの立場でSICFに出展し、多くの非エンジニアの方々にものがどうやってできているのか、そしてハードウェアで面白いことが出来ることを示せた点、そして「回路の事はよくわからないけど面白い!可愛い!デザインがいい!」と沢山の来場者に反応いただけたことがこれからの活動のモチベーションになりました。これからもハードウェアに興味を持ってもらえるような作品づくりや、より意匠性を高めたデザインを目指して精進します。
最後に、今回の展示では多くの友人の皆さまの協力なしでは実現できませんでした。
謝辞を掲載します。本当にありがとうございました。
tueks