Thanks to visit codestin.com
Credit goes to docs.m5stack.com

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

  • Copy and paste the example code below into your project code area as needed, then select the device port (for details, please refer to Program Compilation and Upload), click the compile and upload button in the upper left corner of the Arduino IDE, and wait for the program to complete compilation and upload to the device.

4. Example Program

Note
1. The settings and returned data format of UnitV/StickV are both JSON. Please refer to the prompts before the examples for the JSON data format of each function.
2.UnitV/StickV must be powered via the USB Type-C interface to operate. After plugging or unplugging the USB Type-C interface, this unit will restart.
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, after a power-off restart, you need to configure the settings again.

All the examples below demonstrate the host configuring and parsing the JSON data of UnitV/StickV, and do not achieve the function of switching UnitV/StickV modes. To switch functions, please go to the STICKV & UNITV interface in M5Burner and burn the corresponding functional firmware to UnitV/StickV.

Motion Target Detection

The functional firmware is as follows:

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.

For the JSON data format of the moving object detection function, see here.

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("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
    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 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 functional firmware is as follows:

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

For the JSON data format of the target tracking function, see here.

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 Tracker

The functional firmware is as follows:

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;

For the JSON data format of the color tracking function, see here.

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

The functional firmware is as follows:

For the JSON data format of the face detection function, see here.

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

The code scanning function firmware is as follows:

For the JSON data format of the QR code recognition function, see here.

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

For the JSON data format of the barcode recognition function, see here.

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

For the JSON data format of the Datamatrix code recognition function, see here.

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

For the JSON data format of the Apriltag code recognition function, see here.

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 functional firmware is as follows:

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.

For the JSON data format of the line following function, see here.

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