Spresense 色で奏でる楽器《《Colorful Sun》》
背景
世の中には色とりどりな景色が広がっています。
我々が生活している日本には海があり、山があり、街があり、そこには数えきれない生き物がいます。景色とはその時その瞬間にしか味わうことができない儚いものです。
そこで。 。 。
景色、色を"音"として表現したいと思い、色で奏でる楽器《《Colorful Sun》》の制作しようと思いました!!
どんな人でも簡単に演奏ができるデザイン設計になっています!
みんなで景色を奏でましょう!!
パートナー様について
このプロジェクトでは2組の障がいのあるお子さんを持つご家庭の方々に協力して頂いております。フィールドワークを通じて健常者との社会的な隔離が課題となっていることが明らかになりました。この課題に対処し、ハンディキャップを感じずに、共に演奏することができるゆる楽器の開発に取り組むことにしました。
用意したものなど
名称 | 概要 |
---|---|
Spresenseメインボード | Arduino互換ボードコンピュータ |
Spresense拡張ボード | microSDスロットやヘッドフォンジャック等様々なインターフェースが使えるようにするもの |
Adventure 3 Pro | FLASHFORGE製の3Dプリンター 樹脂筐体の印刷に使用 |
PLAフィラメント | 樹脂筐体の材料 |
ネジ | 直径2mmのネジ:4本 |
アクティブスピーカー | 3.5mmオーディオジャックの入力ができるもの |
リチウムポリマー電池 | 軽量の充電式バッテリー |
昇圧モジュール | リチウムポリマー電池とUSBを繋ぐもの |
制作環境
・MacBook Air(BigSur 11.7.10)
・Arduino IDE
・Neural Network Console
仕組み
1.カメラから任意の画像を数秒ごとに取得します
2.取得した画像はSpresenseを経由して学習済みデータに認識させます
3.認識した結果から色が判定され、それに対応する音が決定されます
4.決定された音はスピーカーから出力されます
機械学習
機械学習において色を認識させるためソニー独自のAIツールNeural Network Consoleを活用しました。
具体的な目標は、4色(赤、黄、青、緑)の判別です。事前にそれぞれの色に関する約400枚の画像データを収集しました。これらのデータを元に構造自動探索機能を使用して学習を行い特定のネットワーク構造を採用しました。
しかし現段階では正答率が50%ほどであるため、今後の調整や改善が必要です。
工作
この楽器のコンセプトは 色を音に変換する ことです。色を認識するためには光が不可欠な要素であるため、光を照らしてくれる太陽をモチーフにしたデザインを採用しました。
Fusion360を用いて筐体の設計を行いました。裏面から簡単にSpresenseを挿入できるような構造にしました。筐体はネジを用いて蓋で閉じることが可能です。また使用する際の疲れを軽減するため、筐体のてっぺんに紐を通せる穴を設計しました。
サポーター様から寄せられた意見により、筐体の円周を囲む棘が尖っており、怪我をする可能性があるという指摘がありました。このフィードバックに応じて棘の先端を丸めるなどして安全性を向上させました。
プロトタイピング動画
オズの魔法使い法によるプロトタイピング動画
*音は映像に後付けしています。
工夫点
触ってみたいと思ってもらえるようなデザインに注力を注ぎました。
また楽器らしい雰囲気を醸し出すために、音符や楽譜の記号をデザインに取り入れ、独自の音楽要素を加えました。屋外での利用を考慮し、電力供給に電池を採用することで、手軽に使用できるような設計に重点を置きました。
今後の課題
色の認識と音の発音
現在の色認識では認識できる色の数が限られているため、これを増やしてさらに多様な音を発音できるように改善が必要です。
機械学習の精度向上
現在使用している機械学習モデルの正答率が低いため、アルゴリズムやデータセットの改善などを通じて、正確性を向上させる必要があります。
筐体の軽量化
筐体がやや重いため、製品の使い勝手向上のためにも軽量化を目指すことが重要だと思います。
外での利用を考慮
屋外での使用を前提としているため、スピーカーを内蔵することで、外部環境でも効果的に音を発信できるように検討します。
特定の景色に対する音の発生
最終目標は特定の景色に応じて音を鳴らすことです。このため、現在の機能を向上させ、より緻密で効果的な音響の操作を実現することを目指します。
Spresenseへの実装
機能を実現するためにSpresenseへの実装を目指します。
プログラム
Spresense_code
#include <Camera.h>
#include "Adafruit_ILI9341.h"
#include <DNNRT.h>
#include <SDHCI.h>
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define OFFSET_X (104)
#define OFFSET_Y (0)
#define CLIP_WIDTH (112)
#define CLIP_HEIGHT (224)
#define DNN_WIDTH (28)
#define DNN_HEIGHT (28)
#define BEEP_PIN 8 // ビープ音のためのピン
SDClass SD;
DNNRT dnnrt;
DNNVariable input(DNN_WIDTH*DNN_HEIGHT);
const char label[4] = {'0','1','2','3'};//0:赤,1:青,2:黄,3:緑
void playTone(int note) {
switch(note) {
case 0: // ド
tone(BEEP_PIN, 262, 100); // 262Hzで100ミリ秒
break;
case 1: // レ
tone(BEEP_PIN, 294, 100); // 294Hzで100ミリ秒
break;
case 2: // ミ
tone(BEEP_PIN, 330, 100); // 330Hzで100ミリ秒
break;
case 3: // ファ
tone(BEEP_PIN, 349, 100); // 349Hzで100ミリ秒
break;
}
delay(100); // 音を100ミリ秒鳴らした後に次の処理に移る
}
void CamCB(CamImage img) {
if (!img.isAvailable()) {
Serial.println("Image is not available. Try again");
return;
}
// カメラ画像の切り抜きと縮小
CamImage small;
CamErr err = img.clipAndResizeImageByHW(small, OFFSET_X, OFFSET_Y, OFFSET_X + CLIP_WIDTH - 1, OFFSET_Y + CLIP_HEIGHT - 1, DNN_WIDTH, DNN_HEIGHT);
if (!small.isAvailable()){
putStringOnLcd("Clip and Resize Error:" + String(err), ILI9341_RED);
return;
}
// 認識用モノクロ画像を設定
uint16_t* imgbuf = (uint16_t*)small.getImgBuff();
float *dnnbuf = input.data();
for (int n = 0; n < DNN_HEIGHT * DNN_WIDTH; ++n) {
dnnbuf[n] = (float)(((imgbuf[n] & 0xf000) >> 8) | ((imgbuf[n] & 0x00f0) >> 4)) / 255.;
}
// 推論の実行
dnnrt.inputVariable(input, 0);
dnnrt.forward();
DNNVariable output = dnnrt.outputVariable(0);
int index = output.maxIndex();
// 推論結果の表示
String gStrResult;
if (index < 11) {
gStrResult = String(label[index]) + String(":") + String(output[index]);
Serial.println(gStrResult);
if (label[index] >= '0' && label[index] <= '3') {
playTone(label[index] - '0'); // 数字に対応する音を鳴らす
}
} else {
gStrResult = String("Error");
}
// 推論結果のディスプレイ表示
img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
display.drawRGBBitmap(0, 0, (uint16_t*)img.getImgBuff(), 320, 224);
putStringOnLcd(gStrResult, ILI9341_YELLOW);
}
void putStringOnLcd(String str, uint16_t color) {
display.fillScreen(ILI9341_BLACK);
display.setTextColor(color);
display.setTextSize(2);
display.setCursor(0, 0);
display.println(str);
}
void setup() {
Serial.begin(115200);
// SDカードの挿入待ち
while (!SD.begin()) {
putStringOnLcd("Insert SD card", ILI9341_RED);
}
// SDカードにある学習済モデルの読み込み
File nnbfile = SD.open("model.nnb");
// 学習済モデルでDNNRTを開始
int ret = dnnrt.begin(nnbfile);
if (ret < 0) {
putStringOnLcd("dnnrt.begin failed" + String(ret), ILI9341_RED);
return;
}
display.begin();
display.setRotation(3);
pinMode(BEEP_PIN, OUTPUT); // ビープ音のピンを出力として設定
theCamera.begin();
theCamera.startStreaming(true, CamCB);
}
void loop() { }
-
Nakajima_Haruto
さんが
2024/01/26
に
編集
をしました。
(メッセージ: 初版)
-
Nakajima_Haruto
さんが
2024/01/26
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/28
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/29
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/30
に
編集
をしました。
-
Nakajima_Haruto
さんが
2024/01/31
に
編集
をしました。
ログインしてコメントを投稿する