shimodashのアイコン画像
shimodash 2022年09月25日作成 © Apache-2.0
製作品 製作品 閲覧数 652
shimodash 2022年09月25日作成 © Apache-2.0 製作品 製作品 閲覧数 652

SPRESENSEでお菓子の箱がトロンボーンに⁉

SPRESENSEでお菓子の箱がトロンボーンに⁉

はじめに

SPRSENSEのAudio出力機能と最近リリースされたライブラリを使って
ゆる楽器⁉のような物を作ってみました。
測距センサとの組み合わせで「簡単に楽器を開発する」はじめの一歩的な
位置づけで参考にして頂けたらと思います。

材料

  • SPRESENSEメインボード
  • SPRESENSE拡張ボード
  • SDカード
  • 測距センサ VL53L0X
  • スピーカー 及び 音声ケーブル

接続図

接続はシンプルで

  1. メインボード、拡張ボードをスタックします
  2. メインボード上のI2CとVL530Xを接続します
  3. 音声ケーブルとスピーカを接続します

キャプションを入力できます

キャプションを入力できます

プログラム

以下に公開されている
https://github.com/SonySemiconductorSolutions/ssih-music
のサンプルスケッチのButtonDrumを修正しています。
センサの入力を"ただ” VL53L0Xに変更したものです。

VL53L0Xのライブラリはライブラリのダウンロードでこちらを使っています。
キャプションを入力できます

サンプルプログラム

/* * SPDX-License-Identifier: (Apache-2.0 OR LGPL-2.1-or-later) * * Copyright 2022 Sony Semiconductor Solutions Corporation */ #ifndef ARDUINO_ARCH_SPRESENSE #error "Board selection is wrong!!" #endif #ifdef SUBCORE #error "Core selection is wrong!!" #endif #include <MemoryUtil.h> #include <SDSink.h> //sensor #include <Wire.h> #include <VL53L0X.h> VL53L0X sensor; // this file names are deifned middle C (60) as C4 const SDSink::Item table[12] = { {60, "SawLpf/60_C4.wav"}, // C4 {61, "SawLpf/61_C#4.wav"}, // C#4 {62, "SawLpf/62_D4.wav"}, // D4 {63, "SawLpf/63_D#4.wav"}, // D#4 {64, "SawLpf/64_E4.wav"}, // E4 {65, "SawLpf/65_F4.wav"}, // F4 {66, "SawLpf/66_F#4.wav"}, // F#4 {67, "SawLpf/67_G4.wav"}, // G4 {68, "SawLpf/68_G#4.wav"}, // G#4 {69, "SawLpf/69_A4.wav"}, // A4 {70, "SawLpf/70_A#4.wav"}, // A#4 {71, "SawLpf/71_B4.wav"} // B4 }; SDSink inst(table, 12); int selector = 0; int button4 = HIGH; int button5 = HIGH; int button6 = HIGH; void setup() { // init built-in I/O Serial.begin(115200); pinMode(LED0, OUTPUT); pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); // init buttons pinMode(PIN_D04, INPUT_PULLUP); pinMode(PIN_D05, INPUT_PULLUP); pinMode(PIN_D06, INPUT_PULLUP); // initialize memory pool initMemoryPools(); createStaticPools(MEM_LAYOUT_RECORDINGPLAYER); // setup instrument if (!inst.begin()) { Serial.println("ERROR: init error."); while (true) { delay(1000); } } Serial.println("Ready to play ButtonDrum"); // VL53L0X setup // Serial.begin(9600); Wire.begin(); sensor.setTimeout(500); if (!sensor.init()) { Serial.println("Failed to detect and initialize sensor!"); while (1) {} } // Start continuous back-to-back mode (take readings as // fast as possible). To use continuous timed mode // instead, provide a desired inter-measurement period in // ms (e.g. sensor.startContinuous(100)). sensor.startContinuous(); } int note1 = INVALID_NOTE_NUMBER; void loop() { Serial.print(sensor.readRangeContinuousMillimeters()); if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); } Serial.println(); int distance_input = sensor.readRangeContinuousMillimeters(); //測定している距離が一定の距離に入ったら音を出すようにする。以下は 100mm未満 if (distance_input < 100 ) { //距離を12等分したものを割って、小数点が切り捨てられるようにし60に加算 //値が72になるとエラーし暴走してしまうので注意 note1 = 60 + int(float(distance_input / (100 / 12.0)-0.5)); Serial.println(note1); inst.sendNoteOn(note1, DEFAULT_VELOCITY, DEFAULT_CHANNEL); } else { inst.sendNoteOff(note1, DEFAULT_VELOCITY, DEFAULT_CHANNEL); } // run instrument inst.update(); }

動作

ここに動画が表示されます

最後に

SPRESENSEはカメラの搭載できるので
お菓子の箱を認識して音色や音階を変化する距離を
自動変更できたら、面白いかなと思います。
すみません、そこまで作り込めなかったのですが
アイデアの種として共有させて頂けたらと思います。

箱に応じた機能変更

1
shimodashのアイコン画像
会社員をしています。 Myms-techという活動名で、子供向けの電子工作ワークショップを しています。 URLは https://shimodash.github.io/Myms-tech facebookは https://www.facebook.com/mymstech twitterは https://twitter.com/shimodash_home もしよかったらSNSフォローを ※発言は個人的なものです。
  • shimodash さんが 2022/09/25 に 編集 をしました。 (メッセージ: 初版)
  • Opening
    shimodashのアイコン画像 shimodash 2022/12/04

    https://github.com/SonySemiconductorSolutions/ssih-music
    のバージョンが0.9.0にアップデートされたのと、
    同じ音階の時は音が延長されるように、修正をしました。

    あと、お菓子の箱の距離では、、、音階変更がシビアなので
    距離を測るレンジを3倍の30cmに変更しています。

    ソースコードはこちらになります。

    /*
     * SPDX-License-Identifier: (Apache-2.0 OR LGPL-2.1-or-later)
     *
     * Copyright 2022 Sony Semiconductor Solutions Corporation
     */
    
    #ifndef ARDUINO_ARCH_SPRESENSE
    #error "Board selection is wrong!!"
    #endif
    #ifdef SUBCORE
    #error "Core selection is wrong!!"
    #endif
    
    #include <MemoryUtil.h>
    
    #include <SDSink.h>
    
    //sensor
    #include <Wire.h>
    #include <VL53L0X.h>
    
    VL53L0X sensor;
    
    
    // this file names are deifned middle C (60) as C4
    const SDSink::Item table[12] = {
        {60, "SawLpf/60_C4.wav"},   // C4
        {61, "SawLpf/61_C#4.wav"},  // C#4
        {62, "SawLpf/62_D4.wav"},   // D4
        {63, "SawLpf/63_D#4.wav"},  // D#4
        {64, "SawLpf/64_E4.wav"},   // E4
        {65, "SawLpf/65_F4.wav"},   // F4
        {66, "SawLpf/66_F#4.wav"},  // F#4
        {67, "SawLpf/67_G4.wav"},   // G4
        {68, "SawLpf/68_G#4.wav"},  // G#4
        {69, "SawLpf/69_A4.wav"},   // A4
        {70, "SawLpf/70_A#4.wav"},  // A#4
        {71, "SawLpf/71_B4.wav"}    // B4
    };
    SDSink inst(table, 12);
    
    int selector = 0;
    
    int button4 = HIGH;
    int button5 = HIGH;
    int button6 = HIGH;
    
    void setup() {
        // init built-in I/O
        Serial.begin(115200);
        pinMode(LED0, OUTPUT);
        pinMode(LED1, OUTPUT);
        pinMode(LED2, OUTPUT);
        pinMode(LED3, OUTPUT);
    
        // init buttons
        pinMode(PIN_D04, INPUT_PULLUP);
        pinMode(PIN_D05, INPUT_PULLUP);
        pinMode(PIN_D06, INPUT_PULLUP);
    
        // initialize memory pool
    //    initMemoryPools();
    //    createStaticPools(MEM_LAYOUT_RECORDINGPLAYER);
    
        // setup instrument
        if (!inst.begin()) {
            Serial.println("ERROR: init error.");
            while (true) {
                delay(1000);
            }
        }
    
        Serial.println("Ready to play DistDrum");
    
    // VL53L0X setup
    //  Serial.begin(9600);
       Wire.begin();
    
        sensor.setTimeout(500);
       if (!sensor.init())
       {
        Serial.println("Failed to detect and initialize sensor!");
        while (1) {}
        }
    
      // Start continuous back-to-back mode (take readings as
      // fast as possible).  To use continuous timed mode
      // instead, provide a desired inter-measurement period in
      // ms (e.g. sensor.startContinuous(100)).
        sensor.startContinuous();
    
    
    //      inst.sendNoteOn(61, DEFAULT_VELOCITY, DEFAULT_CHANNEL);
    //      inst.update();
    //      delay(1000);
    
    }
    
    int note1 = INVALID_NOTE_NUMBER;
    int pre_note1 = INVALID_NOTE_NUMBER;
    
    void loop() {
    
    //  Serial.print(sensor.readRangeContinuousMillimeters());
      if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
    //  Serial.println();
    
      int distance_input = sensor.readRangeContinuousMillimeters();
    
    //測定している距離が一定の距離に入ったら音を出すようにする。以下は 300mm未満 
      if (distance_input < 300 ) {
        //距離を12等分したものを割って、小数点が切り捨てられるようにし60に加算
        //値が72になるとエラーし暴走してしまうので注意
        note1 = 60 + int(float(distance_input / (300 / 12.0)-0.5));
          
        Serial.println(note1);
        if(note1 != pre_note1){
          inst.sendNoteOff(pre_note1, DEFAULT_VELOCITY, DEFAULT_CHANNEL);
          inst.sendNoteOn(note1, DEFAULT_VELOCITY, DEFAULT_CHANNEL);
        }
        pre_note1 = note1;
      }
    
        inst.update();
    }
    0 件の返信が折りたたまれています
ログインしてコメントを投稿する