Arduino シリアル通信 その1:processing 続き

バージョン情報
Arduino Uno , Arduino IDE 1.0.5 , processing 1.5.1 , windows 8.1

実験内容は前回と同じ
 アナログセンサ : フォトリフレクタ
  ↓
 Arduino
  ↓
 PC : processingでグラフ化

前回作ったアニメーションするグラフを、ただの折れ線グラフから時間軸を考慮した散布図に変えようと思ったところ、沢山はまったのでメモっておこう。

【Arduinoのスケッチ】
前回はserial.write()で1Byteデータを送信するのみだった部分を、serial.println()に変更し時間とデータをカンマでつないだ文字列として送信。

int analog_in = 0;
int val = 0;
String str_send_data;
unsigned long sTime = 0;        //プログラム開始時間
unsigned long cTime = 0;        //sTimeからの経過時間
unsigned long rTime = 0;        //サンプリングレート調整用

void setup() {                
  Serial.begin(38400);
  sTime = millis();
}

void loop() {
  cTime = millis() - sTime;
  rTime = millis();
  val = analogRead(analog_in);
  str_send_data = String(cTime) + "," + String(val);
  Serial.println(str_send_data);
  while(millis() - rTime < 100){
    delay(1);
  }
}

【processingのコード】
散布図にしたかっただけなのだが、いろいろとはまったポイントがありコードも随分長くなってしまった。とりあえず動いたので記録しておく。

import processing.serial.*;

Serial myPort;
int lf = 10;
String str_get_data = null;
String buf[];
int[] x = {0};
int[] y = {0};
int cTime = 0;
int flag_first = 0;
int fTime = 0;
int fps = 10;

void setup() 
{
  frameRate(fps);
  size(600, 350);
  myPort = new Serial(this, "COM5", 38400);
  textSize(20);
}

void draw()
{  
    background(0);
    //古いデータの削除
    while((x[0] < cTime - 10000)){
      x = subset(x, 1, x.length - 1);    
      y = subset(y, 1, y.length - 1);    
    }

    //グラフ描画
    draw_plot();

    cTime = cTime + 1000 / fps;
}

void draw_plot(){

    int plot_width = 500;
    int plot_height = 256;
    int x_min = -10000;
    int x_max = 0;
    int y_min = 0;
    int y_max = 1024;
    float x_scale = 1.0 * plot_width/(x_max -  x_min);
    float y_scale = -1.0 * plot_height/(y_max - y_min);
    
    //グラフエリアの描画
    pushMatrix();
    translate(50,300);
    fill(0);
    stroke(255);
    rect(0,0,plot_width,-plot_height);
    fill(255);
    text("0V",-40,5);
    text("5V",-40,-250);
    text("0sec",480,30);
    text("-10sec",-20,30);
    fill(0,255,0);
    text(y[y.length - 1]/1023.0*5,510,-250);

    //グラフプロット
    scale(x_scale,y_scale);
    fill(0);
    translate(x_max -  x_min - cTime,0);
    stroke(0,255,0);
    for (int i = 0; i < x.length - 1; i++){
      line(x[i],y[i],x[i+1],y[i+1]);
    }
    popMatrix();
  
    //println(cTime + "," + x[x.length -1]);
}

void serialEvent(Serial myPort){
  delay(5);

  str_get_data = myPort.readStringUntil(lf);
  if(cTime < 200){
    return;
  }
      
  if (str_get_data != null){
    str_get_data = trim(str_get_data);    //改行コード取り除き
    buf = split(str_get_data,",");
    
    if (flag_first == 0){
      fTime = int(buf[0]);
      flag_first++;
    }    
    x = append(x,int(int(buf[0]) - fTime));
    y = append(y,int(buf[1]));
  }
}

【今回のはまりポイント】
1.Arduinoとprocessingのデータ型の違い

 processing 1.5.1Arduino IDE 1.0.5
int 型 4 Byte2 Byte
long 型8 Byte4 Byte
文字列への型変換str()String()
4 Byte 整数型へ変換int()long()

2.processingでの配列処理
配列の要素削除:subset()
配列の要素追加:append()

3.processingのserialEvent
readStringUntil()でなぜかnullを取得する。
通信タイミングが微妙にずれるとどんどん遅延していく。(delayで調整)
データ取得開始のタイミングが合わない。
 ↓
プログラム上で通信の開始をコントロールした方がよかった。
serialEventはイベントではなくただのループ処理として考えた方が良い?

【メモ】
次は一旦違う言語でシリアル通信を試してみよう。C#を予定。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です