Ryosuke_Kinoのアイコン画像
Ryosuke_Kino 2023年12月14日作成 (2024年01月31日更新) © CC0 1+
製作品 製作品 閲覧数 244
Ryosuke_Kino 2023年12月14日作成 (2024年01月31日更新) © CC0 1+ 製作品 製作品 閲覧数 244

Spresenseと超音波距離センサを用いて、ゆる楽器を作成してみた

Spresenseと超音波距離センサを用いて、ゆる楽器を作成してみた

はじめに

世の中には有名なものからそうでないものまで実にさまざまな楽器があります。その数は打楽器だけで1100を超えるほどだと言います。民族楽器などを数に含めると、もはや正確な楽器の種類がいくつになるのか誰にもわかりません。
 多くの楽器は習熟に多大な練習が必要です。そのため、障がい者の方や楽器に馴染みのない人にとって、演奏は難しかったり、あまり楽しくなかったりすることが多々あります。

今回、研究室の活動として障がい者のお子さん2名とそれぞれのご家族をパートナーとしてお迎えして、インクルーシブな楽器として「ゆる楽器」の制作を行いました。

「ゆる楽器」とは、世界ゆるミュージック協会が定めた「ゆるい」と「楽器」を重ね合わせた言葉です。大きな特徴として、簡単な動作で音が鳴り誰でもすぐに弾けて、誰とでもすぐに合奏できる楽器であることが挙げられます。

制作のパートナーさんについて

今回のゆる楽器の制作に協力してくださったパートナーさんは、それぞれどちらのお子さんも小学生で、常にバギーに乗って行動しているAさんと、声が出せないBさんの二人に協力してもらっています。この二人およびその親御さんとも意見を交換しながら、誰でも楽しむことができるメディア遊び、すなわち「ゆる楽器」を作ることが本プロジェクトの最終的な目標となっています。

開発の初期段階では実際に対面でリサーチを行い、実際の楽器やちょっとしたおもちゃなどさまざまな道具を用意してどんな音や物に興味があるのか調査し、その結果からどのような機能なら使いやすいと思ってもらえるのかを考えて今回の制作物を考案しました。開発の途中でもオンライン通話を通してフィードバックをいただき、制作の参考にさせていただきました。

コンセプト

パートナーさんとの交流を通して、誰でも音を鳴らせることを考えた時、手を振ったり足を振ったり、近づいたり離れたりといった日常の何気ない動作から音に繋げられるのではないかと考えました。
 そこで、超音波センサーを用いて距離を測り、測定した距離に応じた音階を鳴らして光るゆる楽器を、「Distance Sound」 として制作しました。

制作環境など

制作環境

  • MacBook Air (Sonoma 14.1)
  • Arduino IDE 2.2.1

用意したもの

名称 概要
Spresenseメインボード ローパワーでハイパフォーマンスなエッジコンピューティングが可能な、Sonyが開発したIoT向けボードコンピュータ。
Spresense拡張ボード spresenseメインボードにArduino Uno 互換のピンソケットを追加し、さらにmicroSDスロットやヘッドフォンジャック等様々なインターフェースが使えるようになるもの。
HC-SR04 SparkFun製の超音波距離センサモジュール。2cmから4mまでの物体の距離を接触せずに測定可能。
ExtraBASS SRS-XB01 Sonyが発売している有線接続可能なワイヤレススピーカー。
AUX3.5ミリステレオケーブル 両端が3.5ミリのミニプラグであるAUXケーブル。spresenseとSRS-XB01の接続に使用。
その他 ブレッドボード、ジャンパ線 etc...
工作機材 概要
Creality Ender 5 S1 Creality社の3Dプリンター。本体部分の印刷に使用。
PLAフィラメント 3Dプリンタ用の樹脂素材。本体部分の印刷に使用。

仕組み

Distance Soundの仕組みは大きく次の3つからなります。
1:本体に手や脚などをかざすことで、超音波センサー(HC-SR04)から本体から対象までの距離を取得する。
2:取得した距離に応じて、出力する色と音程が決定される。
3:超音波センサー(HC-SR04)が有効な距離を出力する限り、対応した色、音を出力し続ける。

以下に仕組みを図示します。

仕組み

また、超音波センサーで取得した距離に応じた音程と光を以下に図示します。

光と音と距離の関係図

また、配線図は以下のようになります。
配線図

今回実装したソースコードは記事の最後に記述しています。

工作

Distance Soundの筐体は3Dプリンターを用いて出力しました。3DデータはAutoDeskの提供している3D CADソフト、Fusion360を用いて制作しました。

3DCAD

出力中の様子

出力後

デモ動画

@youtube

パートナーさんからのフィードバック

制作段階でパートナーさんに中間発表の形で見てもらった際に、次のようなフィードバックをいただきました。
【感想】

  • 人を呼ぶためのブザーにもできそう。
  • 手が使える子も使えない子も遊べるような楽器はとてもよいと思う。
  • 手を近づけていくことで音が鳴る体験ができる点は良さそう。

【改善案】

  • 音階や音の違いを感覚的に伝えることが出来たらよりよくなりそう。
  • 音程の違いより音そのものが変わるほうが面白そう。
  • 録音した音源が使えると遊びに幅が出て楽しそう。

今後の展望

今のままではただの「音の出る光る箱」となってしまうため、外装を取り付ける形でDistance Soundに自由な形を持たせていきたいと思っています。

また、「多少遅延してもいいから色々な音色で実現できないものか」というパートナーさんからのフィードバックをいただいているので、Beep音以外も鳴らせるようにして現状の仕様と切り替えられるような仕組みを持たせたいと考えています。具体的に、手で握ることができるトリガーを用意し、握っている・握っていないを検出して切り替えるような仕組みを考えています。

終わりに

今回は、距離を検知して光る・鳴るゆる楽器、Distance Soundを試作しました。改良点は多く、特に重要なビジュアル面に取り組みきれていない点は気がかりではあります。しかし、超音波センサーに近づいたり離れたり、あるいは遮ったりすることによって変化する音の鳴り方とLEDテープライトの光り方によって、音だけでなく見て楽しめるものに仕上がっているのではないかと思います。
 パートナーさんからのフィードバックも参考にして改良を重ね、より良いものを目指していきたいと思います。

プログラム

LEDテープを利用するためのライブラリ「SpresenseNeoPixel-master」が必要です。
Beep()関数の仕様を「Spresense Arduino チュートリアル」から確認しました。

Spersenseソースコード

#include <Audio.h> #include <Arduino.h> #include <SpresenseNeoPixel.h> //超音波センサー #define echoPin 8 //超音波センサーで使用するピン #define trigPin 9 //超音波センサーで使用するピン #define range 40 //超音波センサーの認識幅設定(mm) #define firstline 20 //超音波センサーの認識下限に履かせる下駄(mm) #define endline baserange + range * 8 //超音波センサーの認識上限設定(mm) //Beep音の周波数設定 #define DO 262 #define RE 294 #define MI 330 #define FA 349 #define SO 392 #define RA 440 #define SI 494 #define HDO 523 #define OUT 0 //音量設定 : -90~0 (db) #define VOLUME -20 // LEDストラップの設定 const uint16_t PIN = 6; // データ用のピンを指定 const uint16_t NUM_PIXELS = 30; // 点灯させるLEDの数を指定 SpresenseNeoPixel<PIN, NUM_PIXELS> neopixel; int ledIndex = 0; // 色の設定 int col[3]; // RGBの値を格納する配列 float hue = 0.0; // 色相(0.0〜1.0) float brightness = 0.5; // 明るさ(0.0〜1.0) float saturation = 1.0; // 彩度(0.0〜1.0) #define brightness = bright; // 音の設定 AudioClass* theAudio; void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); theAudio = AudioClass::getInstance(); theAudio->begin(); //puts("initialization Audio Library"); theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, 0, 0); neopixel.clear(); neopixel.framerate(40); Serial.println("Start"); } void loop() { long duration, distance, beforeloop; digitalWrite(trigPin, HIGH); delayMicroseconds(10); //超音波センサーの起動に必要な間隙 digitalWrite(trigPin, LOW); duration = pulseIn(echoPin, HIGH); distance = (duration / 2) / 29.1 * 10.0; //超音波センサーで取得した距離(mm) if (distance < firstline + range && beforeloop != DO) { theAudio->setBeep(1, VOLUME, DO); hue = 0.0; // 赤色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = DO; } else if (distance <= (firstline + range *2) && beforeloop != RE) { theAudio->setBeep(1, VOLUME, RE); hue = 0.083; // 橙色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = RE; } else if (distance <= (firstline + range * 3) && beforeloop != MI) { theAudio->setBeep(1, VOLUME, MI); hue = 0.083 * 2.0; // 黄色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = MI; } else if (distance <= (firstline + range * 4) && beforeloop != FA) { theAudio->setBeep(1, VOLUME, FA); hue = 0.083 * 4.0; // 緑色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = FA; } else if (distance <= (firstline + range * 5) && beforeloop != SO) { theAudio->setBeep(1, VOLUME, SO); hue = 0.083 * 5.0; // 水色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = SO; } else if (distance <= (firstline + range * 6) && beforeloop != RA) { theAudio->setBeep(1, VOLUME, RA); hue = 0.083 * 7.0; // 青色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = RA; } else if (distance <= (firstline + range * 7) && beforeloop != SI) { theAudio->setBeep(1, VOLUME, SI); hue = 0.083 * 9.0; // 紫色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = SI; } else if (distance <= (firstline + range * 8) && beforeloop != HDO) { theAudio->setBeep(1, VOLUME, HDO); hue = 0.083 * 11.0; // マゼンタ色に設定 brightness = bright; hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを点灯 beforeloop = HDO; } // センサーの認識範囲外の場合 if ((distance < firstline || endline <= distance) && beforeloop != HDO) { Serial.println("Out of range"); theAudio->setBeep(0, 0, 0); // 音量を0に hue = 0.0; // 無色に設定 (= 消灯) brightness = 0.0; // 明るさを0に設定 hsv2rgb(hue, saturation, brightness, col); // HSVで指定した色を、color[]に格納 neopixel.set(col[0], col[1], col[2]); // LEDの色をRGBで指定 neopixel.show(); // LEDを消灯 beforeloop = OUT; } } // HSV->RGB 変換 //https://gist.github.com/postspectacular/2a4a8db092011c6743a7 float fract(float x) { return x - int(x); } float mix(float a, float b, float t) { return a + (b - a) * t; } int* hsv2rgb(float h, float s, float b, int* rgb) { float rgbf[3]; rgbf[0] = b * mix(1.0, constrain(abs(fract(h + 1.0) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s); rgbf[1] = b * mix(1.0, constrain(abs(fract(h + 0.6666666) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s); rgbf[2] = b * mix(1.0, constrain(abs(fract(h + 0.3333333) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s); rgb[0] = rgbf[0] * 255; rgb[1] = rgbf[1] * 255; rgb[2] = rgbf[2] * 255; return rgb; }
ログインしてコメントを投稿する