今回もM5StakのSDカードの使い方をすすめました。
これで書き込みした数値データを、数値データとして利用出来るようになります。
前回までで、SDの読み書きは一応出来ていました。
通常は以下の参考・にあげたようなところまでのようです。これでデータをPCなどでは解析できます。
しかし、リアルタイムに処理する場合は不十分です。
つまり前回の段階では、読み込んで書き出しは出来ますが、数値としてではなくCharとして実施していました。
以下の参考①はSDに書き込まれた数値が単独であればずばりです。
しかし、実際には数値列だったりします。
そこで、参考②のように関数化する必要が出てきます。
そして、数値列を読む関数が、参考③にありました。
そこで、これらの参考を合体させてみると無事にM5StackのIMUで読み込んだ、pitich, roll, yaw, temperatureのデータを塊ごとに数値として取り扱うことが出きるようになリました。
今回、これを簡単にまとめようと思います。
【参考】
・Logging data on MicroSD Cards with Arduino
①任意の浮動小数点数を文字列に変換、逆変換して元に戻せるか
②【C言語】文字列を数値に変換する方法(atoi・strtol など)
③Loading Data from SD Card & Sending via Bluetooth to Android
コード解説
コード全体は、おまけに記載しました。
主要な部分のコード解説します。
Sampling
計測は、今までと同様な関数sampling()で実施します。
※setup()でmyFile = SD.open("/temp.txt", FILE_WRITE);
しています。
10回計測し、save_temp()関数で書き込みします。
void setup() {
M5.begin();
M5.IMU.Init();
。。。
myFile = SD.open("/temp.txt", FILE_WRITE);
sampling();
output2();
Serial.print("Finished");
}
void sampling() {
for(int i=0; i <10; i++) {
M5.IMU.getAhrsData(&pitch,&roll,&yaw);
M5.IMU.getTempData(&temp);
M5.Lcd.printf(" %5.2f %5.2f %5.2f %5.2f \n", pitch, roll, yaw, temp);
Serial.printf(" %5.2f %5.2f %5.2f %5.2f \n ", pitch, roll, yaw, temp);
save_temp();
delay(100);
}
}
myFile.close();
}
save_temp
書き込みも以下のとおり簡単です。
※ここで書式を決めて書き込んでいることが割と重要です
void save_temp(){
if (myFile) {
myFile.printf("%5.2f, %5.2f, %5.2f, %5.2f \n", pitch, roll, yaw,temp);
} else {
Serial.println("error opening temp.txt");
}
}
output
ながれは一緒なので、まず読み出して簡単な表示から。
myFile = SD.open("/temp.txt");
して、あとは
Serial.write(myFile.read());
でSerialモニターに出力できます。
しかし、これはcharを出力しているだけで、数値として使えません。
void output(){
myFile = SD.open("/temp.txt"); //add "/"
delay(1);
if (myFile) {
Serial.println("temp.txt:");
M5.Lcd.println("temp.txt:");
// read from the file until there's nothing else in it:
while (myFile.available()) {
Serial.write(myFile.read());
delay(10);
}
}
// close the file:
myFile.close();
}
output2
散々悩んで以下のコードにまとめました。
ほぼ参考③を踏襲ですが、char配列readingを関数conv_str2d(reading);で変換しています。
関数書式が分からなかったので、取得した数値配列をglobal変数としました。
一度、変換してしまえば、M5Stackのディスプレイにも綺麗に表示できました。
double num_[4];
void output2(){
// re-open the file for reading:
myFile = SD.open("/temp.txt");
if (myFile) {
Serial.println("temp.txt:");
// read from the file until there's nothing else in it:
while (myFile.available()) {
char reading[30] = "";
char temp = myFile.read();
int idx = 0;
bool somethingWasRead = false;
while (temp != -1 && temp != 13 && temp != 10){
reading[idx] = temp;
temp = myFile.read();
idx++;
somethingWasRead = true;
}
reading[idx++]='\0';
//reading[idx] = 10;
if (somethingWasRead){
Serial.println(reading);
delayMicroseconds(500);
}
conv_str2d(reading);
Serial.printf("pitch %5.2f roll %5.2f yaw %5.2f temp %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
M5.Lcd.printf(" %5.2f %5.2f %5.2f %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
}
。。。
}
conv_str2d関数
問題の変換関数は以下のようにべたに記載しています。
※一行にまとめられますが、わかりやすいので展開して表示しています。
void conv_str2d(char reading[30]){
char a[6];
a[0]=reading[0];a[1]=reading[1];a[2]=reading[2];a[3]=reading[3];a[4]=reading[4];a[5]=reading[5];
num_[0] = strtod(a, NULL);
char b[6];
b[0]=reading[7];b[1]=reading[8];b[2]=reading[9];b[3]=reading[10];b[4]=reading[11];b[5]=reading[12];
num_[1] = strtod(b, NULL);
char c[6];
c[0]=reading[14];c[1]=reading[15];c[2]=reading[16];c[3]=reading[17];c[4]=reading[18];c[5]=reading[19];
num_[2] = strtod(c, NULL);
char d[6];
d[0]=reading[21];d[1]=reading[22];d[2]=reading[23];d[3]=reading[24];d[4]=reading[25];d[5]=reading[26];
num_[3] = strtod(d, NULL);
}
結果
よくできした!
Initializing SD card...initialization done.
0.45 -0.05 -8.32 51.09
0.94 -0.14 -8.13 51.24
1.33 -0.21 -7.97 50.97
1.70 -0.25 -7.81 52.29
2.07 -0.31 -7.63 50.99
2.46 -0.36 -7.46 48.03
2.86 -0.43 -7.28 51.89
3.14 -0.43 -7.12 49.99
3.48 -0.46 -6.93 50.76
3.80 -0.49 -6.77 50.26
temp.txt:
0.45, -0.05, -8.32, 51.09
pitch 0.45 roll -0.05 yaw -8.32 temp 51.09
0.94, -0.14, -8.13, 51.24
pitch 0.94 roll -0.14 yaw -8.13 temp 51.24
1.33, -0.21, -7.97, 50.97
pitch 1.33 roll -0.21 yaw -7.97 temp 50.97
1.70, -0.25, -7.81, 52.29
pitch 1.70 roll -0.25 yaw -7.81 temp 52.29
2.07, -0.31, -7.63, 50.99
pitch 2.07 roll -0.31 yaw -7.63 temp 50.99
2.46, -0.36, -7.46, 48.03
pitch 2.46 roll -0.36 yaw -7.46 temp 48.03
2.86, -0.43, -7.28, 51.89
pitch 2.86 roll -0.43 yaw -7.28 temp 51.89
3.14, -0.43, -7.12, 49.99
pitch 3.14 roll -0.43 yaw -7.12 temp 49.99
3.48, -0.46, -6.93, 50.76
pitch 3.48 roll -0.46 yaw -6.93 temp 50.76
3.80, -0.49, -6.77, 50.26
pitch 3.80 roll -0.49 yaw -6.77 temp 50.26
Finished
### まとめ ・M5StackでSD書き込み読込みが出きるようになった押すだけ🎵
— ウワン (@MuAuan) July 21, 2021
SD入出力出来ました‼️#M5Stack pic.twitter.com/26J0K675i8
・数値データを描画したいと思う
おまけ
# include <SPI.h>
# include <SD.h>
//#define M5STACK_MPU6886
//#include <M5Stack.h>
# include <M5Core2.h> //core2
float pitch = 0.0F;
float roll = 0.0F;
float yaw = 0.0F;
float temp = 0.0F;
int start;
File myFile;
void setup() {
// Open serial communications and wait for port to open:
//Serial.begin(115200);
M5.begin();
M5.IMU.Init();
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(GREEN , BLACK);
M5.Lcd.setTextSize(2);
start = micros();
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.print("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
myFile = SD.open("/temp.txt", FILE_WRITE); //add "/"
sampling();
output2();
Serial.print("Finished");
}
double num_[4];
void save_temp(){
if (myFile) {
myFile.printf("%5.2f, %5.2f, %5.2f, %5.2f \n", pitch, roll, yaw,temp);
} else {
Serial.println("error opening temp.txt");
}
}
void sampling() {
for(int i=0; i <10; i++) {
M5.update(); // need to call update()
M5.Lcd.setCursor(0, 0);
if (M5.BtnB.isPressed()) {
M5.Lcd.printf("B button is pressed.");
} else {
M5.Lcd.printf("B button is released.");
}
if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) {
Serial.println("Stop the measure");
break;
}else{
M5.IMU.getAhrsData(&pitch,&roll,&yaw);
M5.IMU.getTempData(&temp);
M5.Lcd.printf(" %5.2f %5.2f %5.2f %5.2f \n", pitch, roll, yaw, temp);
Serial.printf(" %5.2f %5.2f %5.2f %5.2f \n ", pitch, roll, yaw, temp);
save_temp();
delay(100);
}
}
myFile.close();
}
void output2(){
// re-open the file for reading:
myFile = SD.open("/temp.txt");
if (myFile) {
Serial.println("temp.txt:");
// read from the file until there's nothing else in it:
while (myFile.available()) {
char reading[30] = "";
char temp = myFile.read();
int idx = 0;
bool somethingWasRead = false;
while (temp != -1 && temp != 13 && temp != 10){
reading[idx] = temp;
temp = myFile.read();
idx++;
somethingWasRead = true;
}
reading[idx++]='\0';
//reading[idx] = 10;
if (somethingWasRead){
Serial.println(reading);
delayMicroseconds(500);
}
conv_str2d(reading);
Serial.printf("pitch %5.2f roll %5.2f yaw %5.2f temp %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
M5.Lcd.printf(" %5.2f %5.2f %5.2f %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening temp.txt");
}
}
void conv_str2d(char reading[30]){
char a[6];
a[0]=reading[0];a[1]=reading[1];a[2]=reading[2];a[3]=reading[3];a[4]=reading[4];a[5]=reading[5];
num_[0] = strtod(a, NULL);
char b[6];
b[0]=reading[7];b[1]=reading[8];b[2]=reading[9];b[3]=reading[10];b[4]=reading[11];b[5]=reading[12];
num_[1] = strtod(b, NULL);
char c[6];
c[0]=reading[14];c[1]=reading[15];c[2]=reading[16];c[3]=reading[17];c[4]=reading[18];c[5]=reading[19];
num_[2] = strtod(c, NULL);
char d[6];
d[0]=reading[21];d[1]=reading[22];d[2]=reading[23];d[3]=reading[24];d[4]=reading[25];d[5]=reading[26];
num_[3] = strtod(d, NULL);
}
void output(){
myFile = SD.open("/temp.txt"); //add "/"
delay(1);
if (myFile) {
Serial.println("temp.txt:");
M5.Lcd.println("temp.txt:");
// read from the file until there's nothing else in it:
while (myFile.available()) {
Serial.write(myFile.read());
delay(10);
}
}
// close the file:
myFile.close();
}
void loop(){
//nothing
}