#はじめに…#
ev3rtにてセンサーの値を取りたい時、よくやる手法はLCDに値を書く方法かと思いますが、これってあの小さい液晶を覗き込まなければならなく、見にくいですよね。
教育版ソフトウエアでは「データロギング」というモードがあり、モーター・センサーの値の動きを連続してみることができます。これに近いものをev3rtで実現できれば、ログ取りには困りませんよね。
#標準Cライブラリを使用する#
ev3rtで使える標準Cライブラリには、ファイルを扱う機能があり、Windowsでいうメモ帳で読み書きできる.txtファイルも作成できます。よって今回は.txtファイルに値を書き込んでいくとします。
#書き方#
まずはサンプルコードを見てみましょう。
void main_task(intptr_t unused)
{
int i=100;
FILE *file;//ファイルポインタを宣言
file=fopen("/test.txt","a");//ファイルをオープン(名前の指定)
fprintf(file,"Hello %d\n",i);//書き込み
fclose(file);//ファイルを閉じる
}
fileというのはただの名前なので、別のファイルを作りたければfile2などとすれば複数個同時に作ることも可能です。その際は、上記例に示されているfileはすべてfile2に置き換えることになります。
(例)
FILE *file; → FILE *file2;
file=fopen("/test.txt","a"); → file2=fopen("/test.txt","a");
fprintf(file,"Hello %d\n",i); → fprintf(file2,"Hello %d\n",i);
fclose(file); → fclose(file2);
#テキストを確認#
プログラム終了後、ロボットとPCをUSBケーブルで繋ぐと、SDカード領域がマウントされるはずです。そしてその中に、先程指定した名前のファイルが作成されているはずです。無い場合はプログラムが正常に動いていません。もう一度やってみると作成される場合もあります。それでもなお作られない場合はプログラムミスを疑ってください。
今回の場合は「Hello 100」と書かれているはずです。
#fopenの書式#
上記例の"a"
と書かれている部分ですが、これはテキストの処理方法を宣言していて、以下の表の様に様々な記述方法があります。ロボットの場合、値を随時書き足していくという使い方が多いと思いますので、オススメは"a"
です。
モード | 動作 | ファイルがあるとき | ファイルが無いとき |
---|---|---|---|
"r" | 読み込み専用 | 正常 | エラー(NULL) |
"w" | 書き込み専用 | サイズを0にする(上書き) | 新規作成 |
"a" | 追加書き込み専用 | 最後に追加 | 新規作成 |
"r+" | 読み込み(主)と書き込み | 正常 | エラー(NULL) |
"w+" | 書き込み(主)と読み込み | サイズを0にする(上書き) | 新規作成 |
"a+" | 読み込みと追加書き込み | 最後に追加 | 新規作成 |
#fprintfの書式#
##引数を用いる##
fprintfでは引数として任意の値を代入することができます。例えば、上記例ではint型変数testを%d
の部分に動的に代入しています。この書式法を使えば、任意のタイミングの値を記録することが可能なのです。なお、値の型によって書式が異なります。
変換指定子 | 意味 |
---|---|
d , i | int 型の引数を 10 進符号付き整数に変換する |
u | unsigned int 型の引数を 10 進符号無し整数に変換する |
o | unsigned int 型の引数を 8 進符号無し整数に変換する |
x , X | unsigned int 型の引数を 16 進符号無し整数に変換する |
f , F | double 型の引数を小数形式浮動小数点数に変換する |
e , E | double 型の引数を指数形式浮動小数点数に変換する |
g , G | f か e のどちらかに変換する (変換の結果として得られる指数が -4 より小さいか,精度以上の場合は e 形式になる) |
a , A | double 型の引数を 16 進浮動小数点に変換する |
c | int 型の引数を 一端 unsigned char 型に変換し,変換結果の文字を書き込む |
s | 文字配列の先頭要素へのポインタを文字列に変換する |
p | void 型へのポインタを処理系定義の方法で表示文字の並びに変換する |
n | 整数変数に出力済み文字数を格納する (引数は符号付き整数型へのポインタ) |
又、場合によっては長さ修飾子を付ける必要があります。
長さ修飾子 | 意味 |
---|---|
hh | 対応する実引数の型が char 型であることを指定する |
h | 対応する実引数の型が short 型であることを指定する |
l | 対応する実引数の型が long 型, wchar_t 型であることを指定する |
ll | 対応する実引数の型が long long 型であることを指定する |
j | 対応する実引数の型が intmax_t 型であることを指定する |
z | 対応する実引数の型が size_t 型であることを指定する |
t | 対応する実引数の型が ptrdiff_t 型であることを指定する |
L | 対応する実引数の型が long double 型であることを指定する |
さらに、フラグというものを使うとさらに文字の表現が広がります。
フラグ | 意味 |
---|---|
- | 変換結果をフィールド内に左詰めにする (デフォルトは右詰め) |
+ | 変換結果が正,負に関わらず符号を出力する (デフォルトは負の場合のみ出力) |
空白 | 変換結果の最初の文字が符号でない場合か,符号付き変換の結果が 0 の場合に空白を結果の前に付ける |
# | 結果を "代替形式"※ に変換する |
0 | 出力文字数が最小フィールド幅未満の場合は 0 を埋める |
これだけ説明しといてなんですが、EV3rtで扱うような値(センサー値など)はint型が多く、計算でもしない限り%d
だけで書き出せちゃうのです。(もちろん、私のように複数個の値でパーセンテージなどをだすとfloatもしくはdoubleになりますが…)
あ、そうそう。printfとかfprintf、あるいはsprintfなどはすべて仲間みたいなもんなので書式もほぼ共通です。
ちなみに、この引数は複数個も可能です。
void main_task(intptr_t unused)
{
int i[10]={10,20,30,40,50,60,70,80,90,100};
FILE *file;//ファイルポインタを宣言
file=fopen("/test.txt","a");//ファイルをオープン(名前の指定)
fprintf(file,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n"
,i[0],i[1],i[2],i[3],i[4],i[5],i[6],i[7],i[8],i[9]);//書き込み
fclose(file);//ファイルを閉じる
}
この場合、出力は10,20,30,40,50,60,70,80,90,100
になります。
###センサー値も代入可能###
以下のようにすれば、センサーの値も引数として代入可能です。(今回はライトセンサーをポート1、2に繋いでいます。)
void main_task(intptr_t unused)
{
int i=100;
FILE *file;//ファイルポインタを宣言
file=fopen("/test.txt","a");//ファイルをオープン(名前の指定)
fprintf(file,"Port1:%d,Port2:%d\n",ev3_color_sensor_get_reflect(0),ev3_color_sensor_get_reflect(1));//書き込み
fclose(file);//ファイルを閉じる
}
##改行する##
ファイルを作成するとき、書き出せたは良いものの、改行されていないと非常に見にくいです…
そこで「改行コード」を入力することで、文字列を次の行に移すことが可能です。
LINUX系(EV3rt含む)の場合は\n
です。
#おまけ#
この作成したファイルですが、そのままメモ帳で見るとなかなか見にくいです。そこで、ファイルをexcelで開きましょう。その時ポイントとなるのが、値と値の間に「,」などの印をつけることです。excelでは指定した文字で文字列を分解する機能があります。そうすれば、とても簡単にデータが見れますし、グラフを作ることも容易です。
#最後に#
今回はファイルの扱い方について紹介しました。printf系統は非常によく使うので、覚えておいた方が良いでしょう。
さて、次回はいよいよタスク・周期ハンドラに入っていきたいと思います。僕は理解するのに1年かかりました…