工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduino Dueでマスターする音声認識と音声合成

必要な部品と材料

Arduino Due ×1
SparkFun エレクトレットマイク ブレークアウト ×1
SparkFun モノオーディオアンプ ブレークアウト ×1
スピーカー: 0.25W, 8Ω ×1
ブレッドボード(汎用) ×1
5mm赤色LED ×3
抵抗 330Ω ×3
ジャンパーワイヤー(汎用) ×1

必要な工具と機器

アプリとオンラインサービス

このプロジェクトについて

前回のプロジェクトでは、ArduinoとBitVoicer Serverを使っていくつかのLEDを制御する方法を紹介しました。今回はさらに一歩進めて、Arduino Dueの内蔵DAC(デジタル-アナログ変換器)を使用して音声合成も行います。Arduino Dueをお持ちでない場合は他のArduinoボードでも可能ですが、外部DACとそれを操作する追加コードが必要になります(BVSSpeakerライブラリでは対応できません)。

以下の動画では、Arduinoが短い曲を再生し、LEDがピアノの鍵盤のように点滅する様子が見られます。私のピアノスキルはお察しください(笑)。LEDは実際のド、レ、ミの鍵盤と同じ順序・タイミングで点滅するので、ピアノがあればLEDに合わせて同じ曲を演奏できます。これはかつて存在した老舗小売店(Mappin)のジングルです。

音声コマンドからLED動作と音声合成への変換フロー

  1. SparkFunエレクトレットマイクブレークアウトで音声波を取得・増幅
  2. 増幅信号をArduinoのADC(アナログ-デジタル変換器)でデジタル化・バッファリング
  3. 音声サンプルをシリアルポート経由でBitVoicer Serverにストリーミング
  4. BitVoicer Serverで音声ストリームを処理し、音声を認識
  5. 認識された音声を事前定義コマンドにマッピングし、Arduinoに送信。音声合成コマンドの場合、BitVoicer Serverが音声ストリームを準備してArduinoに送信
  6. Arduinoがコマンドを識別し適切なアクション実行。音声ストリーム受信時はBVSSpeakerクラスにキューイングし、DueのDACとDMAで再生
  7. SparkFunモノオーディオアンプでDAC信号を増幅し、8Ωスピーカーを駆動

材料リストと概算コスト

ステップ1: 配線

以下の写真のようにArduinoとブレッドボードに部品を配線します。スピーカーは振動が大きいため、下に小さなゴムを敷かないと音質が大幅に低下します。

Arduino Dueでマスターする音声認識と音声合成
Arduino Dueでマスターする音声認識と音声合成
Arduino Dueでマスターする音声認識と音声合成
Arduino Dueでマスターする音声認識と音声合成

前回プロジェクトからの小さく重要な違い:ほとんどのArduinoは5V動作ですが、Dueは3.3V動作です。SparkFunエレクトレットブレークアウトは3.3Vでより良い結果が得られたため、5V Arduinoボードを使用する場合は3.3VピンとAREFピンの間にジャンパーを追加することを推奨します。Dueはすでに3.3Vアナログリファレンスを使用しているため、AREFピンへのジャンパーは不要です。実際、DueのAREFピンは抵抗ブリッジ経由でマイコンに接続されており、AREFを使用するには基板上の抵抗BR1を取り外す必要があります。

ステップ2: Arduinoへのコードアップロード

以下のコードをArduinoにアップロードします。便宜上、Arduinoスケッチはこの投稿下部の添付ファイルセクションにもあります。アップロード前に、BitVoicer ServerライブラリをArduino IDEに正しくインストールしてください(.zipライブラリのインポート)。

Arduinoスケッチ: BVS_Demo2.ino

このスケッチは7つの主要部分で構成されます:

ステップ3: BitVoicer Serverソリューションオブジェクトのインポート

BitVoicer ServerをArduino連携用に設定します。主要ソリューションオブジェクトは4つ:Locations(場所)、Devices(デバイス)、BinaryData(バイナリデータ)、Voice Schemas(音声スキーマ)。

音声スキーマの一例「play a little song」には2つのコマンドを含む:

  1. 次のコマンドが音声ストリームであることを示すバイトを送信。ArduinoはLED演奏を開始しながら音声受信待機
  2. 私が自分で録音したピアノジングルを音声ソースとして設定。BitVoicer Serverは8-bitモノラルPCM(8000サンプル/秒)のみサポート。音声ファイル変換には オンライン変換ツール 推奨

以下のファイルから本プロジェクトで使用したすべてのソリューションオブジェクトをインポート可能(ソリューションオブジェクトのインポート参照):

ステップ4: 結び

以上で完成です!すべてを起動すれば、動画と同じことができます。

前回同様、BitVoicer Server ManagerでArduinoデバイスを有効化して音声認識を開始。有効化されると、Arduinoが利用可能な音声認識エンジンを検出し、BitVoicer Serverへ音声ストリーミングを開始。今回はBitVoicer ServerからArduinoへ音声ストリームが送信される際、ArduinoのRX LEDがかなり激しく点滅するのがわかります。

次回プロジェクトではさらに野心的に、1台のArduinoにWiFi通信を追加し、他の2台のArduinoをまとめて音声制御する計画です。何かゲームのような仕組みを考えています。アイデア募集中!

コード

Arduino Sketch (Arduino)

#include <BVSP.h>
#include <BVSMic.h>
#include <BVSSpeaker.h>
#include <DAC.h>

// 音声入力ピン
#define BVSM_AUDIO_INPUT 7

// LEDピン
#define RED_LED_PIN 6
#define YELLOW_LED_PIN 9
#define GREEN_LED_PIN 10

// BVSP.begin パラメータ用定数
const unsigned long STATUS_REQUEST_TIMEOUT = 3000;
const unsigned long STATUS_REQUEST_INTERVAL = 4000;

// バッファサイズ
const int MIC_BUFFER_SIZE = 64;
const int SPEAKER_BUFFER_SIZE = 128;
const int RECEIVE_BUFFER_SIZE = 2;

// グローバルインスタンス
BVSP bvsp = BVSP();
BVSMic bvsm = BVSMic();
BVSSpeaker bvss = BVSSpeaker();

// バッファ
byte micBuffer[MIC_BUFFER_SIZE];
byte speakerBuffer[SPEAKER_BUFFER_SIZE];
byte receiveBuffer[RECEIVE_BUFFER_SIZE]; // Byte 0 = ピン番号, Byte 1 = ピン値

// LEDノート再生制御用
bool playLEDNotes = false;
unsigned int playStartTime = 0;

void setup() {
  pinMode(RED_LED_PIN, OUTPUT);
  pinMode(YELLOW_LED_PIN, OUTPUT);
  pinMode(GREEN_LED_PIN, OUTPUT);
  digitalWrite(RED_LED_PIN, LOW);
  digitalWrite(YELLOW_LED_PIN, LOW);
  digitalWrite(GREEN_LED_PIN, LOW);
  
  Serial.begin(115200);
  
  bvsp.begin(Serial, STATUS_REQUEST_TIMEOUT, STATUS_REQUEST_INTERVAL);
  bvsp.frameReceived = BVSP_frameReceived;
  bvsp.modeChanged = BVSP_modeChanged;
  bvsp.streamReceived = BVSP_streamReceived;
  
  bvsm.begin();
  bvss.begin(DAC);
}

void loop() {
  bvsp.keepAlive();
  bvsp.receive();
  
  if (bvsp.isSREAvailable()) {
    if (!bvsm.isRecording) {
      bvsm.setAudioInput(BVSM_AUDIO_INPUT, DEFAULT);
      bvsm.startRecording();
    }
    if (bvsm.available) {
      if (bvsp.inboundMode == FRAMED_MODE)
        bvsp.setInboundMode(STREAM_MODE);
      int bytesRead = bvsm.read(micBuffer, MIC_BUFFER_SIZE);
      bvsp.sendStream(micBuffer, bytesRead);
    }
  } else {
    if (bvsm.isRecording)
      bvsm.stopRecording();
  }
  
  bvss.play();
  
  if (playLEDNotes)
    playNextLEDNote();
}

void BVSP_frameReceived(byte dataType, int payloadSize) {
  if (dataType == DATA_TYPE_BINARY) {
    if (bvsp.getReceivedBytes(receiveBuffer, RECEIVE_BUFFER_SIZE) == RECEIVE_BUFFER_SIZE) {
      analogWrite(receiveBuffer[0], receiveBuffer[1]);
    }
  } else if (dataType == DATA_TYPE_BYTE) {
    if (bvsp.getReceivedByte() == 255) {
      playLEDNotes = true;
      playStartTime = millis();
    }
  }
}

void BVSP_modeChanged() {
  if (bvsp.outboundMode == FRAMED_MODE)
    bvss.finishPlaying();
}

void BVSP_streamReceived(int size) {
  int bytesRead = bvsp.getReceivedStream(speakerBuffer, SPEAKER_BUFFER_SIZE);
  bvss.enqueue(speakerBuffer, bytesRead);
}

void playNextLEDNote() {
  unsigned long elapsed = millis() - playStartTime;
  allLEDsOff();
  
  if (elapsed >= 11500) {
    analogWrite(RED_LED_PIN, 0);
    playLEDNotes = false;
  } else if (elapsed >= 9900) analogWrite(RED_LED_PIN, 255);     // C
  else if (elapsed >= 9370) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 8900) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 8610) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 8230) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 7970) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 7470) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 6760) analogWrite(GREEN_LED_PIN, 255);     // E
  else if (elapsed >= 6350) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 5880) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 5560) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 5180) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 4890) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 4420) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 3810) analogWrite(GREEN_LED_PIN, 255);     // E
  else if (elapsed >= 3420) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 2930) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 2560) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 2200) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 1930) analogWrite(YELLOW_LED_PIN, 255);    // D
  else if (elapsed >= 1470) analogWrite(RED_LED_PIN, 255);       // C
  else if (elapsed >= 1000) analogWrite(GREEN_LED_PIN, 255);     // E
}

void allLEDsOff() {
  analogWrite(RED_LED_PIN, 0);
  analogWrite(YELLOW_LED_PIN, 0);
  analogWrite(GREEN_LED_PIN, 0);
}

回路図

Arduino Dueでマスターする音声認識と音声合成

製造プロセス

  1. Python連携で信頼性向上: Arduino RFID勤怠管理システム
  2. DHT11温湿度センサーで作る温度アラート – LEDとピエゾブザーで視覚/聴覚通知
  3. NeoPixelリングとArduinoで作るインタラクティブジャイロスコープLEDディスプレイ
  4. Arduino Dueと3.2インチTFTで作る温度監視付きリアルタイムクロック
  5. ArduinoとAndroidでRoomba Create 2をリモコン操作 ─ Bluetooth経由のステップバイステップガイド
  6. ArduinoとNokia 5110ディスプレイで自作電圧計:ステップバイステップガイド
  7. Arduino & MPU6050:SG90 & MG996Rサーボの精密制御
  8. u-blox LEA-6H 02 GPSモジュール: Arduino & Python 統合ガイド
  9. DHT11 と Blynk で温湿度をリアルタイム監視する Arduino チュートリアル
  10. Arduino Unoと1Sheeldで作る4x4x4 LEDキューブ – インタラクティブLEDプロジェクト
  11. Arduino GPS+TFTタッチシールドで作るリアルタイム位置表示デバイス