Ryosuke_Kino が 2024年01月30日05時52分17秒 に編集
コメント無し
タイトルの変更
Spresenseと超音波距離センサを用いたゆる楽器の作成
Spresenseと超音波距離センサを用いて、ゆる楽器を作成してみた
タグの変更
HC-SR04
ライセンスの変更
(CC0 1+) Creative Commons Public Domain Dedication version 1.0 or later
本文の変更
# はじめに
ああああ
世の中には有名なものからそうでないものまで実にさまざまな楽器があります。その数は打楽器だけで**1100を超える**ほどだと言います。民族楽器などを数に含めると、もはや正確な楽器の種類がいくつになるのか誰にもわかりません。 多くの楽器は習熟に**多大な練習**が必要です。そのため、[チャレンジド](https://www.prop.or.jp/about/challenged.html)の方や楽器に馴染みのない人にとって、演奏は難しかったり、あまり楽しくなかったりすることが多々あります。
今回、研究室の活動としてチャレンジドのお子さん2名とそれぞれのご家族をパートナーとしてお迎えして、インクルーシブな楽器として「ゆる楽器」の制作を行いました。 「ゆる楽器」とは、「ゆるい」と「楽器」を重ね合わせた言葉です。大きな特徴として、簡単な動作で音が鳴り`誰でもすぐに弾けて、誰とでもすぐに合奏できる楽器`であることが挙げられます。 ## 制作のパートナーさんについて 今回のゆる楽器の制作に協力してくださったパートナーさんは、それぞれ~~~
# コンセプト
ああああ
誰でも音を鳴らせることを考えた時に、手を振ったり足を振ったり、近づいたり離れたりといった日常の何気ない動作から音に繋げられるのではないかと考えました。 そこで、超音波センサーを用いて距離を測り、測定した距離に応じた音階を鳴らして光るゆる楽器を、**「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までの物体の距離を接触せずに測定可能。|
|Anycubic MEGA X|Anycubic社の3Dプリンター。本体部分の印刷に使用。|
|Creality Ender 5 S1 |Creality社の3Dプリンター。本体部分の印刷に使用。|
|PLAフィラメント|3Dプリンタ用の樹脂素材。本体部分の印刷に使用。| |ExtraBASS SRS-XB01|Sonyが発売している有線接続可能なワイヤレススピーカー。| |AUX3.5ミリステレオケーブル|両端が3.5ミリのミニプラグであるAUXケーブル。spresenseとSRS-XB01の接続に使用。|
|その他|ブレッドボード、ジャンパ線 etc...|
# 仕組み
Distance Soundの仕組みは大きく次の3つからなります。
1:本体に手や脚などをかざすことで、超音波センサー(HC-SR04)から本体から対象までの距離を取得する。 2:取得した距離に応じて、出力する色と音程が決定される。 3:超音波センサー(HC-SR04)が有効な距離を出力する限り、対応した色、音を出力し続ける。
以下に仕組みを図示します。 ![仕組み](https://camo.elchika.com/4a874849e0e36d81d06fdad04aa6a2da79cbc236/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33396233643531622d616233302d346630642d613330612d6264386164396331333036392f35363164303638612d393163662d346366632d616136322d633066346565376363303431/) また、超音波センサーで取得した距離に応じた音程と光を以下に図示します。 ![光と音と距離の関係図](https://camo.elchika.com/29b387ab0c65b28ea6e5cbe448d2c2f4b6b82e68/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33396233643531622d616233302d346630642d613330612d6264386164396331333036392f36383539383639302d333335662d343064392d626662662d363461313537386362376562/) また、回路図は以下のようになります。 ![回路図](https://camo.elchika.com/1148a49b0d1c7c21b959da1221a6c6e8d1dc3288/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33396233643531622d616233302d346630642d613330612d6264386164396331333036392f31623738363663392d373736632d343931322d623765362d656661323033316462646330/) 今回実装したソースコードは記事の最後に記述しています。 # デモ動画 実際に動作させている様子です。 〜〜〜 # 今後の展望 ## パートナーさんからのフィードバック 制作段階でパートナーさんに中間発表の形で見てもらった際に、次のようなフィードバックをいただきました。 【感想】 - 人を呼ぶためのブザーにもできそう。 - 手が使える子も使えない子も遊べるような楽器はとてもよいと思う。 - 手を近づけていくことで音が鳴る体験ができる点は良さそう。 【改善案】 - 音階や音の違いを感覚的に伝えることが出来たらよりよくなりそう。 - 音程の違いより音そのものが変わるほうが面白そう。 - 録音した音源が使えると遊びに幅が出て楽しそう。 ## # 終わりに aaaa
# プログラム LEDテープを利用するためのライブラリ「[SpresenseNeoPixel-master](https://github.com/hideakitai/SpresenseNeoPixel)」が必要
```arduino:
```arduino:Spersenseソースコード
#include <Audio.h> #include <Arduino.h> #include <SpresenseNeoPixel.h> //超音波センサー
#define trigPin 8 //超音波センサーで使用するピン #define echoPin 9 //超音波センサーで使用するピン
#define echoPin 8 //超音波センサーで使用するピン #define trigPin 9 //超音波センサーで使用するピン
#define baserange 40 //mm #define range 40 //mm #define firstline 20 //mm #define endline baserange + range * 8
#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
#define VOLUME -20 //音量設定 : -90~0 (db)
//音量設定 : -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) // 音の設定 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);
delayMicroseconds(10); //超音波センサーの起動に必要な間隙
digitalWrite(trigPin, LOW); duration = pulseIn(echoPin, HIGH);
distance = (duration / 2) / 29.1 * 10.0; //超音波センサで取得した距離(mm)
distance = (duration / 2) / 29.1 * 10.0; //超音波センサーで取得した距離(mm)
if (distance < firstline + baserange && beforeloop != DO) {
if (distance < firstline + range && beforeloop != DO) {
theAudio->setBeep(1, VOLUME, DO); hue = 0.0; // 赤色に設定 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 + baserange + range) && beforeloop != RE) {
} else if (distance <= (firstline + range *2) && beforeloop != RE) {
theAudio->setBeep(1, VOLUME, RE); hue = 0.083; // 橙色に設定 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 + baserange + range * 2) && beforeloop != MI) {
} else if (distance <= (firstline + range * 3) && beforeloop != MI) {
theAudio->setBeep(1, VOLUME, MI); hue = 0.083 * 2.0; // 黄色に設定 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 + baserange + range * 3) && beforeloop != FA) {
} else if (distance <= (firstline + range * 4) && beforeloop != FA) {
theAudio->setBeep(1, VOLUME, FA); hue = 0.083 * 4.0; // 緑色に設定 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 + baserange + range * 4) && beforeloop != SO) {
} else if (distance <= (firstline + range * 5) && beforeloop != SO) {
theAudio->setBeep(1, VOLUME, SO); hue = 0.083 * 5.0; // 水色に設定 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 + baserange + range * 5) && beforeloop != RA) {
} else if (distance <= (firstline + range * 6) && beforeloop != RA) {
theAudio->setBeep(1, VOLUME, RA); hue = 0.083 * 7.0; // 青色に設定 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 + baserange + range * 6) && beforeloop != SI) {
} else if (distance <= (firstline + range * 7) && beforeloop != SI) {
theAudio->setBeep(1, VOLUME, SI); hue = 0.083 * 9.0; // 紫色に設定 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 + baserange + range * 7) && beforeloop != HDO) {
} else if (distance <= (firstline + range * 8) && beforeloop != HDO) {
theAudio->setBeep(1, VOLUME, HDO); hue = 0.083 * 11.0; // マゼンタ色に設定 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"); // 範囲外
Serial.println("Out of range");
theAudio->setBeep(0, 0, 0); // 音量を0に
hue = 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を点灯
neopixel.show(); // LEDを消灯
beforeloop = OUT; } }
// HSV->RGB / RGB->HSV 変換 // https://gist.github.com/postspectacular/2a4a8db092011c6743a7
// 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; } ```
# デモ動画 〜〜〜 # 課題 〜〜〜 # 終わりに # 参考文献