M5StickCでできること 〜加速度センサのデータを内蔵フラッシュに書き込む

スポンサーリンク
お役立ち情報

先日、M5StickC内蔵の加速度センサで採取した加速度データを、SDカードに保存する方法を調査しました(記事は こちら)。

例えば、加速度データを10msecおきに採取(100Hz)し、1回の採取につき1行ずつ、SDカード内のファイルに書き込んで保存していく場合、データサイズは1時間あたり360,000行、1行の文字数が30文字(30バイト)なら10,800,000 B(10.8 MB)になります。
8GBのSDカードを使う場合、約740時間(約30日)分のデータを保存できる計算になります。

これだけの期間のデータをSDカードに保存できるのであれば、SDカードスロットをつけたM5StickCをIoTデバイスとして利用し、M5StickCはデータ採取場所に常時設置したままにしておき、ときどきSDカードを取り替えに行く、という使い方で運用できそうです。

一方、別の記事では、M5StickCにつないだSDカード内のファイルを、Webサーバーに送信する方法を調査しました(記事は こちら)。
先ほどと同じ計算方法で、1分のデータ(6,000行、180 KB)程度であれば、Webサーバーに送信できることを確認できています。

つまり、採取したデータを全てSDカードに保存していくのではなく、必要なごく一部のデータだけをWebサーバー上で保存する方法であれば、テンポラリのファイル保存領域として内蔵フラッシュを用いることで、SDカードスロットを外付けする必要がなくなる可能性もあります。

そんな訳で、M5StickC内蔵フラッシュの使い方を調査することにしました。
具体的には、以下の手順で、データを採取・保存できるようにしてみたいと思います。

  • M5StickCのボタンを押したら、1秒あたり100回の頻度(100Hz)で1分間、加速度データを採取し、内蔵フラッシュの仮置きファイルに書き込む。
  • 1分間のデータ採取・書き込みが完了したら、そのファイルをWebサーバーに送信する。
  • ファイル送信が完了したら、内蔵フラッシュ内の仮置きファイルは不要になるので、そのファイルを削除する。

まずは、以下のスケッチを準備しました。
先日の記事に掲載していたものとほとんど同じで、ボタンを押したら、10msecおきに1分間、加速度データ(X, Y, Z)を採取し、SDカードに書き込んでいくものです。

#include <M5StickC.h>
#include "SD.h"

SPIClass SPI2;

File file;

const char* file_name     = "/test4.txt";
unsigned long flag        = 0;
unsigned long currentTime = 0;
unsigned long prevTime    = 0;
unsigned long startTime   = 0;
float accX = 0.0f;
float accY = 0.0f;
float accZ = 0.0f;

void setup() {
  M5.begin();
  M5.Imu.Init();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 0, 2);

  SPI2.begin(0, 36, 26, -1);
  if(!SD.begin(-1, SPI2)) {
    M5.Lcd.println("SD CARD FAIL");
    return;
  }
  M5.Lcd.println("SD CARD READY");
}

void loop() {
  M5.update();

  if(flag==1) {
    currentTime = millis();
    if(currentTime-prevTime>=10) {
      prevTime = currentTime;
      M5.IMU.getAccelData(&accX, &accY, &accZ);
      file.println((String)(currentTime-startTime) + "," + (String)accX + "," + (String)accY + "," + (String)accZ);
    }
    if(currentTime-startTime>=60000) {
      file.close();
      M5.Lcd.println("IMU FINISH");
      flag = 0;
    }
  }

  if(M5.BtnA.wasPressed() && flag==0) {
    flag = 1;
    file = SD.open(file_name, FILE_WRITE);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.println("IMU START");
    startTime = millis();
  }
}

M5StickCにSDカードスロットをつなぎ、SDカードを挿入して、上記のスケッチを実行したところ、SDカード内に「test4.txt」という約6,000行のファイルができていることを確認できました。

次に、スケッチを以下のように修正しました。
最初にWi-Fiネットワークに接続しておき、SDカードへの加速度データ書き込みが終わったら、そのファイルの内容をWebサーバーに送信します。
送信が終わったら、SDカード内のファイルは不要になるので、そのファイルを削除します。

#include <M5StickC.h>
#include <WiFi.h>
#include "esp_http_client.h"
#include "SD.h"

SPIClass SPI2;

File file;

const char* ssid          = "XXXXXXXX";
const char* password      = "XXXXXXXX";
const char* file_name     = "/test4.txt";
unsigned long var_size    = 2000;
unsigned long flag        = 0;
unsigned long currentTime = 0;
unsigned long prevTime    = 0;
unsigned long startTime   = 0;
float accX = 0.0f;
float accY = 0.0f;
float accZ = 0.0f;

void setup() {
  M5.begin();
  M5.Imu.Init();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 0, 2);

  M5.Lcd.printf("CONNECT TO %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status()!=WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");
  }
  M5.Lcd.println(" CONNECTED");

  SPI2.begin(0, 36, 26, -1);
  if(!SD.begin(-1, SPI2)) {
    M5.Lcd.println("SD CARD FAIL");
    return;
  }
  M5.Lcd.println("SD CARD READY");
}

void loop() {
  M5.update();

  if(flag==1) {
    currentTime = millis();
    if(currentTime-prevTime>=10) {
      prevTime = currentTime;
      M5.IMU.getAccelData(&accX, &accY, &accZ);
      file.println((String)(currentTime-startTime) + "," + (String)accX + "," + (String)accY + "," + (String)accZ);
    }
    if(currentTime-startTime>=60000) {
      file.close();
      M5.Lcd.println("IMU FINISH");
      flag = 0;

      file = SD.open(file_name, FILE_READ);
      M5.Lcd.print("FILE SIZE : ");
      M5.Lcd.println(file.size());
      M5.Lcd.println("FILE SEND START");

      char tmp_var[var_size+1] = "";
      esp_http_client_config_t config = {0};
      config.url    = "http://XXXXXXXX/writefile.php";
      config.method = HTTP_METHOD_POST;
      esp_http_client_handle_t client = esp_http_client_init(&config);
      esp_http_client_open(client, file.size());
      while(file.available()) {
        sprintf(tmp_var, "%s%c", tmp_var, char(file.read()));
        if(strlen(tmp_var)>=var_size) {
          esp_http_client_write(client, (const char *)tmp_var, strlen(tmp_var));
          sprintf(tmp_var, "");
          M5.Lcd.print(".");
        }
      }
      esp_http_client_write(client, (const char *)tmp_var, strlen(tmp_var));
      esp_http_client_close(client);
      esp_http_client_cleanup(client);
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0, 0, 2);
      M5.Lcd.println("FILE SEND FINISH");

      file.close();
      SD.remove(file_name);
      SD.end();
    }
  }

  if(M5.BtnA.wasPressed() && flag==0) {
    flag = 1;
    file = SD.open(file_name, FILE_WRITE);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.println("IMU START");
    startTime = millis();
  }
}

上記のスケッチを実行したところ、Webサーバーに約6,000行のファイルがアップロードされました。
また、SDカードにはファイルは残っていませんでした。

次に、スケッチを以下のように修正しました。
処理内容は全く同じですが、ファイルの保存先をSDカードから内蔵フラッシュ(SPIFFS)に変更しています。

#include <M5StickC.h>
#include <WiFi.h>
#include "esp_http_client.h"
#include "FS.h"
#include "SPIFFS.h"

#define FORMAT_SPIFFS_IF_FAILED true

File file;

const char* ssid          = "XXXXXXXX";
const char* password      = "XXXXXXXX";
const char* file_name     = "/test4.txt";
unsigned long var_size    = 2000;
unsigned long flag        = 0;
unsigned long currentTime = 0;
unsigned long prevTime    = 0;
unsigned long startTime   = 0;
float accX = 0.0f;
float accY = 0.0f;
float accZ = 0.0f;

void setup() {
  M5.begin();
  M5.Imu.Init();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 0, 2);

  M5.Lcd.printf("CONNECT TO %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status()!=WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");
  }
  M5.Lcd.println(" CONNECTED");

  if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
    M5.Lcd.println("SPIFFS FAIL");
    return;
  }
  M5.Lcd.println("SPIFFS READY");
}

void loop() {
  M5.update();

  if(flag==1) {
    currentTime = millis();
    if(currentTime-prevTime>=10) {
      prevTime = currentTime;
      M5.IMU.getAccelData(&accX, &accY, &accZ);
      file.println((String)(currentTime-startTime) + "," + (String)accX + "," + (String)accY + "," + (String)accZ);
    }
    if(currentTime-startTime>=60000) {
      file.close();
      M5.Lcd.println("IMU FINISH");
      flag = 0;

      file = SPIFFS.open(file_name, FILE_READ);
      M5.Lcd.print("FILE SIZE : ");
      M5.Lcd.println(file.size());
      M5.Lcd.println("FILE SEND START");

      char tmp_var[var_size+1] = "";
      esp_http_client_config_t config = {0};
      config.url    = "http://XXXXXXXX/writefile.php";
      config.method = HTTP_METHOD_POST;
      esp_http_client_handle_t client = esp_http_client_init(&config);
      esp_http_client_open(client, file.size());
      while(file.available()) {
        sprintf(tmp_var, "%s%c", tmp_var, char(file.read()));
        if(strlen(tmp_var)>=var_size) {
          esp_http_client_write(client, (const char *)tmp_var, strlen(tmp_var));
          sprintf(tmp_var, "");
          M5.Lcd.print(".");
        }
      }
      esp_http_client_write(client, (const char *)tmp_var, strlen(tmp_var));
      esp_http_client_close(client);
      esp_http_client_cleanup(client);
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0, 0, 2);
      M5.Lcd.println("FILE SEND FINISH");

      file.close();
      SPIFFS.remove(file_name);
      SPIFFS.end();
    }
  }
  
  if(M5.BtnA.wasPressed() && flag==0) {
    flag = 1;
    file = SPIFFS.open(file_name, FILE_WRITE);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.println("IMU START");
    startTime = millis();
  }
}

このスケッチを、SDカードスロットのつながっていないM5StickC単体に書き込んで実行したところ、先ほどと同様に、Webサーバーに約6,000行のファイルがアップロードされました。

Webサーバーにアップロードされたデータをパソコンでダウンロードし、Excelで開くと、このように、採取した加速度データをグラフ表示することができます。

 

なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。


ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。