送信されてくる1バイトのデータをプロットしてみよう

ここでは、シリアル通信で送信されてくるデータをプロットしてみます。

プログラム

まずはProcessing IDEを使って、以下のプログラム(data_plot_1byte)を書きましょう。

// data_plot_1byte

import processing.serial.*;

Serial port;

int y0 = 200;

boolean draw_flag = true;

int t = 0;
int data;

void draw_axis() {
  stroke( 0 );
  line( 0, y0, width, y0 );
}

void plot_data( int data, char c ) {
  if ( c == 'r' ) stroke( 255, 0, 0 );
  strokeWeight( 2 );
  point( t, y0 - map( data, 0, 255, 0, y0 ) );
  strokeWeight( 1 );
}

void setup() {
  size( 500, 230 );
  port = new Serial( this, "/dev/tty.usbserial-A600afi47", 9600 );
}

void draw() {
  if ( draw_flag ) {
    if ( t == 0 ) {
      background( 255 );
      draw_axis();
    }

    plot_data( data, 'r' );

    t = (t+1) % width;

    //println( data );
  }
}

void mouseClicked() {
  draw_flag = !draw_flag;
}

void serialEvent( Serial p ) {
  data = port.read();
}
			

とりあえず実行してみましょう

このデータプロットプログラムを使うと、シリアル通信で送られてくるデータをこんな感じでプロットできます。
images/serial_voltage_byte_plot.png

プログラムを理解しよう

シリアル通信

まずはシリアル通信関係の説明をします。Processingでは、Serialライブラリを利用してシリアル通信を取り扱います。Serialライブラリを利用するために、以下のようにSerialライブラリをインポートし、Serialクラスのオブジェクトを宣言します。


import processing.serial.*;

Serial port;
					

そして、setup()の中でSerialオブジェクトを生成します。


void setup() {
  size( 500, 230 );
  port = new Serial( this, "/dev/tty.usbserial-A600afi47", 9600 );
}
					
Serialオブジェクトのコンストラクタの第1引数は通常"this"とします。第2引数ではポートを設定します。上の例はMacの場合です。ポートの名前は接続したArduinoなどによって変わるので、自分の環境にあわせて変更してください。Arduino IDEのメニューから、Tools -> Serial Portを選択すると確認できます。Windowsでは"COM1"、"COM2"などになります。Macの場合と同様に確認して変更してください。

あとはserialEvent()です。serialEvent()はイベントハンドラと呼ばれ、利用可能な、送信されてきたデータがあるときに実行されます。


void serialEvent( Serial p ) {
  data = port.read();
}
					
ここでは、その利用可能なデータを1バイト読みだしてint型の変数dataに格納しています。

つぎにプロットです。まず、プロット用に作った2つの関数、draw_axis()とplot_data()について説明します。

draw_axis()

draw_axis()はデータの値が0の位置を表す軸を描画する関数です。

void draw_axis() {
  stroke( 0 );
  line( 0, y0, width, y0 );
}
				
stroke()で色を黒に指定した後、line()でその軸を描画しています。y0はint型の変数で、描画する軸のy座標を格納しています。

int y0 = 200;
				

plot_data()

plot_data()はデータをプロットする関数です。

void plot_data( int data, char c ) {
  if ( c == 'r' ) stroke( 255, 0, 0 );
  strokeWeight( 2 );
  point( t, y0 - map( data, 0, 255, 0, y0 ) );
  strokeWeight( 1 );
}
				
第1引数でint型のデータの値を渡し、第2引数で色を指定します。ただし、今回のサンプルプログラムでは、"r"で赤色しか指定できません。

if ( c == 'r' ) stroke( 255, 0, 0 );
				
データをプロットする際、ストロークの太さを2に設定しています。

strokeWeight( 2 );
				
そして、point()でデータをプロットしています。

point( t, y0 - map( data, 0, 255, 0, y0 ) );
				
int型の変数tは、データをプロットする位置のx座標を格納しています。y座標は

y0 - map( data, 0, 255, 0, y0 )
				
で計算できます(map()関数については後述します)。そして、最後に

strokeWeight( 1 );
				
で、ストロークの太さを1に戻しています。

map()

map(float value, float low1, float high1, float low2, float high2)はデータのレンジを変更する関数です。第1引数にレンジを変更したいデータを渡し、第2引数と第3引数で変更する前のレンジを渡します。そして、第4引数と第5引数で新しいレンジを渡します。例えば、レンジが-100以上、100以下のhogeというデータがあったとします。そのデータのレンジを0以上、50以下にしたいときには、

map( hoge, -100, 100, 0, 50 )
				
とします。

最後に残りの部分を説明します。。

まず、boolean型の変数draw_flagです。boolean型の変数は"true"か"false"しか格納できません。


boolean draw_flag = true;
				
後で説明しますが、本サンプルプログラムでは、draw_flagがtrueのときデータをプロットし、falseのときはプロットしません。マウスがクリックされたときに実行されるmouseClicked()ハンドラを以下のように定義しているので(マウスがクリックされるたびにdraw_flagの値を、trueからfalse、またはfalseからtrueに変更している)、マウスのクリックでデータのプロットをオン・オフできます。

void mouseClicked() {
  draw_flag = !draw_flag;
}
				
関数draw()の定義は以下のとおりです。

void draw() {
  if ( draw_flag ) {
    if ( t == 0 ) {
      background( 255 );
      draw_axis();
    }

    plot_data( data, 'r' );

    t = (t+1) % width;

    //println( data );
  }
}
				
前述したように、draw_flagがtrueのときにのみデータをプロットします。

if ( draw_flag ) {
  .....
}
				
また、データをプロットする位置のx座標を格納している変数 t が 0 のときは、ウインドウを白で塗りつぶして、軸を描き直します。

if ( t == 0 ) {
  background( 255 );
  draw_axis();
}
				
そして先に説明した関数plot_data()でシリアル通信で送信されてきたデータをプロットします。

plot_data( data, 'r' );
				
プロットしたら、データをプロットする位置のx座標を格納している変数 t を更新します。

t = (t+1) % width;
				
t を 1 増やした後、width で割った余りを新たな t にしています。こうすることで t は 0 から (width-1) 内に収まり、必ずウインドウ内にデータが表示されます。

データの数値を確認したいときには、以下の//を削除すればコンソールに表示されます。


//println( data );
				

Referenceへのリンク


back to home