編集履歴一覧に戻る
Genkiのアイコン画像

Genki が 2022年09月26日06時04分32秒 に編集

初版

タイトルの変更

+

誰でも和音演奏ができるゆる楽器 傘コード

タグの変更

+

SPRESENSE

+

T1-1942SB

+

BMI160

+

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

製作品

本文の変更

+

**チーム名** ふーぎー **概要** みんなが一度は触れたことのある「傘」によって音楽を奏でるゆる楽器です。 演奏しない時は「閉じて」小さくなり、演奏する時は大きく「開く」ことで演奏前と演奏中の楽器のビジュアルが大きく変化するという傘の持つ特徴を活かした楽器となっています。 傘を開くことでスイッチがオンになり、傾け方に応じた和音が鳴り、華やかな演奏を体験できます。 制御については傘に加速度・ジャイロセンサーを取り付け、その値から傘の傾き方向や大きさを算出し、その値に応じた音を鳴らす仕組みとなっています。 ダイアトニックコードを採用することでおおよその楽曲の演奏に対応しており、小さな子でも馴染みのある傘の形をしたゆる楽器は雨の日を楽しい演奏の時間に変えます。 **部品** **_________________________________________________________________________________________________________________________** | 部品名 | 個数(個) | 価格 (円) | 販売元 | |:---:|:---:|:---:|:---:| | spresense | 1 | 500 |Sony| | T1-1942SB | 1 | 3806 | Tangband | | BMI160-P280 | 1 | 1980 |SWITCH SCIENCE| | SAM2625 | 1 | - |UdaDensi| | SS-5GL2 | 1 | 398 |Omron Electronics| | IFD-216 | 1 | - |IFUDO| | 傘 | 1 | 500 |3COINS| **回路図** **_________________________________________________________________________________________________________________________** ![キャプションを入力できます](https://camo.elchika.com/14ba767850d9c849139660547f51d0f18d6620f6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34343534643362382d626230642d343834612d613737382d3030326238633937343164642f64323135646363612d633035372d343938632d396336312d346337353735643639353130/) ↓演奏動画 https://youtu.be/dbyB-02GIMA ↓演奏している様子 ![キャプションを入力できます](https://camo.elchika.com/83aff73a6f4a4f65893a629894b49226ce10061b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34343534643362382d626230642d343834612d613737382d3030326238633937343164642f35356436613263652d393139322d343864622d383237382d613462643562326332323431/) ↓spresenseに組み込んでいる様子 ![キャプションを入力できます](https://camo.elchika.com/b83d900c2095e6a4a06892ca238af607249771a9/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34343534643362382d626230642d343834612d613737382d3030326238633937343164642f31306633633032642d343234652d343564302d396134632d323534303764666539656430/) ↓畳んでいる状態 ![キャプションを入力できます](https://camo.elchika.com/81b57174b6f68fff56d0aebad0a1ef5defa9ca3b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34343534643362382d626230642d343834612d613737382d3030326238633937343164642f34343932613639352d333537302d346636382d383038352d663435356163313033356461/) ↓傘を開いた時のみ音を鳴らすためのスイッチ ![キャプションを入力できます](https://camo.elchika.com/5229468ae0d0534fce6e9283253b31fca166387d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34343534643362382d626230642d343834612d613737382d3030326238633937343164642f38616137363965612d613133362d343139642d626232662d383234643962633335353238/) ソースコード **_________________________________________________________________________________________________________________________** ```arduino:Spresense用ソースコード #include <math.h> #include <MadgwickAHRS.h> #include <BMI160Gen.h> #define PI 3.141592653589793 Madgwick madgwick; // Madgwickフィルタ unsigned long lastMs = 0; // 周期計測用 unsigned int selected_num = 0; // Switch const int ONOFF_PIN = 24; int onoff_old = 1; // Speaker unsigned int MIM_VOLUME = 150; unsigned int MAX_VOLUME = 150; float MIN_INCLINATION = 0.5; // 傾き0.5以上で出力 float MAX_INCLINATION = 0.9; // Code int chord_table[6][3]={ {60,64,67}, // C {62,65,69}, // Dm {64,67,71}, // Em {65,69,72}, // F {67,71,74}, // G {69,72,76} // Am }; void setup() { // Switch =========== pinMode(ONOFF_PIN, INPUT_PULLUP ); // Speaker =========== Serial2.begin(31250); pinMode(LED3, OUTPUT); //send2bytes(0xC0,78); // 音色選択 くちぶえ send2bytes(0xC0,19); // 音色選択 チャーチオルガン send3bytes(0xB0, 7,127); // vol delay(100); // ====================== // Sensor =========== Serial.begin(115200); while (!Serial); // 6軸センサ初期化 BMI160.begin(); BMI160.setGyroRate(100); BMI160.setAccelerometerRate(100); BMI160.setGyroRange(250);// ジャイロのレンジ設定 BMI160.setAccelerometerRange(2);// 加速度のレンジ設定 delay(100); // Madgwickフィルタの初期化 madgwick.begin(100); //100Hz (10msec周期) // 周期計測用 lastMs = micros(); // ====================== } void loop() { int onoff = digitalRead( ONOFF_PIN ); if (onoff == 1) { send_exp(0); return; } //if (onoff_old == 1) { // 起動音 // chord_sel(0); // send_exp(100); // delay(500); //} //onoff_old = onoff; // 10msec周期で処理 float dt = (micros() - lastMs) / 1000000.0; lastMs = micros(); // 6軸センサ読み出し int ax, ay, az, gx, gy, gz; BMI160.readMotionSensor(ax, ay, az, gx, gy, gz); // 加速度値を分解能で割って加速度[G]に変換する float acc_omg = float(0x7FFF) / 2; float acc_x = ax / acc_omg; // LSB = 2G / 2^15 = 1/16384 G float acc_y = ay / acc_omg; float acc_z = az / acc_omg; // 角速度値を分解能で割って角速度[deg/sec]に変換する float gyro_omg = float(0x7FFF) / 250; float gyro_x = gx / gyro_omg; // LSB = 2000deg/sec / 2^15 = 1/16.384 deg/sec float gyro_y = gy / gyro_omg; float gyro_z = gz / gyro_omg; // Madgwickフィルタの計算 madgwick.updateIMU(gyro_x, gyro_y, gyro_z, acc_x, acc_y, acc_z); // オイラー角の取得 float roll = madgwick.getRoll(); float pitch = madgwick.getPitch(); float yaw = madgwick.getYaw(); // ラジアン角取得 float roll_r = madgwick.getRollRadians(); float pitch_r = madgwick.getPitchRadians(); float yaw_r = madgwick.getYawRadians(); float angle = atan(roll_r / pitch_r); float inclination = sqrt(roll_r * roll_r + pitch_r * pitch_r); unsigned int selecting_num = selected_num; // コード選択 if (pitch_r <= 0) { if (angle < 5 * PI / 12.0 && angle > 3 * PI / 12.0) { selecting_num = 1; } else if (angle < PI / 12.0 && angle > -1 * PI / 12.0) { selecting_num = 2; } else if (angle < -3 * PI / 12.0 && angle > -5 * PI / 12.0) { selecting_num = 3; } } else if (pitch_r > 0) { if (angle < 5 * PI / 12.0 && angle > 3 * PI / 12.0) { selecting_num = 4; } else if (angle < PI / 12.0 && angle > -1 * PI / 12.0) { selecting_num = 5; } else if (angle < -3 * PI / 12.0 && angle > -5 * PI / 12.0) { selecting_num = 6; } } else { // なし } if (selected_num != selecting_num) { chord_sel(selecting_num); // コード発音 selected_num = selecting_num; } // 音量調整 int volume = 0; if (inclination > MIN_INCLINATION) { volume = MAX_VOLUME * ((inclination - MIN_INCLINATION) / (MAX_INCLINATION - MIN_INCLINATION)); } send_exp(volume); // Debug Serial.print(roll); Serial.print(","); Serial.print(pitch); Serial.print(","); Serial.print(yaw); Serial.print(","); Serial.print(angle); Serial.print(","); Serial.print(selected_num); Serial.print(","); Serial.print(inclination); Serial.println(); delay(10); // 10msec周期のためここで10msecdelay } // MIDIメッセージ 3bytes送る void send3bytes(int sts, int data1, int data2){ Serial2.write(sts); Serial2.write(data1); Serial2.write(data2); } // MIDIメッセージ 2bytes送る void send2bytes(int sts, int data){ Serial2.write(sts); Serial2.write(data); } // num:0 音を消す(note off) // num:1-6 番号に応じたコードを発音 void chord_sel(int num){ send3bytes(0xB0,123,0); // all note off if((1<=num)&&(num<=6)){ int velo = 127; //int capo = 0; int capo = 4; int n = num-1; send3bytes(0x90,capo+chord_table[n][0],velo); send3bytes(0x90,capo+chord_table[n][1],velo); send3bytes(0x90,capo+chord_table[n][2],velo); } } void send_exp(int val){ send3bytes(0xB0,11, val); // exp } ``` ``` arduino:Processingによる角度のシミュレート用ソースコード import processing.serial.*; Serial myPort; String arduinoPort = "/dev/cu.usbserial-143240"; // Required to modify float []data = new float [6]; void setup() { lights(); size(300, 300, P3D); myPort = new Serial(this, arduinoPort, 115200); } void draw() { background(230); if (data[5] > 0.75) { fill(0, 0, 255); } else { fill(255, 255, 255); } translate(width / 2, height / 2, 0); rotateZ(radians(data[1])); rotateX(radians(-data[0])); //rotateY(radians(-data[2])); int size = 10; box(20 * size, 1 * size, 15 * size); translate(0, -4 * size, 0); textSize(30); fill(0); text("num: " + int(data[4]) + "\nvalue: " + data[5], -10, -20); } void serialEvent(Serial p) { String inString = myPort.readStringUntil('\n'); if (inString != null) { inString = trim(inString); data = float(split(inString, ',')); println(data); } } ```