Help us understand the problem. What is going on with this article?

Wi-FiがないM5StickVを、M5StickCと繋ぎLINEに投稿してみるまでの手順

概要


M5StickVには、WifiやBlueToothなどの通信機能が付いていません。そこで、WifiやBlueToothと接続する機能のあるM5StickCとつなげてみました。M5StickVとM5StickCとをGroveポートで繋ぎ、M5StickVとM5StickCとでUART通信できるようにしました。

機材

M5StickV
RISC-Vとニューラルネットワークプロセッサ(KPU)搭載のK210を内蔵したAIカメラです。
https://www.switch-science.com/catalog/5700/
M5StickVの開発環境は、maixpyを使いました。
https://maixpy.sipeed.com/en/
M5StickC
ESP32を搭載した小型のM5Stackです。
https://www.switch-science.com/catalog/5517/
M5StickCの開発環境は、arduinoを使いました。
https://docs.m5stack.com/#/ja/core/m5stickc

準備

M5StickVでUART通信を準備する

M5StickVのGroveポートは、GPIOの34番と35番です。

https://maixpy.sipeed.com/en/libs/Maix/fpioa.html
FPIOA (Field Programmable Input and Output Array)という機能で、GPIOの34番と35番をUARTに割り付けます。

from fpioa_manager import fm
from machine import UART
fm.register(35, fm.fpioa.UART2_TX, force=True)
fm.register(34, fm.fpioa.UART2_RX, force=True)

M5StickVでUART通信で送信する

UARTで文字を送る場合、maixpyのwrite関数を使います。
本稿執筆時点(2019/7/31)で、英語のmaixpyのUARTのドキュメントはないのですが、中国語のドキュメントはあったので、これを参照しました。
https://maixpy.sipeed.com/zh/libs/machine/uart.html

uart_Port = UART(UART.UART2, 115200,8,0,0, timeout=1000, read_buf_len= 4096)
data_packet = bytearray([0x00,0x00,0x00,0x00,0x00])
uart_Port.write(data_packet )

M5StickCでUART通信を準備する

M5StickCのGroveポートは、GPIOの32番と33番です。

HardwareSerial serial_ext(2);
serial_ext.begin(115200, SERIAL_8N1, 32, 33);

M5StickCでUART通信を受信する

arduinoでは、UARTから、1byteデータを受信する場合は、readByte関数を使います。

if (serial_ext.available()) {
uint8_t rx_buffer;
rx_buffer= serial_ext.readByte(rx_buffer);
}

arduinoでは、UARTから、複数byteデータを受信する場合は、readBytes関数を使います。

if (serial_ext.available()) {
uint8_t rx_buffer[10];
int rx_size = serial_ext.readBytes(rx_buffer, 10);
}

実装


M5StickVのボタンを押したときに、M5StickVは撮影した画像データをM5StickCにUART通信で送信し、M5StickCでは画像データをUART通信から受信してLINE投稿するように実装しました。

識別用パケットの実装

UART通信で、大サイズのデータを送信する場合、データがどこから始まるのかを検出できるようにしないといけません。
そこで、データの先端に識別用のパケットを埋め込む方法を取りました。

M5StickV (MaixPY)

M5StickV (MaixPY)では、データがどこから始まるのかを検出できるようにするために、データの前に0xFF,0xD8,0xEAの識別用パケットdata_packet を送信するデータに付与します。また、識別用パケットに画像データサイズを格納します。画像データサイズは1byteでは収まらないため、3byteに分割します。

img_size1 = (img.size()& 0xFF0000)>>16
img_size2 = (img.size()& 0x00FF00)>>8
img_size3 = (img.size()& 0x0000FF)>>0
data_packet = bytearray([0xFF,0xD8,0xEA,0x01,img_size1,img_size2,img_size3,0x00,0x00,0x00])
uart_Port.write(data_packet)
uart_Port.write(img_buf)

M5StickC (Arduino)

M5StickC (Arduino)では、データの先頭に0xFF,0xD8,0xEAの識別用パケットがついていた場合にデータの受信を開始します。
識別用パケットに画像データサイズも3byteに分けて格納されていますので、画像データサイズを復号します。

static const uint8_t packet_begin[3] = { 0xFF, 0xD8, 0xEA };

 if (serial_ext.available()) {
    uint8_t rx_buffer[10];
    int rx_size = serial_ext.readBytes(rx_buffer, 10);
    if (rx_size == 10) {   //packet receive of packet_begin
      if ((rx_buffer[0] == packet_begin[0]) && (rx_buffer[1] == packet_begin[1]) && (rx_buffer[2] == packet_begin[2])) {
        //image size receive of packet_begin
        jpeg_data.length = (uint32_t)(rx_buffer[4] << 16) | (rx_buffer[5] << 8) | rx_buffer[6];
        int rx_size = serial_ext.readBytes(jpeg_data.buf, jpeg_data.length);
      }
    }
  }

M5StickV (MaixPY) のソースコード

M5StickV でAボタンが押されたら、写真データをUARTに送信するソ-スコードです。


## This Source is M5StickV MaixPy
import network, socket, time, sensor, image,lcd
from Maix import GPIO
from fpioa_manager import fm, board_info
from machine import UART

#M5StickV Camera Start
clock = time.clock()
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
sensor.skip_frames(time = 2000)
#M5StickV GPIO_UART
fm.register(35, fm.fpioa.UART2_TX, force=True)
fm.register(34, fm.fpioa.UART2_RX, force=True)
uart_Port = UART(UART.UART2, 115200,8,0,0, timeout=1000, read_buf_len= 4096)
#M5StickV ButtonA
but_a=GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP)
while True:
    clock.tick()
    img = sensor.snapshot()
    lcd.display(img)
#   IF Button A Push Then Image Send UART
    if but_a.value() == 0:
        img_buf = img.compress(quality=70)
        img_size1 = (img.size()& 0xFF0000)>>16
        img_size2 = (img.size()& 0x00FF00)>>8
        img_size3 = (img.size()& 0x0000FF)>>0
        data_packet = bytearray([0xFF,0xD8,0xEA,0x01,img_size1,img_size2,img_size3,0x00,0x00,0x00])
        uart_Port.write(data_packet)
        uart_Port.write(img_buf)
        time.sleep(1.0)
#   Send UART End
uart_Port.deinit()
del uart_Port
print("finish")



M5StickC (Arduino)のソースコード

UARTから、写真データを受信するソ-スコードです。
読み取ったパケットが[0xFF,0xD8,0xEA]から始まるデータだった場合に、画像データの読み取りを行います。
-今回は、画像データをLINEに投稿してみました。
+さらに、今回は、受信した画像データをLINEに投稿してみました。

#include <M5StickC.h>
#include <WiFi.h>
#include <ssl_client.h>
#include <WiFiClientSecure.h>
const char* ssid = "your_ssid";
const char* passwd = "your_passwd";

HardwareSerial serial_ext(2);

typedef struct {
  uint32_t length;
  uint8_t *buf;
} jpeg_data_t;

jpeg_data_t jpeg_data;
static const int RX_BUF_SIZE = 20000;
static const uint8_t packet_begin[3] = { 0xFF, 0xD8, 0xEA };

/*
sendLineNotify関数は、以下参照。
https://github.com/anoken/purin_wo_mimamoru_gijutsu/blob/master/2_6_M5Camera_Send_LineNotify/2_6_M5Camera_Send_LineNotify.ino
*/
void sendLineNotify(uint8_t* image_data, size_t image_sz);

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 30, 4);
  M5.Lcd.println("m5stick_uart_wifi_converter");

  setup_wifi();

  jpeg_data.buf = (uint8_t *) malloc(sizeof(uint8_t) * RX_BUF_SIZE);
  jpeg_data.length = 0;
  if (jpeg_data.buf == NULL) {
    Serial.println("malloc jpeg buffer 1 error");
  }

  serial_ext.begin(115200, SERIAL_8N1, 32, 33);
}

void loop() {
  M5.update();

  if (serial_ext.available()) {
    uint8_t rx_buffer[10];
    int rx_size = serial_ext.readBytes(rx_buffer, 10);
    if (rx_size == 10) {   //packet receive of packet_begin
      if ((rx_buffer[0] == packet_begin[0]) && (rx_buffer[1] == packet_begin[1]) && (rx_buffer[2] == packet_begin[2])) {
        //image size receive of packet_begin
        jpeg_data.length = (uint32_t)(rx_buffer[4] << 16) | (rx_buffer[5] << 8) | rx_buffer[6];
        int rx_size = serial_ext.readBytes(jpeg_data.buf, jpeg_data.length);

        //image processing, for example, line notify send image
        sendLineNotify(jpeg_data.buf, jpeg_data.length);
        //image processing end
      }
    }
  }
  vTaskDelay(10 / portTICK_RATE_MS);
}

void setup_wifi() {
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, passwd);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


LINE Notifyに画像を投稿するsendLineNotify関数は、冗長になることから割愛しています。
以下の「プリンを見守る技術」のgithubに掲載されています。
https://github.com/anoken/purin_wo_mimamoru_gijutsu/blob/master/2_6_M5Camera_Send_LineNotify/2_6_M5Camera_Send_LineNotify.ino

参考文献

Maixpy_m5stickv
https://github.com/sipeed/MaixPy/
MaixPy_scripts EXAMPLE
https://github.com/sipeed/MaixPy_scripts/
プリンを守る技術 ~その1:LINEへの通知~
https://qiita.com/nnn112358/items/8d2021bce1113d7e60ce
プリンを見守る技術
https://github.com/anoken/purin_wo_mimamoru_gijutsu/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした