pdf-icon

Arduino Quick Start

2. Devices & Examples

6. Applications

UnitV/StickV Arduino Tutorial

1. Preparation

2. Notes

Pin Compatibility
Due to different pin configurations for each host, to make it easier for users to use, M5Stack officially provides a pin compatibility table. Please modify the sample program according to the actual pin connection.

3. Compile and Upload

  • Select the device port (for details refer to Program Compilation and Burning), click the compile/upload button in the upper left corner of Arduino IDE, and wait for the program to compile and upload to the device.

4. Example Program

Note
1.The settings and returned data format of UnitV/StickV are both JSON. Details of the JSON data format for each function can be found here.
2.UnitV/StickV must be powered via the USB Type-C interface to work. After inserting or removing the USB Type-C connector, the unit will reboot.
3.The firmware in M5Burner does not have default parameter settings for all functions, and the parameters set on this unit will be lost after power off. Therefore, it is necessary to reconfigure the settings each time after a power cycle.

All the examples below have the host configure and parse the JSON data from UnitV/StickV, not switch the UnitV/StickV functions. To switch functions, please use M5Burner to burn the corresponding functional firmware to UnitV/StickV.
The firmware page is shown below:

Motion Target Detection

The motion target detection function can be configured with two detection modes: static detection mode (COMPUTE_MODE_STATIC) and dynamic detection mode (COMPUTE_MODE_DYNAMIC). The default in M5Burner firmware is dynamic detection mode.

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
#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("UnitV 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["MOTION DETECT"] = 1.0;                     // Not optional                     
    obj["mode"] = "COMPUTE_MODE_DYNAMIC";           // "COMPUTE_MODE_STATIC" or "COMPUTE_MODE_DYNAMIC"
    obj["thr_w"] = 20;                              // optional
    obj["thr_h"] = 20;                              // optional
    obj["stepx"] = 1;                               // optional
    obj["stepy"] = 2;                               // optional
    obj["delta"] = 20;                              // optional
    obj["merge"] = 10;                              // optional
}

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_detect_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(motion_detect_obj) == "undefined")){
        display.fillRect(0, 35, 320, 205, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack Motion Detect V-Func example");
        if (motion_detect_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) motion_detect_obj["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) motion_detect_obj["FUNC"]);
        }
        if (motion_detect_obj.hasOwnProperty("DIFF TOTAL")) {
          Serial.print("Diff TOTAL = ");
          Serial.println((int)motion_detect_obj["DIFF TOTAL"]);
          display.printf(" Diff TOTAL: %d\n", (int)motion_detect_obj["DIFF TOTAL"]);
        }
        if (motion_detect_obj.hasOwnProperty("DIFF MAX")) {
          Serial.print("Diff MAX = ");
          Serial.println((int)motion_detect_obj["DIFF MAX"]);
          display.printf(" Diff MAX: %d\n", (int)motion_detect_obj["DIFF MAX"]);
        }

        if (motion_detect_obj.hasOwnProperty("TOTAL")) {
          motion_cnt = (int)motion_detect_obj["TOTAL"];
          Serial.printf("Motion number = %d\n", motion_cnt);
          display.printf(" Motion number: %d\n", motion_cnt);
        }
        for (int i = 0; i < motion_cnt; i++) {
          display.setCursor(0, 120);
          display.fillRect(0, 120, 320, 130, TFT_WHITE);
          Serial.print("Motion ");
          Serial.print(i);
          display.printf("Motion %d:", i);
          Serial.print(":\r\n\tX:");
          Serial.println((int) motion_detect_obj[String(i)]["x"]);
          display.printf("\r\n\t X: %d", (int) motion_detect_obj[String(i)]["x"]);
          Serial.print("\tY:");
          Serial.println((int) motion_detect_obj[String(i)]["y"]);
          display.printf("\r\n\t Y: %d", (int) motion_detect_obj[String(i)]["y"]);
          Serial.print("\tWidth:");
          Serial.println((int) motion_detect_obj[String(i)]["w"]);
          display.printf("\r\n\t Width: %d", (int) motion_detect_obj[String(i)]["w"]);
          Serial.print("\tHeight:");
          Serial.println((int) motion_detect_obj[String(i)]["h"]);
          display.printf("\r\n\t Height: %d", (int) motion_detect_obj[String(i)]["h"]);
          Serial.print("\tArea:");
          Serial.println((int) motion_detect_obj[String(i)]["area"]);
          display.printf("\r\n\t Area: %d", (int) motion_detect_obj[String(i)]["area"]);
          delay(500);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      } else {
        return;
      }
    }
}

The above example uses dynamic detection mode. When StickV/UnitV detects object motion, it will provide real-time feedback on the object's position and other data. The detection result is as shown below.

Object Tracking

The object tracking function requires capturing the target object's information in the current camera frame after UnitV/StickV powers on to function properly. The capture start point and width/height parameter configuration code is shown below. To customize the capture position, please modify here.

    obj["x"] = 80;  //start point x-coordinate           
    obj["y"] = 0;   //start point y-coordinate                             
    obj["w"] = 100; //width                            
    obj["h"] = 100; //height

The example below sends parameter data once after the host powers on. At that time, the StickV screen appears as shown below. Make sure the tracking target is within the yellow capture box.

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
#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("UnitV 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["TARGET TRACKER"] = " V1.0";                     
    obj["x"] = 80;            
    obj["y"] = 0;                              
    obj["w"] = 100;                              
    obj["h"] = 100;                               
    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 object = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(object) == "undefined")){
        display.fillRect(0, 35, 320, 205, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack Target Tracker V-Func example");
        if (object.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) object["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) object["FUNC"]);
        }
        if (object.hasOwnProperty("x")) {
          Serial.print("X: ");
          Serial.println((int) object["x"]);
          display.printf(" X: %d\n", (int) object["x"]);
        }
        if (object.hasOwnProperty("y")) {
          Serial.print("Y: ");
          Serial.println((int) object["y"]);
          display.printf(" Y: %d\n", (int) object["y"]);
        }
        if (object.hasOwnProperty("w")) {
          Serial.print("Width: ");
          Serial.println((int) object["w"]);
          display.printf(" Width: %d\n", (int) object["w"]);
        }
        if (object.hasOwnProperty("h")) {
          Serial.print("Height: ");
          Serial.println((int) object["h"]);
          display.printf(" Height: %d\n", (int) object["h"]);
        }
        display.waitDisplay();
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      } else {
        return;
      }
    }
}

After successfully capturing the target object data, the host will display and print the object's position and other data in real time. The detection result is as shown below.

Color Tracking

The color tracking function requires setting the target color parameters after UnitV/StickV powers on in order to operate correctly. The color parameters can be obtained using the LAB Color Picker Tool.

Steps for obtaining and configuring the color parameters:

  • After opening the tool, click open at the lower part of the interface to open the sample image (this example's sample image), then click the specific area in the image to sample. Determine the final color parameters according to the white area below (i.e., the specific sampling position).
  • Fill the LAB color from the image above into the code below in order from left to right (from top to bottom).
    obj["Lmin"] = 0;               
    obj["Lmax"] = 100;              
    obj["Amin"] = 51;               
    obj["Amax"] = 61;               
    obj["Bmin"] = 34;               
    obj["Bmax"] = 44;
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
#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("UnitV Json Example", 2, 2);
    display.drawLine(0, 20, 320, 20, TFT_BLACK);

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

    //Setting JSON
    JSONVar obj;
    obj["COLOR TRACKER"] = 1.0;    
    obj["thr_w"] = 20;             
    obj["thr_h"] = 20;             
    obj["stepx"] = 2;              
    obj["stepy"] = 2;              
    obj["merge"] = 10;             
    //Please fill in the below six parameters with the values extracted from the LAB color selection tool.
    obj["Lmin"] = 0;               
    obj["Lmax"] = 100;              
    obj["Amin"] = 51;               
    obj["Amax"] = 61;               
    obj["Bmin"] = 34;               
    obj["Bmax"] = 44;               
    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 color_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(color_obj) == "undefined")) {
        display.fillRect(0, 35, 320, 205, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack Color Tracker V-Func example");
        if (color_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) color_obj["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) color_obj["FUNC"]);
        }
        int box_cnt = 0;
        if (color_obj.hasOwnProperty("TOTAL")) {
          box_cnt = (int)color_obj["TOTAL"];
          Serial.printf("Box number = %d\n", box_cnt);
          display.printf(" Box number: %d\n", box_cnt);
        }
        for (int i = 0; i < box_cnt; i++) {
          Serial.print("Box ");
          Serial.print(i);
          display.printf("Box %d:", i);
          Serial.print(":\r\n\tX:");
          Serial.println((int) color_obj[String(i)]["x"]);
          display.printf("\r\n\t X: %d", (int) color_obj[String(i)]["x"]);
          Serial.print("\tY:");
          Serial.println((int) color_obj[String(i)]["y"]);
          display.printf("\r\n\t Y: %d", (int) color_obj[String(i)]["y"]);
          Serial.print("\tWidth:");
          Serial.println((int) color_obj[String(i)]["w"]);
          display.printf("\r\n\t Width: %d", (int) color_obj[String(i)]["w"]);
          Serial.print("\tHeight:");
          Serial.println((int) color_obj[String(i)]["h"]);
          display.printf("\r\n\t Height: %d", (int) color_obj[String(i)]["h"]);
          Serial.print("\tArea:");
          Serial.println((int) color_obj[String(i)]["area"]);
          display.printf("\r\n\t Area: %d\r\n\t", (int) color_obj[String(i)]["area"]);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      }
      delay(50);
    }
} 

When the program runs successfully, the host will display and print the tracked color block's position, size, quantity, and other data in real time. (In the case of multiple tracked color blocks, it is recommended to view the feedback data via serial monitor.) Detection result is as shown below.

Face Detection

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
#include <M5Unified.h>
#include <M5GFX.h>
#include <Arduino_JSON.h>

M5GFX display;
int face_cnt;

void setup() {

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

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

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 face_detect_obj = JSON.parse(line);

    // JSON.typeof(jsonVar) can be used to get the type of the var
    if (!(JSON.typeof(face_detect_obj) == "undefined")) {
      display.fillRect(0, 35, 320, 205, TFT_WHITE);
      // display.drawString("Parsing Json succeed!", 5, 30);
      Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
      Serial.println("M5Stack Face Detect V-Func example");
      if (face_detect_obj.hasOwnProperty("FUNC")) {
        Serial.print("V-Function = ");
        Serial.println((const char*)face_detect_obj["FUNC"]);
        display.setCursor(0, 35);
        display.printf(" V-Fun: %s\n", (const char*)face_detect_obj["FUNC"]);
      }

      if (face_detect_obj.hasOwnProperty("count")) {
        face_cnt = (int)face_detect_obj["count"];
        Serial.printf("Face number = %d\n", face_cnt);
        display.printf(" Face number: %d\n", face_cnt);
      }

      for (int i = 0; i < face_cnt; i++) {
        Serial.print("Face ");
        Serial.print(i + 1);
        display.printf("Face %d:", i);
        Serial.print(":\r\n\tX:");
        Serial.println((int)face_detect_obj[String(i)]["x"]);
        display.printf("\r\n\t X: %d", (int)face_detect_obj[String(i)]["x"]);
        Serial.print("\tY:");
        Serial.println((int)face_detect_obj[String(i)]["y"]);
        display.printf("\r\n\t Y: %d", (int)face_detect_obj[String(i)]["y"]);
        Serial.print("\tWidth:");
        Serial.println((int)face_detect_obj[String(i)]["w"]);
        display.printf("\r\n\t Width: %d", (int)face_detect_obj[String(i)]["w"]);
        Serial.print("\tHeight:");
        Serial.println((int)face_detect_obj[String(i)]["h"]);
        display.printf("\r\n\t Height: %d", (int)face_detect_obj[String(i)]["h"]);
        Serial.print("\tConfidence:");
        Serial.println(face_detect_obj[String(i)]["value"]);
        display.printf("\r\n\t Confidence:");
        display.println(face_detect_obj[String(i)]["value"]);
      }
      Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    } else {
      return;
    }
  }
} 

Scan the face on the left side below, and the detection result is as shown on the right.

QR Code Recognition

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;

void setup() {

    display.begin();
    display.setRotation(1);
    display.clear(TFT_WHITE);
    display.setFont(&fonts::FreeMonoBold9pt7b);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV 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["FIND CODE"] = 1.0;                    
    obj["mode"] = "QRCODE";      // Recognition mode, optional: QRCODE, APRILTAG, DATAMATRIX, BARCODE
    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 code_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(code_obj) == "undefined")){
        display.fillRect(0, 35, 320, 205, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack QRCode Detect V-Func example");
        if (code_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) code_obj["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) code_obj["FUNC"]);
        }
        int qrcode_cnt = 0;
        if (code_obj.hasOwnProperty("count")) {
          qrcode_cnt = (int)code_obj["count"];
          Serial.printf("QR Code number = %d\n", qrcode_cnt);
          display.printf(" QR Code number: %d\n", qrcode_cnt);
        }
        for (int i = 0; i < qrcode_cnt; i++) {
          Serial.print("QRCode ");
          Serial.print(i);
          display.printf("QRCode %d:", i);
          Serial.print(":\r\n\tX:");
          Serial.println((int) code_obj[String(i)]["x"]);
          display.printf("\r\n\t X: %d", (int) code_obj[String(i)]["x"]);
          Serial.print("\tY:");
          Serial.println((int) code_obj[String(i)]["y"]);
          display.printf("        Y: %d", (int) code_obj[String(i)]["y"]);
          Serial.print("\tWidth:");
          Serial.println((int) code_obj[String(i)]["w"]);
          display.printf("\r\n\t Width: %d", (int) code_obj[String(i)]["w"]);
          Serial.print("\tHeight:");
          Serial.println((int) code_obj[String(i)]["h"]);
          display.printf("    Height: %d", (int) code_obj[String(i)]["h"]);
          Serial.print("\tPayload:");
          Serial.println((const char*) code_obj[String(i)]["payload"]);
          display.printf("\r\n\t Payload: %s", (const char*) code_obj[String(i)]["payload"]);
          Serial.print("\tVersion:");
          Serial.println((int) code_obj[String(i)]["version"]);
          display.printf("\r\n\t Version: %d", (int) code_obj[String(i)]["version"]);
          Serial.print("\tECC Level:");
          Serial.println((int) code_obj[String(i)]["ecc_level"]);
          display.printf("\r\n\t ECC Level: %d", (int) code_obj[String(i)]["ecc_level"]);
          Serial.print("\tMask:");
          Serial.println((int) code_obj[String(i)]["mask"]);
          display.printf("\r\n\t Mask: %d", (int) code_obj[String(i)]["mask"]);
          Serial.print("\tData Type:");
          Serial.println((int) code_obj[String(i)]["data_type"]);
          display.printf("\r\n\t Data Type: %d", (int) code_obj[String(i)]["data_type"]);
          Serial.print("\tECI:");
          Serial.println((int) code_obj[String(i)]["eci"]);
          display.printf("\r\n\t ECI: %d", (int) code_obj[String(i)]["eci"]);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      }
      delay(50);
    }
}

Scan the QR code on the left side below, and the detection result is as shown on the right.

Barcode Recognition

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
#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("UnitV Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);

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

    JSONVar obj;
    obj["FIND CODE"] = 1.0;        
    obj["mode"] = "BARCODE";       // Recognition mode, optional: QRCODE, APRILTAG, DATAMATRIX, BARCODE
    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 code_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(code_obj) == "undefined")){
        display.fillRect(0, 35, 320, 205, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack Barcode Detect V-Func example");
        if (code_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) code_obj["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) code_obj["FUNC"]);
        }
        int barcode_cnt = 0;
        if (code_obj.hasOwnProperty("count")) {
          barcode_cnt = (int)code_obj["count"];
          Serial.printf("Barcode number = %d\n", barcode_cnt);
          display.printf(" Barcode number: %d\n", barcode_cnt);
        }
        for (int i = 0; i < barcode_cnt; i++) {
          Serial.print("Barcode ");
          Serial.print(i);
          display.printf("Barcode %d:", i);
          Serial.print(":\r\n\tX:");
          Serial.println((int) code_obj[String(i)]["x"]);
          display.printf("\r\n\t X: %d", (int) code_obj[String(i)]["x"]);
          Serial.print("\tY:");
          Serial.println((int) code_obj[String(i)]["y"]);
          display.printf("\r\n\t Y: %d", (int) code_obj[String(i)]["y"]);
          Serial.print("\tWidth:");
          Serial.println((int) code_obj[String(i)]["w"]);
          display.printf("\r\n\t Width: %d", (int) code_obj[String(i)]["w"]);
          Serial.print("\tHeight:");
          Serial.println((int) code_obj[String(i)]["h"]);
          display.printf("\r\n\t Height: %d", (int) code_obj[String(i)]["h"]);
          Serial.print("\tPayload:");
          Serial.println((const char*) code_obj[String(i)]["payload"]);
          display.printf("\r\n\t Payload: %s", (const char*) code_obj[String(i)]["payload"]);
          Serial.print("\tType:");
          Serial.println((int) code_obj[String(i)]["type"]);
          display.printf("\r\n\t Type: %d", (int) code_obj[String(i)]["type"]);
          Serial.print("\tRotation:");
          Serial.println((double) code_obj[String(i)]["rotation"]);
          display.printf("\r\n\t Rotation: %f", (double) code_obj[String(i)]["rotation"]);
          Serial.print("\tQuality:");
          Serial.println((int) code_obj[String(i)]["quality"]);
          display.printf("\r\n\t Quality: %d", (int) code_obj[String(i)]["quality"]);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      }
      delay(50);
    }
}

Scan the barcode below, and the detection result is as shown.

Datamatrix Code Recognition

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
#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("UnitV Json Example", 5, 5);
    display.drawLine(0, 25, 320, 25, TFT_BLACK);

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

    JSONVar obj;
    obj["FIND CODE"] = 1.0;                   
    obj["mode"] = "DATAMATRIX";      // Recognition mode, optional: QRCODE, APRILTAG, DATAMATRIX, BARCODE
    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 code_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(code_obj) == "undefined")){
        display.fillRect(0, 40, 320, 200, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack DataMatrix Detect V-Func example");
        if (code_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) code_obj["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) code_obj["FUNC"]);
        }
        int dm_cnt = 0;
        if (code_obj.hasOwnProperty("count")) {
          dm_cnt = (int)code_obj["count"];
          Serial.printf("DataMatrix number = %d\n", dm_cnt);
          display.printf(" DataMatrix number: %d\n", dm_cnt);
        }
        for (int i = 0; i < dm_cnt; i++) {
          Serial.print("DataMatrix ");
          Serial.print(i);
          display.printf("DataMatrix %d:", i);
          Serial.print(":\r\n\tX:");
          Serial.println((int) code_obj[String(i)]["x"]);
          display.printf("\r\n\t X: %d", (int) code_obj[String(i)]["x"]);
          Serial.print("\tY:");
          Serial.println((int) code_obj[String(i)]["y"]);
          display.printf("       Y: %d", (int) code_obj[String(i)]["y"]);
          Serial.print("\tWidth:");
          Serial.println((int) code_obj[String(i)]["w"]);
          display.printf("\r\n\t Width: %d", (int) code_obj[String(i)]["w"]);
          Serial.print("\tHeight:");
          Serial.println((int) code_obj[String(i)]["h"]);
          display.printf("    Height: %d", (int) code_obj[String(i)]["h"]);
          Serial.print("\tPayload:");
          Serial.println((const char*) code_obj[String(i)]["payload"]);
          display.printf("\r\n\t Payload: %s", (const char*) code_obj[String(i)]["payload"]);
          Serial.print("\tRotation:");
          Serial.println((double) code_obj[String(i)]["rotation"]);
          display.printf("\r\n\t Rotation: %f", (double) code_obj[String(i)]["rotation"]);
          Serial.print("\tRows:");
          Serial.println((int) code_obj[String(i)]["rows"]);
          display.printf("\r\n\t Rows: %d", (int) code_obj[String(i)]["rows"]);
          Serial.print("\tColumns:");
          Serial.println((int) code_obj[String(i)]["columns"]);
          display.printf("     Columns: %d", (int) code_obj[String(i)]["columns"]);
          Serial.print("\tCapacity:");
          Serial.println((int) code_obj[String(i)]["capacity"]);
          display.printf("\r\n\t Capacity: %d", (int) code_obj[String(i)]["capacity"]);
          Serial.print("\tPadding:");
          Serial.println((int) code_obj[String(i)]["padding"]);
          display.printf("\r\n\t Padding: %d", (int) code_obj[String(i)]["padding"]);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      }
      delay(50);
    }
}

Scan the Datamatrix code on the left side below, and the detection result is as shown on the right.

Apriltag Code Recognition

Note
UnitV/StickV only supports detecting Apriltag codes from the TAG36H11 family.
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
#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::Font2);
    display.setTextColor(TFT_BLACK);
    delay(100);
    display.drawString("UnitV Json Example", 2, 2);
    display.drawLine(0, 20, 320, 20, TFT_BLACK);

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

    JSONVar obj;
    obj["FIND CODE"] = 1.0;                    
    obj["mode"] = "APRILTAG";      // Recognition mode, optional: QRCODE, APRILTAG, DATAMATRIX, BARCODE
    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 code_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(code_obj) == "undefined")){
        display.fillRect(0, 25, 320, 215, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack AprilTag Detect V-Func example");
        if (code_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) code_obj["FUNC"]);
          display.setCursor(0, 25);
          display.printf(" V-Fun: %s\n", (const char*) code_obj["FUNC"]);
        }
        int april_cnt = 0;
        if (code_obj.hasOwnProperty("count")) {
          april_cnt = (int)code_obj["count"];
          Serial.printf("AprilTag number = %d\n", april_cnt);
          display.printf(" AprilTag number: %d\n", april_cnt);
        }
        for (int i = 0; i < april_cnt; i++) {
          Serial.print("AprilTag ");
          Serial.print(i);
          display.printf("AprilTag %d:", i);
          Serial.print(":\r\n\tX:");
          Serial.println((int) code_obj[String(i)]["x"]);
          display.printf("  X: %d", (int) code_obj[String(i)]["x"]);
          Serial.print("\tY:");
          Serial.println((int) code_obj[String(i)]["y"]);
          display.printf("  Y: %d", (int) code_obj[String(i)]["y"]);
          Serial.print("\tWidth:");
          Serial.println((int) code_obj[String(i)]["w"]);
          display.printf("  Width: %d", (int) code_obj[String(i)]["w"]);
          Serial.print("\tHeight:");
          Serial.println((int) code_obj[String(i)]["h"]);
          display.printf("  Height: %d", (int) code_obj[String(i)]["h"]);
          Serial.print("\tID:");
          Serial.println((int) code_obj[String(i)]["id"]);
          display.printf("\r\n\t ID: %d", (int) code_obj[String(i)]["id"]);
          Serial.print("\tFamily:");
          Serial.println((int) code_obj[String(i)]["family"]);
          display.printf("    Family: %d", (int) code_obj[String(i)]["family"]);
          Serial.print("\tCX:");
          Serial.println((int) code_obj[String(i)]["cx"]);
          display.printf("    CX: %d", (int) code_obj[String(i)]["cx"]);
          Serial.print("\tCY:");
          Serial.println((int) code_obj[String(i)]["cy"]);
          display.printf("    CY: %d", (int) code_obj[String(i)]["cy"]);
          Serial.print("\tRotation:");
          Serial.println((double) code_obj[String(i)]["rotation"]);
          display.printf("\r\n\t Rotation: %f", (double) code_obj[String(i)]["rotation"]);
          Serial.print("\tDecision margin:");
          Serial.println((double) code_obj[String(i)]["decision_margin"]);
          display.printf("\r\n\t Decision margin: %f", (double) code_obj[String(i)]["decision_margin"]);
          Serial.print("\tHamming:");
          Serial.println((int) code_obj[String(i)]["hamming"]);
          display.printf("    Hamming: %d", (int) code_obj[String(i)]["hamming"]);
          Serial.print("\tGoodness:");
          Serial.println((double) code_obj[String(i)]["goodness"]);
          display.printf("\r\n\t Goodness: %f", (double) code_obj[String(i)]["goodness"]);
          Serial.print("\tX translation:");
          Serial.println((double) code_obj[String(i)]["x_translation"]);
          display.printf("\r\n\t X translation: %f", (double) code_obj[String(i)]["x_translation"]);
          Serial.print("\tY translation:");
          Serial.println((double) code_obj[String(i)]["y_translation"]);
          display.printf("\r\n\t Y translation: %f", (double) code_obj[String(i)]["y_translation"]);
          Serial.print("\tZ translation:");
          Serial.println((double) code_obj[String(i)]["z_translation"]);
          display.printf("\r\n\t Z translation: %f", (double) code_obj[String(i)]["z_translation"]);
          Serial.print("\tX rotation:");
          Serial.println((double) code_obj[String(i)]["x_rotation"]);
          display.printf("\r\n\t X rotation: %f", (double) code_obj[String(i)]["x_rotation"]);
          Serial.print("\tY rotation:");
          Serial.println((double) code_obj[String(i)]["y_rotation"]);
          display.printf("\r\n\t Y rotation: %f", (double) code_obj[String(i)]["y_rotation"]);
          Serial.print("\tZ rotation:");
          Serial.println((double) code_obj[String(i)]["z_rotation"]);
          display.printf("\r\n\t Z rotation: %f", (double) code_obj[String(i)]["z_rotation"]);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      }
      delay(50);
    }
}

Scan the Apriltag on the left side below, and the detection result is as shown on the right.

Line Tracking

The line tracking function requires setting the line color parameters after UnitV/StickV powers on to operate correctly. These color parameters can be obtained using the LAB Color Picker Tool.

The process for obtaining and configuring the color parameters is the same as in Color Tracking. The example image of the weight sampling area is shown below. Please set the proportion values according to your own needs.

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
#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("UnitV 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["LINE  TRACKER"] = 1.0;    
    obj["thr_w"] = 20;             
    obj["thr_h"] = 20;             
    obj["stepx"] = 2;              
    obj["stepy"] = 2;              
    obj["merge"] = 10;             
    //Please fill in the below six parameters with the values extracted from the LAB color selection tool.
    obj["Lmin"] = 0;               
    obj["Lmax"] = 100;              
    obj["Amin"] = 51;               
    obj["Amax"] = 61;               
    obj["Bmin"] = 34;               
    obj["Bmax"] = 44;                
    obj["weight_0"] = 0.1;          
    obj["weight_1"] = 0.3;          
    obj["weight_2"] = 0.6;          
    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 line_obj = JSON.parse(line);

      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (!(JSON.typeof(line_obj) == "undefined")){
        display.fillRect(0, 40, 320, 200, TFT_WHITE);
        Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Serial.println("M5Stack Line Tracker V-Func example");
        if (line_obj.hasOwnProperty("FUNC")) {
          Serial.print("V-Function = ");
          Serial.println((const char*) line_obj["FUNC"]);
          display.setCursor(0, 35);
          display.printf(" V-Fun: %s\n", (const char*) line_obj["FUNC"]);
        }
        if (line_obj.hasOwnProperty("angle")) {
          Serial.print("Angle: ");
          Serial.println((double) line_obj["angle"]);
          display.printf(" Angle: %f\n", (double) line_obj["angle"]);
        }
        Serial.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
      } else {
        return;
      }
    }
} 

When the program runs successfully, the host will display and print the turn angle in real time.

On This Page