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

RGBライトを制御するためのTinyMLキーワード検出

コンポーネントと消耗品

>
Arduino Nano 33 BLE Sense
× 1

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

>
Edge Impulse Studio

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

前提

エッジでの機械学習は、従来のコードと比較してはるかに少ないプログラミングと論理フローチャートで「インテリジェント」なタスクを実行できるデバイスを作成するのに非常に役立ちます。そのため、特定の単語を認識し、発言内容に基づいてタスクを実行できる最先端のキーワード検出を組み込みたいと考えました。

ハードウェア

このプロジェクトには、Arduino Nano 33 BLESenseという1つのコンポーネントしかありません。実際の魔法は機械学習モデルで発生します。 Arduino Nano 33 BLE Senseには、マイク、9軸IMU、環境センサー、ジェスチャー/近接/色/環境光センサー(APDS-9960)などのセンサーが満載です。その上のマイクロコントローラは、64MHzで動作し、1MBのフラッシュメモリと256KBのRAMを含むnRF52840です。このプロジェクトでは、オンボードRGBLEDを使用して現在の色を表示します。

<図> <図>

エッジインパルスの設定

まず、Edge Impulseで新しいプロジェクトを作成し、次にEdge ImpulseCLIツールをインストールしました。これを行う方法の詳細については、インストール手順ページにアクセスしてください。これにより、Arduino Nanoはクラウドサービスと通信して、コマンドを受信し、センサーデータを自動的に送信できます。最新のEdgeImpulseファームウェアをダウンロードし、リセットボタンをダブルクリックしてブートローダーモードにすることでボードにフラッシュしました。次に、 flash_windows.bat を実行しました それを転送します。

<図>

コマンドプロンプトで edge-impulse-daemon を実行しました ウィザードに従って設定しました。これで、Nanoがプロジェクトのデバイスリストに表示され、トレーニング/テストデータセットの一部としてサンプルを取得してアップロードできるようになります。

<図>

サンプルの収集

機械学習モデルのトレーニングには、データとそのかなりの量が必要です。 RGBLEDストリップに次のモードが必要でした。

  • オン
  • オフ

モードごとに約1分の音が出て、1〜2秒間隔で単語を繰り返し言って分割しました。

<図> <図>

しかし、これらのサンプルを持っているだけでは十分ではありません。バックグラウンドノイズや他の単語が誤った読みを与えるからです。ありがたいことに、Edge Impulseは、ノイズと「不明な」単語の事前に作成されたデータセットをすでに提供しているため、「既存のデータのアップロード」ツールを使用して、これらのオーディオファイルをトレーニングデータにアップロードしました。

<図>

最後に、データセットのバランスを取り直して、データのトレーニングとテストにそれぞれ推奨される80〜20の分割を行いました。

<図>

モデルのトレーニング

1時間のトレーニングデータとたくさんのラベルで武装したので、モデルをトレーニングする時が来ました。私が設計したインパルスは、ウィンドウサイズが1秒でウィンドウが500ms増加する時系列データとしてオーディオを取り込みます。次に、MFCCブロックを通過してKerasニューラルネットワークブロックに入ります。

<図>

MFCCブロックを使用すると、周波数を視覚的に示すスペクトログラムとともに、オーディオの処理方法を構成できます。

<図>

ニューラルネットワークの設定はほとんどデフォルトのままにしましたが、いくつかの変更も加えました。最初に、最小信頼しきい値を0.80から0.70に変更し、追加のノイズとマスキング時間帯域の形でデータ拡張を少し追加しました。これにより、NNはより多様なデータを処理できるため、モデルの過剰適合を回避できます。

<図>

Arduino Nano 33 BLESenseへの展開

Arduino Nano 33 BLE Senseは、音声を継続的にサンプリングし、キーワードの1つが話されたかどうかを検出する常時オンのマイクとして機能します。見つかったら、キーワードは目的の色をデコードするために使用されるインデックスに変換されます。 onまたはoffキーワードの場合、LEDは黒またはライトグレーに設定されます。

モデルをライブラリとしてダウンロードしてArduinoIDEに追加し、コードをコンパイルしてNanoにフラッシュしました。

<図>

コード

  • RGBLEDKeywordDetection
RGBLEDKeywordDetection C / C ++
 / * Edge ImpulseArduinoの例* Copyright(c)2020 EdgeImpulse Inc. * *このソフトウェアおよび関連するドキュメントファイル(「ソフトウェア」)のコピーを取得するすべての人に*許可が無料で付与されます。ソフトウェアのコピーを使用、コピー、変更、マージ、公開、配布、サブライセンス、および/または販売する権利を含むがこれらに限定されない、ソフトウェアでの取引、およびソフトウェアの所有者を許可すること。 * *上記の著作権通知およびこの許可通知は、ソフトウェアのすべてのコピーまたは実質的な部分に含まれるものとします。 * *ソフトウェアは「現状有姿」で提供され、商品性の保証を含むがこれに限定されない、明示または黙示を問わず、いかなる種類の保証もありません。*特定の目的および非侵害への適合性。いかなる場合も、*作者または著作権所有者は、本ソフトウェアまたは使用またはその他に起因または関連して、契約、不法行為、またはその他の行為にかかわらず、いかなる請求、損害、またはその他の責任についても責任を負わないものとします。 *ソフトウェアでの取引。 * ///ターゲットのメモリが制限されている場合は、このマクロを削除して10Kを節約しますRAM#define EIDSP_QUANTIZE_FILTERBANK 0 / ***モデルウィンドウごとのスライス数を定義します。例えば。 1000ミリ秒のモデルウィンドウ*モデルウィンドウあたりのスライス数は4に設定されています。結果としてスライスサイズは250ミリ秒になります。 *詳細:https://docs.edgeimpulse.com/docs/continuous-audio-sampling * /#define EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW 3 / *含まれるもの------------------- --------------------------------------------- * /#include  #include  #include 
 #define CONFIDENCE_THRESHOLD 0.7static const uint32_tcolors [] ={0x00ff0000、0x0000ff00、0x000000ff}; //赤、緑、青のアクション{LED_ON =1、LED_OFF =0、LED_RED =2、LED_GREEN =3、LED_BLUE =4、NONE =5};列挙関数{CHANGE_LED_ON_OFF =0、CHANGE_LED_COLOR =1、CHANGE_LED_NONE =2}; static const uint8_t redPin =22、greenPin =23、bluePin =24; const std ::map  actionToFunctionMap ={{LED_ON、CHANGE_LED_ON_OFF}、{LED_OFF、CHANGE_LED_ON_OFF}、{LED_RED、CHANGE_LED_COLOR}、{LED_GREEN、CHANGE_ }、{LED_BLUE、CHANGE_LED_COLOR}、{NONE、CHANGE_LED_NONE}}; const std ::map  labelToActionMap ={{"on"、LED_ON}、{"off"、LED_OFF}、{"red" 、LED_RED}、{"green"、LED_GREEN}、{"blue"、LED_BLUE}、{"unknown"、NONE}、{"noise"、NONE}}; / **オーディオバッファー、ポインター、セレクター* / typedef struct {署名された短い* buffers [2]; unsigned char buf_select; unsigned char buf_ready; unsigned int buf_count; unsigned int n_samples;} inference_t; static inference_t inference; static bool record_ready =false; static signed short * sampleBuffer; static bool debug_nn =false; //これをtrueに設定すると、例が表示されます。生のsignalstaticintから生成された機能print_results =-(EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW); / ** * @briefArduinoセットアップ関数* / void setup(){//セットアップコードをここに配置して、1回実行します:Serial.begin(115200); Serial.println( "エッジインパルス推論"); setPixelColor(0xaeae00); //推論設定の概要(model_metadata.hから)ei_printf( "推論設定:\ n"); ei_printf( "\ tInterval:%。2fms。\ n"、(float)EI_CLASSIFIER_INTERVAL_MS); ei_printf( "\ tフレームサイズ:%d \ n"、EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE); ei_printf( "\ tサンプルの長さ:%dms。\ n"、EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16); ei_printf( "\ tクラスの数:%d \ n"、sizeof(ei_classifier_inferencing_categories)/ sizeof(ei_classifier_inferencing_categories [0])); run_classifier_init(); if(microphone_inference_start(EI_CLASSIFIER_SLICE_SIZE)==false){ei_printf( "ERR:オーディオサンプリングのセットアップに失敗しました\ r \ n");戻る; }} / ** * @briefArduinoのメイン関数。推論ループを実行します。 * / void loop(){bool m =Mike_inference_record(); if(!m){ei_printf( "ERR:オーディオの録音に失敗しました... \ n");戻る; } signal_tシグナル; signal.total_length =EI_CLASSIFIER_SLICE_SIZE; signal.get_data =&microphone_audio_signal_get_data; ei_impulse_result_t result ={0}; EI_IMPULSE_ERROR r =run_classifier_continuous(&signal、&result、debug_nn); if(r!=EI_IMPULSE_OK){ei_printf( "ERR:分類子(%d)の実行に失敗しました\ n"、r);戻る; } if(++ print_results> =(EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW)){//予測を出力ei_printf( "Predictions"); ei_printf( "(DSP:%d ms。、分類:%d ms。、異常:%d ms。)"、result.timing.dsp、result.timing.classification、result.timing.anomaly); ei_printf( ":\ n"); for(size_t ix =0; ix  CONFIDENCE_THRESHOLD){performAction(result.classification [ix] .label); } ei_printf( "%s:%。5f \ n"、result.classification [ix] .label、result.classification [ix] .value); } #if EI_CLASSIFIER_HAS_ANOMALY ==1 ei_printf( "異常スコア:%。3f \ n"、result.anomaly);#endif print_results =0; }} void setPixelColor(uint32_t c){analogWrite(redPin、255-(c>> 16)); analogWrite(greenPin、255-((c>> 8)&0xff)); analogWrite(bluePin、255-(c&0xff));} void PerformAction(const char * ClassificationLabel){auto itr =labelToActionMap.find(classificationLabel); if(itr ==labelToActionMap.end())return; auto itr2 =actionToFunctionMap.find(itr-> second); if(itr2 ==actionToFunctionMap.end())return; switch(itr2-> second){case CHANGE_LED_ON_OFF:setPixelColor((itr-> second)?0x5c5c5c:0x00);壊す;ケースCHANGE_LED_COLOR:{uint32_t pixelColor =色[itr->秒-2]; setPixelColor(pixelColor); } 壊す;ケースCHANGE_LED_NONE:ブレーク; }} / ** * @brief Printf関数はvsnprintfを使用し、Arduinoシリアルを使用して出力します* * @param [in] format変数引数リスト* / void ei_printf(const char * format、...){static char print_buf [1024] ={0}; va_list args; va_start(args、format); int r =vsnprintf(print_buf、sizeof(print_buf)、format、args); va_end(args); if(r> 0){Serial.write(print_buf); }} / ** * @briefPDMバッファフルコールバック*データを取得してオーディオスレッドコールバックを呼び出す* / static void pdm_data_ready_inference_callback(void){int bytesAvailable =PDM.available(); //サンプルバッファに読み込まれますintbytesRead =PDM.read((char *)&sampleBuffer [0]、bytesAvailable); if(record_ready ==true){for(int i =0; i > 1; i ++){inference.buffers [inference.buf_select] [inference.buf_count ++] =sampleBuffer [i]; if(inference.buf_count> =inference.n_samples){inference.buf_select ^ =1; inference.buf_count =0; inference.buf_ready =1; }}}} / ** * @briefInit推論構造体とセットアップ/開始PDM * * @param [in] n_samplesnサンプル** @return {description_of_the_return_value} * / static boolmicrophone_inference_start(uint32_t n_samples){inference.buffers [ 0] =(signed short *)malloc(n_samples * sizeof(signed short)); if(inference.buffers [0] ==NULL){falseを返す; } inference.buffers [1] =(signed short *)malloc(n_samples * sizeof(signed short)); if(inference.buffers [0] ==NULL){free(inference.buffers [0]); falseを返します。 } sampleBuffer =(signed short *)malloc((n_samples>> 1)* sizeof(signed short)); if(sampleBuffer ==NULL){free(inference.buffers [0]); free(inference.buffers [1]); falseを返します。 } inference.buf_select =0; inference.buf_count =0; inference.n_samples =n_samples; inference.buf_ready =0; //データ受信コールバックを構成しますPDM.onReceive(&pdm_data_ready_inference_callback); //オプションでゲインを設定します。デフォルトは20です。PDM.setGain(80); PDM.setBufferSize((n_samples>> 1)* sizeof(int16_t)); // PDMを次のように初期化します://-1つのチャネル(モノモード)//-16 kHzのサンプルレートif(!PDM.begin(1、EI_CLASSIFIER_FREQUENCY)){ei_printf( "Failed to start PDM!"); } record_ready =true; return true;} / ** * @ brief新しいデータを待機します** @ return終了時にTrue * / static boolmicrophone_inference_record(void){bool ret =true; if(inference.buf_ready ==1){ei_printf( "エラーサンプルバッファオーバーラン。モデルウィンドウあたりのスライス数を減らします" "(EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW)\ n"); ret =false; } while(inference.buf_ready ==0){delay(1); } inference.buf_ready =0; return ret;} / ***生のオーディオ信号データを取得します* / static intmicrophone_audio_signal_get_data(size_t offset、size_t length、float * out_ptr){numpy ::int16_to_float(&inference.buffers [inference.buf_select ^ 1] [offset]、out_ptr 、 長さ); return 0;} / ** * @brief PDMを停止し、バッファを解放します* / static void Miker_inference_end(void){PDM.end(); free(inference.buffers [0]); free(inference.buffers [1]); free(sampleBuffer);}#if!defined(EI_CLASSIFIER_SENSOR)|| EI_CLASSIFIER_SENSOR!=EI_CLASSIFIER_SENSOR_MICROPHONE#error "現在のセンサーのモデルが無効です。"#endif 

製造プロセス

  1. 2020年のIIoTセキュリティのヒントとトレンド
  2. IoT向けのクラウドおよびエッジコンピューティング:短い歴史
  3. なぜIoTのエッジコンピューティングなのか?
  4. Kontrons KBoxA-150-データ集約型IoTエッジアプリケーション向けのWKL
  5. TinyMLデバイス用に設計されたアームコア
  6. AI結晶化のためのエッジコンピューティングの利点
  7. エッジコンピューティングでの成功を確実にするための4つのステップ
  8. マイクロソフトが5Gアプリケーション向けのAzureエッジゾーンを発表
  9. エッジでのオープンソースの必要性(eBook)
  10. 低濃度レベルの化学検出システム
  11. ガス検知装置を維持する 3 つの理由