MTM07で出展したArduino Megaの話も今回で最後である。さて、前回のList 2のSketchをロードした後で、Windows側のプログラムを立ち上げる(コードが未完成なので、今回はWindows側のソースは無しである)。で、実際に実行してみると、うまくデータが取れる場合(Photo01)と取れない場合(Photo02)が出てきた。頻度で言えば、表示のインターバルを2秒程度にすると、概ね5割程度の確率でデータが取れるが、1秒以下の頻度にするとかなりの確率でデータが取れない。

Photo01: うまくデータが取れた場合。実はプログラム内部の、各ワットメーター毎の係数まで調整を行っている暇がなく、Arduino Unoにワットメーター1台を繋いでいた時の係数をそのまま使っていた関係で、電圧/電流ともにちょっとおかしい。

Photo02: データが取れない場合は、こんな具合に0になる。ちなみに数字は上から1~4台目のワットメーターについて、左から順に電圧(V)/電流(A)/電力(W)を表示している。

で、ためしにArduino IDEのSerial Monitorを使うとこんな結果になる(Photo03)。一応毎回数字はちゃんと流れてくるのだが、まず9桁目のサンプル数が30を超えている事になる。これは明らかにおかしい。というのは、前回のグラフ5からも判るとおり、ノーウェイトでひたすらサンプリングだけを行っても、一周期あたりのサンプリングは30回が限界である。ましてや前回のList 2から判るとおり、実際にSketchの内容は、

(1) 8ポート(4台のワットメーター×(電圧と電流))にanalogRead()
(2) 1台目の電圧と電流がどちらも0か判断
(3) 波形のどの位置のデータをサンプリングしているかを判断
(4) 8つのデータについて加算

を行っているから、サンプリング間隔はもっと少なくないとおかしい。ためしに前回のList 1に、上の4つの処理を擬似的に追加したSketch(List 1)を実施してみたところ、グラフ1の様な結果が得られた。ノーウェイトでも1周期あたり22サンプルが限界で、とても34サンプルなどには行き着かない。

Photo03: この画面ではサンプル数が34前後取れていることになるが、これがそもそも大嘘。

このあと幾つかテストコードを書いて振る舞いを調べたのだが、「これだ」という確たる証拠はつかめなかった。ただ、振る舞いに関する大雑把な仮説は見つかった。要するに前回のList 2のSketchを実際にぶん回すと、Arduino MEGAの処理が間に合わずにどこかで飽和するようだ。これはどういうことかというと、今回のList 1の場合は50サンプル×8chで合計400回のサンプリングをした後でシリアルに結果を送って1秒ウェイトするので、結果的に400回のサンプリング毎にちょっと時間を置くことになり、結果フルスピードでぶん回しても余裕でこなせるのだが、前回のSketchだと切れ目無くサンプリングを行っていることになる(1周期分のサンプリングの後で結果をまとめるが、その後も電圧の正負の反転を確認するために定期的にサンプリングが続く)ため、長時間連続稼働だとどこかで飽和する事になる。この飽和をしている間はサンプリングを含めた動作がどっかで止まってしまい、結果的に2周期分以上の波形をサンプリングする事になるため、トータルとしてのサンプル数が34とか異様に多くなるものと考えられる。しかも、この飽和中は通信もとまるので、CPU側にはデータ無しと認識され、電圧/電流が0とレポートされる事になる。

で、これはArduino全般というよりも、Arduino MEGAに負荷の高い処理をやらせたのがどうもまずかった気がする。というのは、ためしに測定するワットメーターを1台に減らすように前回のList 2を書き換えて走らせても、やはりサンプル数が多すぎるとレポートされる(本来なら60サンプル/周期程度が上限なのに、結果は100サンプル位取れたとされる)上、通信途絶の状況も変わらなかったからだ。こうした事柄はArduino UNOでは発生しておらず、Arduino MEGAを酷使したのが悪かったのではないかと判断される。

ということであれば、やはりArduino MEGAを使って複数のワットメーターをまとめてサンプリングというのが無茶、という話でやはりArduino UNOを使って1台のワットメーターの値をサンプリングする程度で収めておくほうが無難、という判断ができる。そんなわけで次回からは改めてArduino Unoに戻し、ちゃんとデータのサンプリングができるシステムを完成させることにしたい。

List 1:

#define  VOL1PIN  0
#define  AMP1PIN  1
#define  VOL2PIN  2
#define  AMP2PIN  3
#define  VOL3PIN  4
#define  AMP3PIN  5
#define  VOL4PIN  6
#define  AMP4PIN  7
#define  BUFSIZE  50
#define  VOL1BIAS  483
#define  AMP1BIAS  495
#define  VOL2BIAS  484
#define  AMP2BIAS  497
#define  VOL3BIAS  480
#define  AMP3BIAS  487
#define  VOL4BIAS  483
#define  AMP4BIAS  476

long  vol0[BUFSIZE], amp0[BUFSIZE];
long  vol1[BUFSIZE], amp1[BUFSIZE];
long  vol2[BUFSIZE], amp2[BUFSIZE];
long  vol3[BUFSIZE], amp3[BUFSIZE];

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int lpCnt;
  long vol1Sum, vol2Sum, vol3Sum, vol4Sum;
  long amp1Sum, amp2Sum, amp3Sum, amp4Sum;
  long vol1Act;
  int  flag;

  flag = 0;
  vol1Sum = vol2Sum = vol3Sum = vol4Sum = 0;
  amp1Sum = amp2Sum = amp3Sum = amp4Sum = 0;

  for(lpCnt=0;lpCnt < BUFSIZE;lpCnt++)
  {
    vol0[lpCnt] = analogRead(VOL1PIN);
    amp0[lpCnt] = analogRead(AMP1PIN);
    vol1[lpCnt] = analogRead(VOL2PIN);
    amp1[lpCnt] = analogRead(AMP2PIN);
    vol2[lpCnt] = analogRead(VOL3PIN);
    amp2[lpCnt] = analogRead(AMP3PIN);
    vol3[lpCnt] = analogRead(VOL4PIN);
    amp3[lpCnt] = analogRead(AMP4PIN);
    // delayMicroseconds(1);

    /* 両方0なら0としてBreak; */
    if (!(vol1[lpCnt]||amp1[lpCnt]))
    {
      vol1Sum = vol2Sum = vol3Sum = vol4Sum = 0;
      amp1Sum = amp2Sum = amp3Sum = amp4Sum = 0;
    }

    /* flagの値を判断 */
    vol1Act = vol0[lpCnt]-VOL1BIAS;
    if ((flag==2)&&(vol1Act>0))
      flag=0;              /* データサンプリング開始 */
    else if ((flag==0)&&(vol1Act<0))
      flag++;              /* 一度目の値の符号反転 */
    else if((flag==1)&&(vol1Act>0))
      flag++;               /* 二度目の値の符号反転 */

    /* 取得した値を加算 */
    if(flag!=2)
    {
      vol1Sum += abs(vol1Act);
      amp1Sum += abs(amp0[lpCnt]-AMP1BIAS);
      vol2Sum += abs(vol1[lpCnt]-VOL2BIAS);
      amp2Sum += abs(amp1[lpCnt]-AMP2BIAS);
      vol3Sum += abs(vol2[lpCnt]-VOL3BIAS);
      amp3Sum += abs(amp2[lpCnt]-AMP3BIAS);
      vol4Sum += abs(vol3[lpCnt]-VOL4BIAS);
      amp4Sum += abs(amp3[lpCnt]-AMP4BIAS);
    }
  }

  for(lpCnt=0;lpCnt < BUFSIZE;lpCnt++)
  {
    Serial.print(lpCnt);
    Serial.print(":");
    Serial.print(vol0[lpCnt]);
    Serial.print(":");
    Serial.print(amp0[lpCnt]);
    Serial.print(":");
    Serial.print(vol1[lpCnt]);
    Serial.print(":");
    Serial.print(amp1[lpCnt]);
    Serial.print(":");
    Serial.print(vol2[lpCnt]);
    Serial.print(":");
    Serial.print(amp2[lpCnt]);
    Serial.print(":");
    Serial.print(vol3[lpCnt]);
    Serial.print(":");
    Serial.println(amp3[lpCnt]);
  }
  Serial.print(vol1Sum);
  Serial.print(":");
  Serial.print(amp1Sum);
  Serial.print(":");
  Serial.print(vol2Sum);
  Serial.print(":");
  Serial.print(amp2Sum);
  Serial.print(":");
  Serial.print(vol3Sum);
  Serial.print(":");
  Serial.print(amp3Sum);
  Serial.print(":");
  Serial.print(vol4Sum);
  Serial.print(":");
  Serial.println(amp4Sum);
  delay(1000);
}