前回の調査(こちら)で、M5StickCとSDカードリーダーをつなぎ、M5StickCからSDカードを認識させることができました。
今回は、センサで採取したデータを、実際にSDカードに書き込んでみようと思います。
以前、M5StickC内蔵の加速度センサ(MPU6886)で、データ採取できる時間間隔を調査しました(記事は こちら)。このセンサでは、1秒間に160回程度、データを採取することができます。
今回は、この加速度データを、SDカードに書き込んでみます。
まず最初に、以下のようなスケッチを準備しました。
以前の記事でつくったスケッチ(加速度センサでデータ採取できる時間間隔を調査したもの)と基本的には同じで、ボタンを押すたびにデータ採取を開始・終了するようにしただけのものです。データ採取中は1秒ごとに、LCD画面に1秒間のデータ採取回数が表示されます。
#include <M5StickC.h> unsigned long currentTime; unsigned long prevTime=0; unsigned long cnt=0; unsigned long flag=0; float accX = 0.0f; float accY = 0.0f; float accZ = 0.0f; float prevX = 0.0f; float prevY = 0.0f; float prevZ = 0.0f; void setup() { M5.begin(); M5.Imu.Init(); M5.Lcd.setRotation(3); } void loop() { M5.update(); if(flag==1) { M5.IMU.getAccelData(&accX, &accY, &accZ); if(accX!=prevX || accY!=prevY || accZ!=prevZ) { cnt++; prevX=accX; prevY=accY; prevZ=accZ; } currentTime=millis(); if(currentTime-prevTime>=1000) { M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 0, 4); M5.Lcd.println(cnt); cnt=0; prevTime=currentTime; } } if(M5.BtnA.wasPressed()) { flag = (flag+1)%2; if(flag==0) M5.Lcd.println("STOP"); } }
以前の調査の時と同様に、1秒間に160〜170回データを採取できました。
次に、SDカードにデータを書き込むための処理を追加しました。
ボタンAを押すと、ファイル “test1.csv” をWRITEモードで開きます。ファイルを開いている間は、センサで採取したデータをファイルにどんどん書き込んでいきます。もう一度ボタンAを押すと、ファイルを閉じてデータ採取を終了します。
#include <M5StickC.h> #include "SD.h" SPIClass SPI2; unsigned long currentTime; unsigned long prevTime=0; unsigned long cnt=0; unsigned long flag=0; float accX = 0.0f; float accY = 0.0f; float accZ = 0.0f; float prevX = 0.0f; float prevY = 0.0f; float prevZ = 0.0f; File file; void setup() { M5.begin(); M5.Imu.Init(); M5.Lcd.setRotation(3); SPI2.begin(0, 36, 26, -1); // SPI初期化 if(!SD.begin(-1, SPI2)) { // SDカード初期化 M5.Lcd.println("Card Mount Failed"); return; } } void loop() { M5.update(); if(flag==1) { M5.IMU.getAccelData(&accX, &accY, &accZ); if(accX!=prevX || accY!=prevY || accZ!=prevZ) { file.println((String)millis() + "," + (String)accX + "," + (String)accY + "," + (String)accZ); cnt++; prevX=accX; prevY=accY; prevZ=accZ; } currentTime=millis(); if(currentTime-prevTime>=1000) { M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 0, 4); M5.Lcd.println(cnt); cnt=0; prevTime=currentTime; } } if(M5.BtnA.wasPressed()) { flag = (flag+1)%2; if(flag==1) { file = SD.open("/test1.csv", FILE_WRITE); } if(flag==0) { file.close(); M5.Lcd.println("STOP"); } } }
結果はデータ書き込み処理を追加する前とほぼ変わっておらず、1秒間に160回程度、データを採取できました。
SDカードで作成されたデータをパソコンに取り込み、Excelで開いてみました。
A列がデータ採取時刻です(ms単位)。おおむね6〜7ms間隔でデータを採取できていることが分かります。
また、このスケッチでは、ファイルをWRITEモードで開いていますので、データ採取処理を複数回実行すると、前回のデータは上書きされて消えてしまいます。
次に、スケッチを以下のように変更してみました。
データ採取し、ファイルに書き込むたびに、ファイル “test2.csv” のオープン・クローズを実施しています。データをどんどん追記していく必要があるので、ファイルはAPPENDモードで開いています。
#include <M5StickC.h> #include "SD.h" SPIClass SPI2; unsigned long currentTime; unsigned long prevTime=0; unsigned long cnt=0; unsigned long flag=0; float accX = 0.0f; float accY = 0.0f; float accZ = 0.0f; float prevX = 0.0f; float prevY = 0.0f; float prevZ = 0.0f; File file; void setup() { M5.begin(); M5.Imu.Init(); M5.Lcd.setRotation(3); SPI2.begin(0, 36, 26, -1); // SPI初期化 if(!SD.begin(-1, SPI2)) { // SDカード初期化 M5.Lcd.println("Card Mount Failed"); return; } } void loop() { M5.update(); if(flag==1) { M5.IMU.getAccelData(&accX, &accY, &accZ); if(accX!=prevX || accY!=prevY || accZ!=prevZ) { file = SD.open("/test2.csv", FILE_APPEND); file.println((String)millis() + "," + (String)accX + "," + (String)accY + "," + (String)accZ); file.close(); cnt++; prevX=accX; prevY=accY; prevZ=accZ; } currentTime=millis(); if(currentTime-prevTime>=1000) { M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 0, 4); M5.Lcd.println(cnt); cnt=0; prevTime=currentTime; } } if(M5.BtnA.wasPressed()) { flag = (flag+1)%2; if(flag==0) { M5.Lcd.println("STOP"); } } }
実験の結果、1秒間に50〜80回程度、データを採取できました。
こちらのデータもExcelで開いてみました。
概ね10〜20ms間隔でデータを採取しています。また、データ採取間隔が50ms程度まで広がっている箇所も所々で見られました。
データ書き込みの都度、ファイルオープンしていると、その処理がボトルネックになってしまい、加速度センサの性能を発揮できないことがわかりました。
追記
上記の2番目の方法で、1秒間に160回程度の間隔で、約1時間分のデータを書き込んでみたところ、できあがったファイルは 約584,000行 で、その時のファイルサイズは 13.7MB でした。
例えば8GBのSDカードを使用する場合、約 24.3日 分のデータを保存できる計算になります。
また、Excelのサポートページ(こちら)によると、ワークシートの最大行数は「1,048,576 行」とのことです。
今回の方法で、1秒間に160行ずつ、csvファイルにデータを書き込んでいくと、1時間で「576,000 行」になる計算になります。
つまり、1.82時間で、Excelの制限を超えてしまうことになります。
この方法で長期間のデータを保存するためには、長くても1時間半ぐらいの間隔で、別ファイルにしていく必要がありそうです。
なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。
ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。
このサイトで書いている、M5Stackシリーズ(M5Stack、M5StickCなど)に関するブログ記事を、「さとやまノート」という別のブログページに、あらためて整理してまとめました。
他のM5Stackシリーズの記事にも興味のある方は「さとやまノート」をご覧ください。