pdf-icon

Arduino入門

2. デバイス&サンプル

6. アプリケーション

UnitV2 Arduino 使用ガイド

1. 準備作業

2. 注意事項

ピン互換性
各ホストボードのピン配置は異なります。ユーザーが使いやすくするため、M5Stack公式よりピン互換性表が提供されています。実際のピン接続状況に応じてサンプルプログラムを修正してください。

3. コンパイルとアップロード

  • 必要に応じて以下のサンプルコードをプロジェクトのコード領域にコピー&ペーストし、デバイスポートを選択します(詳細はプログラムのコンパイルと書き込みを参照)。Arduino IDEの左上にあるコンパイル&アップロードボタンをクリックし、プログラムのコンパイルとデバイスへのアップロードが完了するのを待ちます。

4. UnitV2 の接続方法

4.1 イーサネットモード接続(USB接続)

この接続方法では、事前に使用しているオペレーティングシステムに応じたSR9900ドライバープログラムをダウンロードしてインストールする必要があります。その後、UnitV2をUSB Type-Cインターフェースでパソコンに接続します。UnitV2には有線LANカードが内蔵されているため、パソコンは自動的にネットワークデバイスとして認識し、UnitV2とのネットワーク接続を自動的に確立します。

4.2 APモード接続(WiFi接続)

この接続方法ではドライバープログラムのインストールは必要ありません。UnitV2に電源を供給すると、UnitV2は自動的にWiFiホットスポットを起動します。ホットスポット名はUnitV2-XXXX(XXXXはデバイスによって異なります)で、パスワードは12345678です。パソコンやスマートフォンなどのデバイスでこのホットスポットに接続すると、UnitV2とのネットワーク接続を確立できます。

5. サンプルプログラム

以下のサンプルプログラムはすべてM5Stack公式ファームウェアに対応しており、機能の切り替えとUnitV2から返されるJSONデータの解析を目的としています。公式ファームウェアについてはUnitV2ファームウェア更新ガイドを参照してください。UnitV2のその他の説明についてはこちらをご覧ください。

説明
1.UnitV2の設定と返却データのフォーマットはいずれもJSONです。各機能のJSONデータフォーマットについてはサンプルプログラムの前の説明を参照してください。
2.UnitV2はUSB Type-Cインターフェースから電源を供給しなければ動作しません。USB Type-Cインターフェースを抜き差しすると、ユニットは再起動します。
3.本ユニットの機能設定は電源を切断すると失われます。そのため、ユニットの電源を切断して再起動した後は、再度機能を設定する必要があります。ただし、各機能で保存したデータとパラメータ設定は電源切断後も保持されます

5.1 ビデオストリーム

このサンプルでは UnitV2 をビデオストリーム機能に切り替えることができ、機能ページでカメラ映像をリアルタイムで確認できます。ブラウザでドメイン unitv2.py または IP:10.254.239.1 にアクセスすると機能ページを表示できます。画面内容は以下の通りです:

ビデオストリーム機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;

void setup() {

    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);

    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C

    //Setting JSON
    JSONVar obj;
    obj["function"] = "Camera Stream";                                        
    obj["args"] = "";           
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
}

void loop() {

    if (Serial2.available() > 0) {
      String line = Serial2.readStringUntil('\r');
      while (line.length() && line[0] != '{') {// clear '\0'
          line.remove(0, 1);
      }
      Serial2.flush();

      JSONVar camera_stream_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(camera_stream_obj) == "undefined")){
        display.fillRect(0, 35, 320, 205, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("UnitV2 Camera Stream example");
        if (camera_stream_obj.hasOwnProperty("msg")) {
          Serial.print("msg : ");
          Serial.println(String(code_obj["msg"]).c_str());
          display.setCursor(0, 35);
          display.printf(" msg: %s\n", String(code_obj["msg"]).c_str());
        }
        if (camera_stream_obj.hasOwnProperty("running")) {
          Serial.print("running : ");
          Serial.println(String(code_obj["running"]).c_str());
          display.printf(" running: %s\n", String(code_obj["running"]).c_str());
        }        
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      } else {
        return;
      }
    }
} 

5.2 コード(バーコード/QRコード)認識

このサンプルプログラムではUnitV2をコード認識機能に切り替えることができ、QRコード、バーコード、DataMatrixコードなどの一般的なコードを認識できます。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

コード認識機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#include <M5Unified.h>                
#include <M5GFX.h>                  
#include <Arduino_JSON.h>          

M5GFX display;                
int code_cnt = 0;             

void setup() {
    display.begin();                 
    display.setRotation(1);        
    display.clear(TFT_WHITE);     
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK); 
    delay(100);                    
    display.drawString("UnitV2 Json Example", 5, 5); 
    display.drawLine(0, 25, 320, 25, TFT_BLACK);  
    Serial.begin(115200);          
    Serial2.begin(115200, SERIAL_8N1, 13, 14); 

    // Create initial JSON for configuration
    JSONVar obj;
    obj["function"] = "Code Detector";                         
    obj["args"] = "";                 
    String jsonString = JSON.stringify(obj); // Convert JSON to string
    Serial2.println(jsonString);       // Send JSON string to Serial2
    Serial2.flush();                   // Flush Serial2 buffer
}

void loop() {
    if (Serial2.available() > 0) {         
        String line = Serial2.readStringUntil('\r'); 
        while (line.length() && line[0] != '{') { // Remove non-JSON starting characters
            line.remove(0, 1);
        }
        Serial2.flush();       

        JSONVar code_obj = JSON.parse(line);

        if (!(JSON.typeof(code_obj) == "undefined")) { 
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Code Detector example");   

            // Configuration response
            if (code_obj.hasOwnProperty("msg")) {
                Serial.print("msg : ");
                Serial.println(String(code_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(code_obj["msg"]).c_str());
                if (code_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(code_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(code_obj["running"]).c_str());
                }
            } else {
              if (code_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(code_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(code_obj["running"]).c_str());
              }
            }
           
            if (code_obj.hasOwnProperty("num")) {
                code_cnt = (int)code_obj["num"];
                Serial.printf("num = %d\n", code_cnt);
                display.printf(" num: %d\n", code_cnt);
            }
            
            if (code_obj.hasOwnProperty("code")) {
                JSONVar code_arr = code_obj["code"];
                for (int i = 0; i < (int)code_cnt; i++) {
                    display.fillRect(0, 80, 320, 160, TFT_WHITE);
                    display.setCursor(0, 80);
                    if (JSON.typeof(code_arr[i]) != "undefined") {
                        Serial.printf("------[Code %d]------\n", i);
                        Serial.printf("\tprob: %f\n", (double)code_arr[i]["prob"]);
                        Serial.printf("\tx: %d\n", (int)code_arr[i]["x"]);
                        Serial.printf("\ty: %d\n", (int)code_arr[i]["y"]);
                        Serial.printf("\tw: %d\n", (int)code_arr[i]["w"]);
                        Serial.printf("\th: %d\n", (int)code_arr[i]["h"]);
                        Serial.printf("\ttype: %s\n", (const char*)code_arr[i]["type"]);
                        Serial.printf("\tcontent: %s\n", (const char*)code_arr[i]["content"]);
                        display.printf("Code %d:\n", i);
                        display.printf(" prob: %.3f\n", (double)code_arr[i]["prob"]);
                        display.printf(" x: %d, y: %d\n", (int)code_arr[i]["x"], (int)code_arr[i]["y"]);
                        display.printf(" w: %d, h: %d\n", (int)code_arr[i]["w"], (int)code_arr[i]["h"]);
                        display.printf(" type: %s\n", (const char*)code_arr[i]["type"]);
                        display.printf(" content: %s\n\n", (const char*)code_arr[i]["content"]);
                    }
                    delay(200);
                }
            }
            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
}

下図左側のQRコードをスキャンすると、右側の図のような認識結果が表示されます。

5.3 物体認識

このサンプルプログラムではUnitV2を物体認識機能に切り替えることができます。出荷時のファームウェアにはnanodet_80classyolo_20classsのモデルがデフォルトで内蔵されており、すぐに使用できます。カスタムモデルを学習させたい場合は、ガイドUnitV2 V-Trainingを参照してください。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

物体認識機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int obj_cnt = 0;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Object Recognition";                                
    obj["args"][0] = "yolo_20class";   // yolo_20class or nanodet_80class  
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // clear '\0'
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar rec_obj = JSON.parse(line);

        if (!(JSON.typeof(rec_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Object Recognition example");            

            if (rec_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println((const char*) rec_obj["msg"]);
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", (const char*) rec_obj["msg"]);
                if (rec_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(rec_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(rec_obj["running"]).c_str());
                }
            } else {
              if (rec_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(rec_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(rec_obj["running"]).c_str());
              }
            }
            if (rec_obj.hasOwnProperty("num")) {
                obj_cnt = (int)rec_obj["num"];
                Serial.printf("num = %d\n", obj_cnt);
                display.printf(" num: %d\n", obj_cnt);
            }

            if (rec_obj.hasOwnProperty("obj")) {
                JSONVar obj_arr = rec_obj["obj"];
                for (int i = 0; i < (int)obj_cnt; i++) {
                    display.fillRect(0, 80, 320, 160, TFT_WHITE);
                    display.setCursor(0, 80);
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        Serial.printf("------[obj %d]------\n", i);
                        Serial.printf("\tprob: %f\n", (double)obj_arr[i]["prob"]);
                        Serial.printf("\tx: %d\n", (int)obj_arr[i]["x"]);
                        Serial.printf("\ty: %d\n", (int)obj_arr[i]["y"]);
                        Serial.printf("\tw: %d\n", (int)obj_arr[i]["w"]);
                        Serial.printf("\th: %d\n", (int)obj_arr[i]["h"]);
                        Serial.printf("\ttype: %s\n", (const char*)obj_arr[i]["type"]);
                        
                        display.printf("obj %d:\n", i);
                        display.printf(" prob: %.3f\n", (double)obj_arr[i]["prob"]);
                        display.printf(" x: %d, y: %d\n", (int)obj_arr[i]["x"], (int)obj_arr[i]["y"]);
                        display.printf(" w: %d, h: %d\n", (int)obj_arr[i]["w"], (int)obj_arr[i]["h"]);
                        display.printf(" type: %s\n\n", (const char*)obj_arr[i]["type"]);
                    }
                    delay(200);
                }
            }
            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
}

下図左側の画像をスキャンすると、右側の図のような認識結果が表示されます。

5.4 色追跡

このサンプルプログラムではUnitV2を色追跡機能に切り替えることができます。色追跡機能を使用するには、UnitV2に電源を供給した後、追跡する色のパラメータを設定する必要があります。色パラメータの設定方法は2通りあります。1つは機能ページで画面をクリックして追跡する色を範囲選択する方法(操作方法は下図参照)、または左側のL、A、Bの値を入力した後「update」ボタンをクリックして設定する方法です。

もう1つは以下のコード内のJSON形式で設定する方法で、ROI(関心領域)を範囲選択して自動的にLAB色値を分析して設定することも、直接LAB色値を設定することもできます。以下のコードではデフォルトでROI方式を使用して設定しています。LAB方式で設定したい場合は、コード内の#define USING_LABのコメントを解除し、以下に示すコード部分にLAB色値を入力してください。

    LAB["l_min"] = 0; 
    LAB["l_max"] = 255; 
    LAB["a_min"] = 179; 
    LAB["a_max"] = 201; 
    LAB["b_min"] = 162; 
    LAB["b_max"] = 184; 

ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

色追跡機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

// このマクロ定義を有効にするとLAB方式を使用します。無効の場合はデフォルトでROI方式を使用します。
// #define USING_LAB

M5GFX display;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Color Tracker";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
#if defined(USING_LAB) 
    JSONVar LAB;
    LAB["config"] = "Color Tracker";                                
    LAB["l_min"] = 0; 
    LAB["l_max"] = 255; 
    LAB["a_min"] = 179; 
    LAB["a_max"] = 201; 
    LAB["b_min"] = 162; 
    LAB["b_max"] = 184;   
    jsonString = JSON.stringify(LAB);
#else
    JSONVar ROI;
    ROI["config"] = "Color Tracker";                                
    ROI["x"] = 160; 
    ROI["y"] = 120; 
    ROI["w"] = 320; 
    ROI["h"] = 240;  
    jsonString = JSON.stringify(ROI);
#endif
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // clear '\0'
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar color_obj = JSON.parse(line);

        if (!(JSON.typeof(color_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Color Tracker example");            

            if (color_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(color_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(color_obj["msg"]).c_str());
                if (color_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(color_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(color_obj["running"]).c_str());
                }
            } else {
              if (color_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(color_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(color_obj["running"]).c_str());
              }
              // ROI設定のレスポンス
              if (color_obj.hasOwnProperty("a_cal")) {
                  double a_cal = (double)color_obj["a_cal"];
                  double b_cal = (double)color_obj["b_cal"];
                  double va    = (double)color_obj["va"];
                  double vb    = (double)color_obj["vb"];

                  int l_min   = (int)color_obj["l_min"];
                  int l_max   = (int)color_obj["l_max"];
                  int a_min   = (int)color_obj["a_min"];
                  int a_max   = (int)color_obj["a_max"];
                  int b_min   = (int)color_obj["b_min"];
                  int b_max   = (int)color_obj["b_max"];

                  Serial.printf("a_cal = %f\n", a_cal);
                  Serial.printf("b_cal = %f\n", b_cal);
                  Serial.printf("va = %f\n", va);
                  Serial.printf("vb = %f\n", vb);
                  Serial.printf("l_min = %d\nl_max = %d\n", l_min, l_max);
                  Serial.printf("a_min = %d\na_max = %d\nb_min = %d\nb_max = %d\n",
                                a_min, a_max, b_min, b_max);

                  display.printf(" a_cal: %f\n", a_cal);
                  display.printf(" b_cal: %f\n", b_cal);
                  display.printf(" va: %f\n", va);
                  display.printf(" vb: %f\n", vb);
                  display.printf(" l_min: %d\n", l_min);
                  display.printf(" l_max: %d\n", l_max);
                  display.printf(" a_min: %d\n", a_min);
                  display.printf(" a_max: %d\n", a_max);
                  display.printf(" b_min: %d\n", b_min);
                  display.printf(" b_max: %d\n", b_max);
                  delay(2000);
              }
            }

            if (color_obj.hasOwnProperty("cx")) {
                int cx   = (int)color_obj["cx"];
                int cy   = (int)color_obj["cy"];
                int r   = (int)color_obj["r"];
                int mx   = (int)color_obj["mx"];
                int my   = (int)color_obj["my"];

                Serial.printf("cx = %d\n", cx);
                Serial.printf("cy = %d\n", cy);
                Serial.printf("r  = %d\n", r);
                Serial.printf("mx = %d\n", mx);
                Serial.printf("my = %d\n", my);

                display.setCursor(0, 60);
                display.printf(" cx = %d\n", cx);
                display.printf(" cy = %d\n", cy);
                display.printf(" r  = %d\n", r);
                display.printf(" mx = %d\n", mx);
                display.printf(" my = %d\n", my);
            }

            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
} 

サンプルプログラムが正常に実行されると、ホストボードは追跡している色のブロックの中心点の位置、サイズなどのデータをリアルタイムで表示・出力します。検出結果は以下の図の通りです:

5.5 レーンライン追跡

このサンプルプログラムではUnitV2をレーンライン追跡機能に切り替えることができます。色追跡機能と同様に、UnitV2に電源を供給した後、色パラメータを設定する必要があります。色パラメータの設定方法は上記の色追跡を参照してください。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

以下のコードではデフォルトでROI方式を使用して設定しています。LAB方式で設定したい場合は、コード内の#define USING_LABのコメントを解除し、以下に示すコード部分にLAB色値を入力してください。

    LAB["l_min"] = 0; 
    LAB["l_max"] = 255; 
    LAB["a_min"] = 176; 
    LAB["a_max"] = 198; 
    LAB["b_min"] = 155; 
    LAB["b_max"] = 175; 

レーンライン追跡機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

// このマクロ定義を有効にするとLAB方式を使用します。無効の場合はデフォルトでROI方式を使用します。
// #define USING_LAB

M5GFX display;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Lane Line Tracker";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
#if defined(USING_LAB) 
    JSONVar LAB;
    LAB["config"] = "Lane Line Tracker";                                
    LAB["l_min"] = 0; 
    LAB["l_max"] = 255; 
    LAB["a_min"] = 176; 
    LAB["a_max"] = 198; 
    LAB["b_min"] = 155; 
    LAB["b_max"] = 175;   
    jsonString = JSON.stringify(LAB);
#else
    JSONVar ROI;
    ROI["config"] = "Lane Line Tracker";                                
    ROI["x"] = 160; 
    ROI["y"] = 120; 
    ROI["w"] = 320; 
    ROI["h"] = 240;  
    jsonString = JSON.stringify(ROI);
#endif
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // clear '\0'
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar line_obj = JSON.parse(line);

        if (!(JSON.typeof(line_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Lane Line Tracker example");            

            if (line_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(line_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(line_obj["msg"]).c_str());
                if (line_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(line_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(line_obj["running"]).c_str());
                }
            } else {
              if (line_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(line_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(line_obj["running"]).c_str());
              }
              // ROI設定のレスポンス
              if (line_obj.hasOwnProperty("a_cal")) {
                  double a_cal = (double)line_obj["a_cal"];
                  double b_cal = (double)line_obj["b_cal"];
                  double va    = (double)line_obj["va"];
                  double vb    = (double)line_obj["vb"];

                  int l_min   = (int)line_obj["l_min"];
                  int l_max   = (int)line_obj["l_max"];
                  int a_min   = (int)line_obj["a_min"];
                  int a_max   = (int)line_obj["a_max"];
                  int b_min   = (int)line_obj["b_min"];
                  int b_max   = (int)line_obj["b_max"];

                  Serial.printf("a_cal = %f\n", a_cal);
                  Serial.printf("b_cal = %f\n", b_cal);
                  Serial.printf("va = %f\n", va);
                  Serial.printf("vb = %f\n", vb);
                  Serial.printf("l_min = %d\nl_max = %d\n", l_min, l_max);
                  Serial.printf("a_min = %d\na_max = %d\nb_min = %d\nb_max = %d\n",
                                a_min, a_max, b_min, b_max);

                  display.printf(" a_cal: %f\n", a_cal);
                  display.printf(" b_cal: %f\n", b_cal);
                  display.printf(" va: %f\n", va);
                  display.printf(" vb: %f\n", vb);
                  display.printf(" l_min: %d\n", l_min);
                  display.printf(" l_max: %d\n", l_max);
                  display.printf(" a_min: %d\n", a_min);
                  display.printf(" a_max: %d\n", a_max);
                  display.printf(" b_min: %d\n", b_min);
                  display.printf(" b_max: %d\n", b_max);
                  delay(2000);
              }
            }

            if (line_obj.hasOwnProperty("x")) {
                int x  = (int)line_obj["x"];
                int y  = (int)line_obj["y"];
                double k  = (double)line_obj["k"];

                Serial.printf("x = %d\n", x);
                Serial.printf("y = %d\n", y);
                Serial.printf("k = %f\n", k);
                
                display.setCursor(0, 60);
                display.printf(" x = %d\n", x);
                display.printf(" y = %d\n", y);
                display.printf(" k = %f\n", k);                
            }

            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
} 

下図左側の画像をスキャンすると、右側の図のような認識結果が表示されます。

5.6 ターゲット追跡

このサンプルプログラムではUnitV2をターゲット追跡機能に切り替えることができます。UnitV2に電源を供給した後、カメラの現在の映像からターゲット物体の情報を取得してから使用する必要があります。機能ページで範囲選択することができ(ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスして機能ページを開く)、以下のコードのパラメータを設定して取得することもできます。起点、幅、高さのパラメータを設定するコードは以下の通りです:

    obj["x"] = 160;  //起点のX座標           
    obj["y"] = 120;  //起点のY座標                             
    obj["w"] = 320;  //幅                            
    obj["h"] = 240;  //高さ

ターゲット追跡機能のJSONデータフォーマットの詳細はこちらを参照してください。

以下のサンプルプログラムでは、ホストボードに電源を供給した後に1回だけパラメータ設定データを送信します。追跡対象が取得範囲内にあることを確認してください。サンプルの機能ページは以下の通りです:

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Target Tracker";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
    JSONVar ROI;
    ROI["config"] = "Target Tracker";                                
    ROI["x"] = 160; 
    ROI["y"] = 120; 
    ROI["w"] = 320; 
    ROI["h"] = 240;  
    jsonString = JSON.stringify(ROI);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // clear '\0'
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar target_obj = JSON.parse(line);

        if (!(JSON.typeof(target_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Target Tracker example");            

            if (target_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(target_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(target_obj["msg"]).c_str());
                if (target_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(target_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(target_obj["running"]).c_str());
                }
            } else {
              if (target_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(target_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(target_obj["running"]).c_str());
              }
            }

            if (target_obj.hasOwnProperty("x")) {
                int x  = (int)target_obj["x"];
                int y  = (int)target_obj["y"];
                int w  = (int)target_obj["w"];
                int h  = (int)target_obj["h"];

                Serial.printf("x = %d\n", x);
                Serial.printf("y = %d\n", y);
                Serial.printf("w = %d\n", w);
                Serial.printf("h = %d\n", h);
                
                display.setCursor(0, 60);
                display.printf(" x = %d\n", x);
                display.printf(" y = %d\n", y);
                display.printf(" w = %d\n", w);
                display.printf(" h = %d\n", h);                
            }

            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
} 

ターゲット物体のデータを正常に取得すると、ホストボードはターゲット物体の位置などのデータをリアルタイムで表示・出力します。検出結果は以下の図の通りです:

5.7 動体追跡

このサンプルプログラムではUnitV2を動体追跡機能に切り替えることができます。この機能を使用する前に、背景を1回設定して効果的に動体追跡を行う必要があります。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

動体検出機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int motion_cnt = 0;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Motion Tracker";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
    JSONVar BCKG;
    BCKG["config"] = "Motion Tracker";                                
    BCKG["operation"] = "update";  
    jsonString = JSON.stringify(BCKG);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // clear '\0'
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar motion_obj = JSON.parse(line);

        if (!(JSON.typeof(motion_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Target Tracker example");            

            if (motion_obj.hasOwnProperty("msg")) {//ここは設定のレスポンスを1回受信するための処理です
                Serial.print("msg = ");
                Serial.println(String(motion_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(motion_obj["msg"]).c_str());
                if (motion_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(motion_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(motion_obj["running"]).c_str());
                }
            } else {
              if (motion_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(motion_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(motion_obj["running"]).c_str());
              }
            }

            if (motion_obj.hasOwnProperty("num")) {
                motion_cnt = (int)motion_obj["num"];
                Serial.printf("num = %d\n", motion_cnt);
                display.printf(" num: %d\n", motion_cnt);
            }

            // obj配列を走査
            if (motion_obj.hasOwnProperty("roi")) {
                JSONVar obj_arr = motion_obj["roi"];
                for (int i = 0; i < (int)motion_cnt; i++) {
                    display.fillRect(0, 80, 320, 160, TFT_WHITE);
                    display.setCursor(0, 80);
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        Serial.printf("------[roi %d]------\n", i);
                        Serial.printf("\tx: %d\n", (int)obj_arr[i]["x"]);
                        Serial.printf("\ty: %d\n", (int)obj_arr[i]["y"]);
                        Serial.printf("\tw: %d\n", (int)obj_arr[i]["w"]);
                        Serial.printf("\th: %d\n", (int)obj_arr[i]["h"]);
                        Serial.printf("\tangle: %f\n", (double)obj_arr[i]["angle"]);
                        Serial.printf("\tarea: %d\n", (int)obj_arr[i]["area"]);
                        
                        display.printf("roi %d:\n", i);
                        display.printf(" x: %d, y: %d\n", (int)obj_arr[i]["x"], (int)obj_arr[i]["y"]);
                        display.printf(" w: %d, h: %d\n", (int)obj_arr[i]["w"], (int)obj_arr[i]["h"]);
                        display.printf(" angle: %f\n", (double)obj_arr[i]["angle"]);
                        display.printf(" area: %d\n", (int)obj_arr[i]["area"]);
                    }
                    delay(200);
                }
            }

            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
} 

UnitV2が物体の動きを検出すると、物体の位置などのデータをリアルタイムでフィードバックします。フィードバック結果は以下の図の通りです:

5.8 物体認識分類

このサンプルプログラムではUnitV2を物体認識分類機能に切り替えることができます。出荷時のファームウェアにはCore、UnitV、StickC、Atomの4つのカテゴリがデフォルトで搭載されています。カスタムカテゴリを作成したい場合は、機能ページの「add」ボタンをクリックして追加し、「train」ボタンをクリックして該当カテゴリの学習を行い、最後に「save&run」ボタンをクリックして該当カテゴリのデータを保存して学習モードを終了すると、物体認識分類機能を使用できます。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

また、以下のサンプルプログラム内のenter_training_modesave_and_start関数を使用して設定することもできます。以下のサンプルプログラムではearphone(イヤホン)というカテゴリを新規作成して学習を行い、学習回数は10回です。他のカテゴリを追加したい場合は、enter_training_mode関数内のカテゴリIDと名前を変更してください。

注意
reset操作(機能ページの「reset」ボタンをクリックするか、以下のコード内のenter_training_mode_with_all_classes_clear関数を使用する)を行うと、すべての学習済みカテゴリデータ(出荷時のデフォルトカテゴリを含む)が永久に削除されます電源を切断して再度供給しても復元されませんので、慎重に使用してください!

物体認識分類機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int cla_cnt = 0;

String enter_training_mode(int id, String name) {
    JSONVar json;
    json["config"] = "Online Classifier";                                
    json["operation"] = "train";  
    json["class_id"] = id; //0~N
    json["class"] = name;  //形式:"class_name"
    return JSON.stringify(json);
}

String enter_training_mode_with_all_classes_clear(void) {
    JSONVar json;
    json["config"] = "Online Classifier";                                
    json["operation"] = "reset";  
    return JSON.stringify(json);
}

String save_and_start(void) {
    JSONVar json;
    json["config"] = "Online Classifier";                                
    json["operation"] = "saverun";  
    return JSON.stringify(json);
}

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Online Classifier";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);delay(10);

    // このコマンドを実行すると出荷時ファームウェアのデフォルトカテゴリが削除されます。推奨しません。
    // jsonString = enter_training_mode_with_all_classes_clear();
    // Serial2.println(jsonString);delay(10);

    for (int i=0; i < 10; i++){
        jsonString = enter_training_mode(0, "earphone");
        Serial2.println(jsonString);delay(10);            
    }    
    delay(2000);

    jsonString = save_and_start();
    Serial2.println(jsonString);
    delay(10);
    Serial2.flush();
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // 空文字('\0')をクリア
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar cla_obj = JSON.parse(line);

        if (!(JSON.typeof(cla_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Target Tracker example");            

            if (cla_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(cla_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(cla_obj["msg"]).c_str());
                if (cla_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(cla_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(cla_obj["running"]).c_str());
                }
            } else {
              if (cla_obj.hasOwnProperty("running")) {
                  Serial.print("running = ");
                  Serial.println(String(cla_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(cla_obj["running"]).c_str());
              }
            }

            if (cla_obj.hasOwnProperty("class_num")) {
                cla_cnt = (int)cla_obj["class_num"];
                String best_match = String(cla_obj["best_match"]).c_str();
                double best_score = (double)cla_obj["best_score"];

                Serial.printf("class num = %d\n", cla_cnt);
                Serial.printf("best match = %s\n", best_match);
                Serial.printf("best score = %f\n", best_score);

                display.printf(" class num: %d\n", cla_cnt);
                display.printf(" best match = %s\n", best_match);
                display.printf(" best score = %f\n", best_score);
            }

            if (cla_obj.hasOwnProperty("class")) {
                JSONVar obj_arr = cla_obj["class"];
                for (int i = 0; i < (int)cla_cnt; i++) {
                    display.fillRect(0, 120, 320, 120, TFT_WHITE);
                    display.setCursor(0, 120);
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        Serial.printf("------[class %d]------\n", i);
                        Serial.printf("\tname: %s\n", String(obj_arr[i]["name"]).c_str());
                        Serial.printf("\tscore: %f\n", (double)obj_arr[i]["score"]);
                        
                        display.printf("class %d:\n", i);
                        display.printf(" name: %s\n", String(obj_arr[i]["name"]).c_str());
                        display.printf(" score: %f\n", (double)obj_arr[i]["score"]);
                    }
                    delay(200);
                }
            }

            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
}

UnitV2が物体を検出すると、物体が属するカテゴリなどのデータをリアルタイムでフィードバックします。フィードバック結果は以下の図の通りです:

5.9 顔認識

このサンプルプログラムではUnitV2を顔認識機能に切り替えることができます。出荷時のファームウェアには顔データが含まれていません。顔データを設定するには、機能ページの「add」ボタンをクリックして追加し、「train」ボタンをクリックして該当顔データの学習を行い、最後に「save」ボタンをクリックして該当顔データを保存して学習モードを終了すると、顔認識機能を使用できます。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

また、以下のサンプルプログラム内のcreate_new_facesave_and_start関数を使用して設定することもできます。以下のサンプルプログラムではLenaという顔データを新規作成して学習を行い、学習回数は10回です。他の顔データを追加したい場合は、create_new_face関数内のカテゴリIDと名前を変更してください。

注意
reset操作(機能ページの「reset」ボタンをクリックするか、以下のコード内のclear_all_faces関数を使用する)を行うと、すべての学習済み顔データが永久に削除されます電源を切断して再度供給しても復元されませんので、慎重に使用してください!

顔認識機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int face_cnt = 0;

String create_new_face(int id, String name) {
    JSONVar json;
    json["config"] = "Face Recognition";                                
    json["operation"] = "train";  
    json["face_id"] = id; //0~N
    json["name"] = name;  //形式:"face_name"
    return JSON.stringify(json);
}

String clear_all_faces(void) {
    JSONVar json;
    json["config"] = "Face Recognition";                                
    json["operation"] = "reset";  
    return JSON.stringify(json);
}

String save_and_start(void) {
    JSONVar json;
    json["config"] = "Face Recognition";                                
    json["operation"] = "saverun";  
    return JSON.stringify(json);
}

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 3, 3);
    display.drawLine(0, 23, 320, 23, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Face Recognition";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);delay(10);

    // jsonString = clear_all_faces();
    // Serial2.println(jsonString);delay(10);

    for (int i=0; i < 10; i++){
        jsonString = create_new_face(0, "Lena");
        Serial2.println(jsonString);delay(10);            
    }    
    delay(2000);

    jsonString = save_and_start();
    Serial2.println(jsonString);delay(10);
    Serial2.flush();
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // 空文字('\0')をクリア
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar face_obj = JSON.parse(line);

        if (!(JSON.typeof(face_obj) == "undefined")) {
            display.fillRect(0, 25, 320, 215, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Face Recognition example");            

            if (face_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(face_obj["msg"]).c_str());
                display.setCursor(0, 25);
                display.printf(" msg: %s\n", String(face_obj["msg"]).c_str());
                if (face_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(face_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(face_obj["running"]).c_str());
                }
            } else {
              if (face_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(face_obj["running"]).c_str());
                  display.setCursor(0, 25);
                  display.printf(" running: %s\n", String(face_obj["running"]).c_str());
              }
              if (face_obj.hasOwnProperty("status")) {
                  Serial.printf("status : %s\n", String(face_obj["status"]).c_str());
                  Serial.printf("\tx: %d\n", (int)face_obj["x"]);
                  Serial.printf("\ty: %d\n", (int)face_obj["y"]);
                  Serial.printf("\tw: %d\n", (int)face_obj["w"]);
                  Serial.printf("\th: %d\n", (int)face_obj["h"]);
                  Serial.printf("\tprob: %f\n", (double)face_obj["prob"]);
                  Serial.printf("\tname: %s\n", String(face_obj["name"]).c_str());

                  display.printf(" status: %s\n", String(face_obj["status"]).c_str());
                  display.printf(" x: %d\n", (int)face_obj["x"]);
                  display.printf(" y: %d\n", (int)face_obj["y"]);
                  display.printf(" w: %d\n", (int)face_obj["w"]);
                  display.printf(" h: %d\n", (int)face_obj["h"]);
                  display.printf(" prob: %f\n", (double)face_obj["prob"]);
                  display.printf(" name: %s\n", String(face_obj["name"]).c_str());
              }
            }

            if (face_obj.hasOwnProperty("num")) {
                face_cnt = (int)face_obj["num"];
                Serial.printf("num = %d\n", face_cnt);
                display.printf(" num: %d\n", face_cnt);
            }

            if (face_obj.hasOwnProperty("face")) {
                JSONVar obj_arr = face_obj["face"];
                display.fillRect(0, 60, 320, 180, TFT_WHITE);
                display.setCursor(0, 60);
                for (int i = 0; i < (int)face_cnt; i++) {
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        int fx = (int)obj_arr[i]["x"];
                        int fy = (int)obj_arr[i]["y"];
                        int fw = (int)obj_arr[i]["w"];
                        int fh = (int)obj_arr[i]["h"];
                        double fprob = (double)obj_arr[i]["prob"];
                        double fmprob = (double)obj_arr[i]["match_prob"];
                        String fname = String(obj_arr[i]["name"]);
                        Serial.printf("------[face %d]------\n", i);
                        Serial.printf("\tx: %d\n", fx);
                        Serial.printf("\ty: %d\n", fy);
                        Serial.printf("\tw: %d\n", fw);
                        Serial.printf("\th: %d\n", fh);
                        Serial.printf("\tprob: %f\n", fprob);
                        Serial.printf("\tmatch prob: %f\n", fmprob);
                        Serial.printf("\tname: %s\n", fname.c_str());
                        display.printf("face %d:\n", i);
                        display.printf(" x:%d, y:%d,", fx, fy);
                        display.printf(" w:%d, h:%d\n", fw, fh);
                        display.printf(" prob: %f\n", fprob);
                        display.printf(" match prob: %f\n", fmprob);
                        display.printf(" name: %s\n", fname.c_str());

                        if (obj_arr[i].hasOwnProperty("mark")) {
                            JSONVar marks = obj_arr[i]["mark"];
                            for (int j = 0; j < 5; j++) {
                                if (JSON.typeof(marks[j]) != "undefined") {
                                    int mx = (int)marks[j]["x"];
                                    int my = (int)marks[j]["y"];
                                    display.printf("\t mark%d: x=%d, y=%d\n", j, mx, my);
                                    Serial.printf("\t\tmark%d: x=%d, y=%d\n", j, mx, my);
                                }
                            }
                        }
                    }
                    delay(200);
                }
            }
            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
} 

下図左側の顔をスキャンすると、右側の図のような認識結果が表示されます。

5.10 顔検出

このサンプルプログラムではUnitV2を顔検出機能に切り替えることができます。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

顔検出機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int face_cnt = 0;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Face Detector";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);
    Serial2.flush();
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // 空文字('\0')をクリア
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar face_obj = JSON.parse(line);

        if (!(JSON.typeof(face_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Face Detector example");            

            if (face_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(face_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(face_obj["msg"]).c_str());
                if (face_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(face_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(face_obj["running"]).c_str());
                }
            } else {
              if (face_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(face_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(face_obj["running"]).c_str());
              }
            }

            if (face_obj.hasOwnProperty("num")) {
                face_cnt = (int)face_obj["num"];
                Serial.printf("num = %d\n", face_cnt);
                display.printf(" num: %d\n", face_cnt);
            }

            if (face_obj.hasOwnProperty("face")) {
                JSONVar obj_arr = face_obj["face"];
                display.fillRect(0, 70, 320, 170, TFT_WHITE);
                display.setCursor(0, 70);
                for (int i = 0; i < (int)face_cnt; i++) {
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        int fx = (int)obj_arr[i]["x"];
                        int fy = (int)obj_arr[i]["y"];
                        int fw = (int)obj_arr[i]["w"];
                        int fh = (int)obj_arr[i]["h"];
                        double fprob = (double)obj_arr[i]["prob"];
                        Serial.printf("------[face %d]------\n", i);
                        Serial.printf("\tx: %d\n", fx);
                        Serial.printf("\ty: %d\n", fy);
                        Serial.printf("\tw: %d\n", fw);
                        Serial.printf("\th: %d\n", fh);
                        Serial.printf("\tprob: %f\n", fprob);
                        display.printf("face %d:\n", i);
                        display.printf(" x:%d, y:%d\n", fx, fy);
                        display.printf(" w:%d, h:%d\n", fw, fh);
                        display.printf(" prob: %f\n", fprob);

                        if (obj_arr[i].hasOwnProperty("mark")) {
                            JSONVar marks = obj_arr[i]["mark"];
                            for (int j = 0; j < 5; j++) {
                                if (JSON.typeof(marks[j]) != "undefined") {
                                    int mx = (int)marks[j]["x"];
                                    int my = (int)marks[j]["y"];
                                    display.printf("\t mark%d: x=%d, y=%d\n", j, mx, my);
                                    Serial.printf("\t\tmark%d: x=%d, y=%d\n", j, mx, my);
                                }
                            }
                        }
                    }
                    delay(200);
                }
            }
            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
}

下図左側の顔をスキャンすると、右側の図のような検出結果が表示されます。

5.11 形状検出

このサンプルプログラムではUnitV2を形状検出機能に切り替えることができます。この機能を使用する前に、背景を1回設定して検出を行う必要があります。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

形状検出機能のJSONデータフォーマットの詳細はこちらを参照してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int shape_cnt = 0;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Shape Detector";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);delay(10);
    JSONVar BCKG;
    BCKG["config"] = "Shape Detector";                                
    BCKG["operation"] = "update";  
    jsonString = JSON.stringify(BCKG);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // 空文字('\0')をクリア
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar shape_obj = JSON.parse(line);

        if (!(JSON.typeof(shape_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Shape Detector example");            

            if (shape_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(shape_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(shape_obj["msg"]).c_str());
                if (shape_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(shape_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(shape_obj["running"]).c_str());
                }
            } else {
              if (shape_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(shape_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(shape_obj["running"]).c_str());
              }
            }

            if (shape_obj.hasOwnProperty("num")) {
                shape_cnt = (int)shape_obj["num"];
                Serial.printf("num = %d\n", shape_cnt);
                display.printf(" num: %d\n", shape_cnt);
            }

            if (shape_obj.hasOwnProperty("shape")) {
                JSONVar obj_arr = shape_obj["shape"];
                for (int i = 0; i < (int)shape_cnt; i++) {
                    display.fillRect(0, 80, 320, 160, TFT_WHITE);
                    display.setCursor(0, 80);
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        String name = String(obj_arr[i]["name"]);
                        int x = (int)obj_arr[i]["x"];
                        int y = (int)obj_arr[i]["y"];
                        int w = (int)obj_arr[i]["w"];
                        int h = (int)obj_arr[i]["h"];
                        double angle = (double)obj_arr[i]["angle"];
                        int area = (int)obj_arr[i]["area"];

                        Serial.printf("------[shape %d]------\n", i);
                        Serial.printf("\tname: %s\n", name.c_str());
                        Serial.printf("\tx: %d\n", x);
                        Serial.printf("\ty: %d\n", y);
                        Serial.printf("\tw: %d\n", w);
                        Serial.printf("\th: %d\n", h);
                        Serial.printf("\tangle: %f\n", angle);
                        Serial.printf("\tarea: %d\n", area);

                        display.printf("shape %d:\n", i);
                        display.printf(" name: %s\n", name.c_str());
                        display.printf(" x:%d, y:%d\n", x, y);
                        display.printf(" w:%d, h:%d\n", w, h);
                        display.printf(" angle: %f\n", angle);
                        display.printf(" area: %d\n", area);
                    }
                    delay(200);
                }
            }
            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
}

下図左側の画像をスキャンすると、右側の図のような検出結果が表示されます。

5.12 カスタム形状マッチング

このサンプルプログラムではUnitV2をカスタム形状マッチング機能に切り替えることができます。この機能を使用する前に、背景を1回設定して検出マッチングを行う必要があります。出荷時のファームウェアには形状データが含まれていません。形状データを設定するには、機能ページの「add」ボタンをクリックして追加し、「upload」ボタンをクリックして「白地に黒い形状」の「pngファイル」をアップロードします。作成される形状名はファイル名に基づいて設定され、この例ではアップロードするファイル名をarrow.pngとしているため、形状名はarrow(矢印)となります。画像のアップロードが成功すると、形状マッチング機能を使用できます。ブラウザでドメインunitv2.pyまたはIPアドレス10.254.239.1にアクセスすると機能ページが表示され、ページの内容は以下の通りです:

形状検出機能のJSONデータフォーマットの詳細はこちらを参照してください。

説明
以下のサンプルプログラムでは、JSONデータ内のすべてのフィールドを出力しているわけではありません。すべてのフィールドを確認したい場合は、JSONデータフォーマットを参考に独自に追加してください。
cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int shape_cnt = 0;

void setup() {
    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV2 Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);
    Serial.begin(115200);
    Serial2.begin(115200, SERIAL_8N1, 13, 14);//PORT.C
    //Setting JSON
    JSONVar obj;
    obj["function"] = "Shape Matching";                                
    obj["args"] = "";   
    String jsonString = JSON.stringify(obj);
    Serial2.println(jsonString);delay(10);
    JSONVar BCKG;
    BCKG["config"] = "Shape Matching";                                
    BCKG["operation"] = "update";  
    jsonString = JSON.stringify(BCKG);
    Serial2.println(jsonString);
    Serial2.flush();
    delay(200);
}

void loop() {
    if (Serial2.available() > 0) {
        String line = Serial2.readStringUntil('\r');
        while (line.length() && line[0] != '{') { // 空文字('\0')をクリア
            line.remove(0, 1);
        }
        Serial2.flush();
        JSONVar shape_obj = JSON.parse(line);

        if (!(JSON.typeof(shape_obj) == "undefined")) {
            display.fillRect(0, 35, 320, 205, TFT_WHITE);
            Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Serial.println("UnitV2 Shape Matching example");            

            if (shape_obj.hasOwnProperty("msg")) {
                Serial.print("msg = ");
                Serial.println(String(shape_obj["msg"]).c_str());
                display.setCursor(0, 35);
                display.printf(" msg: %s\n", String(shape_obj["msg"]).c_str());
                if (shape_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(shape_obj["running"]).c_str());
                  display.printf(" running: %s\n", String(shape_obj["running"]).c_str());
                }
            } else {
              if (shape_obj.hasOwnProperty("running")) {
                  Serial.print("running : ");
                  Serial.println(String(shape_obj["running"]).c_str());
                  display.setCursor(0, 35);
                  display.printf(" running: %s\n", String(shape_obj["running"]).c_str());
              }
            }

            if (shape_obj.hasOwnProperty("num")) {
                shape_cnt = (int)shape_obj["num"];
                Serial.printf("num = %d\n", shape_cnt);
                display.printf(" num: %d\n", shape_cnt);
            }

            if (shape_obj.hasOwnProperty("shape")) {
                JSONVar obj_arr = shape_obj["shape"];
                for (int i = 0; i < (int)shape_cnt; i++) {
                    display.fillRect(0, 80, 320, 160, TFT_WHITE);
                    display.setCursor(0, 80);
                    if (JSON.typeof(obj_arr[i]) != "undefined") {
                        String name = String(obj_arr[i]["name"]);
                        int x = (int)obj_arr[i]["x"];
                        int y = (int)obj_arr[i]["y"];
                        int w = (int)obj_arr[i]["w"];
                        int h = (int)obj_arr[i]["h"];
                        int area = (int)obj_arr[i]["area"];

                        Serial.printf("------[shape %d]------\n", i);
                        Serial.printf("\tname: %s\n", name.c_str());
                        Serial.printf("\tx: %d\n", x);
                        Serial.printf("\ty: %d\n", y);
                        Serial.printf("\tw: %d\n", w);
                        Serial.printf("\th: %d\n", h);
                        Serial.printf("\tarea: %d\n", area);

                        display.printf("shape %d:\n", i);
                        display.printf(" name: %s\n", name.c_str());
                        display.printf(" x:%d, y:%d\n", x, y);
                        display.printf(" w:%d, h:%d\n", w, h);
                        display.printf(" area: %d\n", area);
                    }
                    delay(200);
                }
            }
            Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }
} 

下図左側の画像をスキャンすると、右側の図のような検出結果が表示されます。

On This Page