HOME >> 鉄道模型工学 > 動力特性の測定の自動化 > 電圧・電流測定ユニットの製作

鉄道模型工学  動力特性の測定の自動化 電圧・電流測定ユニットの製作

■ 電圧・電流測定ユニットの製作

 分散させている測定ユニットの中で、まず、電圧・電流測定ユニットを組立てる事にした。 ブレッドボードで検証した回路をユニバーサル基板に組立てた基本回路は出来あがっていたので、メインユニットへの配線や電圧計への配線を実施して、電圧・電流測定ユニットとして完成させた。

 この電圧・電流測定ユニットには、測定中に目視出来るようにと電圧計と電流計を取り付ける計画であったが、測定データの影響を心配して、高インピーダンスのデジタル電圧計のみにしている。 その電圧計を下に示す。 このコードを電圧・電流測定ユニットのソケットに差し込むとメイン回路の電圧が表示される。 その電源は、同じユニットから供給してもらうようにした。

 

■ メインユニットの製作

 次に、Arduino 本体を搭載するメインユニットを製作する。 Arduinoでは「シールド」と呼ぶそうである。 まず、Arduino 本体の表と裏を写す。

 この本体の上に、シールドと呼ばれている Arduino用のユニバーサル基板を取り付けるのである。 この基板には、付属する本体との接続用コネクタ付を始めとして、各測定ユニットと接続するコネクタや、表示用のLEDを取り付ける。 カタログのページより基板パターンの絵を取りこんで印刷し、それに配線を書き込みながら検討した。 シールドと本体の隙間を見ると、ICなどの部品が邪魔してコネクタの足が干渉する恐れがあるので、下左の写真の様にずれた位置に配置している。 また、この基板は両面にパターンが印刷されており、表裏がスルーホールで連通している。 さらに、両サイドには電源ラインとグランドラインが縦につながっているので、裸線の配線ではショートしてしまう恐れがある。 このため、コネクタの端子などに配線する部分は絶縁されている電線を使用している。 

 このシールドと本体を組合わせた状態を下の写真に示す。

 このメインユニットは測定台のどこかに取り付ける予定であるが、とりあえずベニヤ板に仮止めして使うことにした。 信号入力として臨時に使用するためブレッドボード上にタクトスイッチを付けている。 下の写真。 最新の回路図も下に示す。

 

 ハードの準備が整ったので、プログラムを組んで見る事にする。

 

■ シールドの機能テスト

 Arduino の電源は、9Volt用のACアダプターを使用し、USBケーブルでパソコンと接続して実験を開始する。 電圧・電流測定ユニット、デジタル電圧計、また、コントローラや負荷回路も接続した状態を下の写真に示す。 なお、デスクトップパソコンは、2008年11月購入の VAIO-VGC-LN50DB、Windows Vista、RAM/2GB を使用している。

   ***** 押しボタン式信号機 ******

  #define LEDG_PIN 9
  #define LEDY_PIN 8
  #define LEDR_PIN 7
  #define Button 5

  void setup()
  {
    pinMode(LEDG_PIN,OUTPUT);
    pinMode(LEDY_PIN,OUTPUT);
    pinMode(LEDR_PIN,OUTPUT);
    pinMode(Button,INPUT);  
  }

  void loop()
  {
    int input_Button = HIGH;
    while (input_Button == HIGH ) {
      input_Button = digitalRead(Button);
      digitalWrite(LEDG_PIN, HIGH);
    }
      
    digitalWrite(LEDG_PIN, LOW);
    delay(500);
    digitalWrite(LEDG_PIN, HIGH);
    delay(500);
    digitalWrite(LEDG_PIN, LOW);
    delay(500);
    digitalWrite(LEDG_PIN, HIGH);
    delay(500);
    digitalWrite(LEDG_PIN, LOW);
    delay(500);
    digitalWrite(LEDG_PIN, HIGH);
    delay(500);
    digitalWrite(LEDG_PIN, LOW);
    digitalWrite(LEDY_PIN, HIGH);
    delay(2500);
    digitalWrite(LEDY_PIN, LOW);
    digitalWrite(LEDR_PIN, HIGH);
    delay(3500);
    digitalWrite(LEDR_PIN, LOW);
  }

 Arduinoの作動テストとして、信号機としての作動を走らせてみる。 無事に動く事を確認したので、押しボタンスイッチの動作チェック用として次のスケッチを作成した。 ボタンを押すと青が点滅を初めて黄、赤と変化し、最後にもとの青を点灯して待機する動作をさせるのである。 ボタンが押されまで待機させるために、while 命令の使い方を確認するためである。 右にその内容を記載する。

■ 電圧・電流ユニットの機能テスト

 次に、電圧・電流ユニットから電圧値と電流値を読み取り、パソコンに送信するまでの機能をチェックしてみる。 受信されたかどうかはArduinoのシリアルモニタで確認する。 スケッチを下に示す。

   ***** 送信テスト ******

  #define LEDG_PIN 9
  #define Button 5

  void setup()
  {
    pinMode(LEDG_PIN,OUTPUT);
    pinMode(Button,INPUT);
    Serial.begin(9600);
  }

  void loop()
  {
    int voltage;
    int current;
    int vol_pin = 1;
    int cur_pin = 2;
    int input_Button = HIGH;
    
    while (input_Button == HIGH ) {
      input_Button = digitalRead(Button);
      digitalWrite(LEDG_PIN, HIGH);
    }
    
    voltage = analogRead(vol_pin);
    current = analogRead(cur_pin);
    
    Serial.println(voltage);
    Serial.println(current);
    
    digitalWrite(LEDG_PIN, LOW);
    delay(1000);
  }

 while 命令で、ボタンが押されるまで待機させている。

 ボタンが押されると、電圧と電流のアナログ入力値をanalogRead によって、読み取り、Serial.println によってシリアル通信により、そのデータをパソコンに送信する。

 一度送信するとしばらくLEDを消灯し、時間を於いて(1秒)、再びボタンの待機状態に戻る。 これは、2度打を防止するためである。

 シリアルモニタを見ていると、何やらデータを受け取っており、コントローラのダイヤルを変えると、データも変化しているのが確認出来た。

 ここまで来たらしめたもので、次のステップとしてこのデータを検証する必要がある。 まずパソコン上のExcel にデータを取り込み、テスターで測定した値と比較することにする。

 このため、Excel にデータを取り込む方法にチャレンジする。

 

■ Excel へのデータの取り込み

   ***** Arduino1 ******

'RS-232C通信用のWIN32API定義
 Declare Function CreateFile Lib ・・・・・・・・・・・・
  ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
'CreateFileパラメータ用定数
 Const GENERIC_READ = (&H80000000)
 ・・・・・・・・・・・・
'SetCommTimeouts関数用構造体定義
 Type COMMTIMEOUTS
   ReadIntervalTimeout As Long
   ・・・・・・・・・・・・
 End Type
--------------------------
Sub Arduino1()
  Dim c As COMMTIMEOUTS
   Cells(1, 2) = ""
  ・・・・・・・・・・・・・・・・・・・・・・・・
 'オープン
  port$ = "COM3"
  h = CreateFile(port$, ・・・・・・・・・)
  If h < 0 Then
      MsgBox "通信ポート " & port$ & " がオープンできません"・・・・
      Exit Sub
  End If
 'タイムアウト
    c.ReadIntervalTimeout = 0
    ・・・・・・・・・・・・・
 '送信
    buf$ = Cells(1, 1) + Chr(13) + Chr(10)
    WriteFile h, buf$, ・・・・・・・・
 '受信
    buf$ = String$(128, vbNullChar)
    ReadFile h, buf$,・・・・・・・・・
    buf$ = Replace(buf$, vbNullChar, "")
 'クローズ
    CloseHandle h
 ' 結果をB1にセット
    rn = 1
    While InStr(buf$, Chr$(13) + Chr$(10)) > 0
       ・・・・・・・・・・・・
       rn = rn + 1
    Wend
    If buf$ <> "" Then Sheet1.Cells(rn, 1) = buf$
End Sub

 いよいよ、Excel のマクロに取り掛かかります。 まず始めに参考書2に付属するCDより、Arduino1.xlsm をコピーして、Arduino と通信を始めたが正常に反応しない。 送信した文字が帰ってこないのである。 色々試したがダメであったので、他の方法を考えて見た。 それは、シリアル通信モニタにてテキストファイルをとしてデータを読み込み、Excel で開いて処理しようとするものである。

 そこで、シリアル通信モニタソフトとして、「 TerTerm 」をインストールして起動するも、これまた動かない。 なんで?・・・・・・・と落ち込んでしまったが、昼食時間となり休憩とした。

 午後、愛犬との散歩から戻り、気を取り直してArduino1.xlsm を起動し Arduinoと通信を始めると、何と正常に反応するではないか! どうして?・・・・・・・・。  おそらくパソコンを再起動させたので、正しい環境に設定されたのだと自己流に判断する。

   “おかしくなったら再起動せよ!”

と言う昔の古いジンクスは生きている様である。 不要になった TerTerm はさっさとアンインストールしてしまったのである。

**********************************

 さて、これからが本番である。 このサンプルデータを活用して、データ処理のプログラムを作らなければならないのであるが、それには、このサンプルデータの内容を理解しなければならない。 参考書には、簡単な説明があるだけで、小生には充分に理解できないである。

 このサンプルプログラムはネットでも殆んど同じ物を見つけたが、著者は一緒なのか、他人なのかは不明である。 両方を参考にしながら、私と同じ様な初心者のために、自分が理解した内容を説明しよう。 このプログラムの内容の要約を左に示す。 ”・・・・・”と表記した部分は省略しています。 もし、このプラグラムを活用される方は、紹介した参考書を参照して下さい。

◆プログラムの内容

1) 最初の部分は、使用する関数、サブプログラム、構造体などの形式を宣言している部分で、自分にはさっぱり分かりません。 このまま活用させて頂くことにします。

2) Sub Arduino1()End Sub の間がプラグラム本体のようです。 そして、使用する定数などを宣言して、 Excel の(1、2)のセルに空白文字を入力します。

3) 'オープン の部分でシリアル通信ポートをオープンします。 自分のパソコンではCOM3 だったので書き換えています。 h はポートのハンドルで、ポートが正常にオープンすると CreateFile は正値を、オープン出来ない場合には、-1 を返すそうです。 エラー表示を含めて、これもこのまま活用することにします。

4) 'タイムアウトの部分も良く理解出来ないが、もしもの場合にプログラムが暴走しないように、このまま活用します。

5) '送信 サンプルプログラムの場合は、Excel 側からデータを送信し、Arduino がそれに応える設定ですが、今回の場合は不要ですので、この部分は不要です。 ここで実行している内容は、セル(1、1)の内容に Chr(13) とChr(10)を加えた内容をbuf$ に入れ、このbuf$ をファイル h に書き込むことで、シリアル通信での送信を実行していることが理解出来ます。 でもなぜ Chr(13) とChr(10) を加えるのか疑問でした。

6) '受信 Arduino から送信されたデータは、シリアル通信ポートのバッファが受取っているようですので、ReadFile h によってファイル h を読み込みます。 読み込んだデータはbuf$ に書き込まれます。 でも、buf$ = String$(128, vbNullChar) にして、buf$ = Replace(buf$, vbNullChar, "") とするのかいまいち理解できません。

7) 'クローズ データを受け取ったのでこの処理によって通信ポートをクローズします。

8) 結果をB1にセット 通信で受取ったデータをExcel のセルに書き込みます。 セルB1 は (1、2)のセルの事ですが、While 〜 Wend 命令によって何やらごそごそとやっている様です。 そして、最後にある If 命令は何をしているのでしょうか?

◆ ひとつずつ理解していく

 ともかくも、プログラム内容を理解しなければ前に進めません。

 まず、 Chr(13) とChr(10)の意味ですが、昔、見たような気がして、アスキーコードを見て見ました。 Chr(13) はキャリッジリターンのコードであり、 Chr(10) はラインフィード、即ち、一行送ることのコードであることが判りました。 このコードは返信されたデータにも含まれているはずですので、データをチェックしている N = InStr(buf$, Chr$(13) + Chr$(10)) で、このコードの位置をチェックしているようです。 その後は何をしているのでしょうか?

 その答えは、参考書の後の方を見ると理解出来ました。 16個のデータの送受信を行っているプログラムにも同じ記述があり、受信したデータからキャリッジリターンコードを頼りにデータを切り取っている様です。

 ここで、“長さゼロの文字列” と “値ゼロを持つ文字列” の違いを勉強しました。 “長さゼロの文字列” は "" で表示され、 “値ゼロを持つ文字列” は Chr(0) か vbNullChar で指定するとのこと。 この意味を理解すると、buf$ = String$(128, vbNullChar) は、値ゼロの128ケタの文字列を作成し、buf$ = Replace(buf$, vbNullChar, "") は、値0の文字を空白に置き換える処理をしていることになります。 これは、余分な部分を切り取る作業と理解しました。 でも、受信処理でこの面倒な処理をする理由が判りません。 ノイズ対策なのかどうか、あるいは、ほかの応用を考えての事だろうか?

 InStr() についてネットで調べて見ました。 InStr(引数1,引数2) は、引数1の文字列の中から、引数2の文字列を探し出し、その位置を返すそうです。 このため、

     While InStr(buf$, Chr$(13) + Chr$(10)) > 0
では、 buf$ の文字列の中で、キャリッジリターンとラインフィードのある位置が 0 より大きい、即ち、それが存在したら、次の命令を実行しなさい。 もし、無かったら、
    If buf$ <> "" Then Sheet1.Cells(rn, 1) = buf$
即ち、buf$ が 長さゼロの文字列でないのであれば、即ち何かの文字があるので、セル(m、1) に書き込みなさい。 と言う記述である事が理解される。

 そして、While 命令の中では、キャリッジリターンとラインフィードのある位置をN とし、
    a$ = Left(buf$, N - 1)
によって、 buf$ の中から N - 1番目より左側だけを切り取り、a$ と言う文字列を作ります。 
    Sheet1.Cells(rn, 2) = a$
によって、セル(m、2)にその文字列を書き込みます。 そして、
    buf$ = Mid$(buf$, N + 2)
によって、切り取れた後ろの部分を新たに buf$ という文字列にし、m をひとつ加算して繰り返せと言う事である。 これによって、シリアル通信で受信したデータは、キャリッジリターンとラインフィードのある位置を頼りに、ひとつずつ切り離され、セルに書き込まれて行きます。

 Left() と Mid$() の意味も同じくネットで調べました。 これで、このプログラムの実行している内容が理解出来たような気がします。

*******  受信処理 ver1 ******************

Sub Jushin_01()
  Dim N As Integer
  Dim c As COMMTIMEOUTS
  Dim l As Long

  m = Sheet1.Cells(2, 1)

  rn = 1
  For rn = 1 To 6

    'オープン
     port$ = "COM3"
     h = CreateFile(port$, ・・・・・・・・・・)
     If h < 0 Then
        MsgBox "通信ポート " & port$ & " がオープンできません"
        ・・・・・・・・・・・・・・
        Exit Sub
     End If

    'タイムアウト
        c.ReadIntervalTimeout = 0
        ・・・・・・・・・・・・・・・

    '受信待ち
      buf$ = String$(128, vbNullChar)
      While InStr(buf$, ",") = 0
         ReadFile h, buf$, ・・・・・・・
      Wend
      buf$ = Replace(buf$, vbNullChar, "")

    'クローズ
      CloseHandle h

    ' 結果を表示する
      sn = 2
      While InStr(buf$, ",") > 0
        N = InStr(buf$, ",")
        a$ = Left(buf$, N - 1)
        buf$ = Mid$(buf$, N + 1)
        Sheet1.Cells(rn + m, sn) = a$
        sn = sn + 1
     Wend

  Next
  Sheet1.Cells(2, 1) = m + 6

End Sub

■ Excel のデータ処理

 いよいよ、自分様のテストプログラムを作ってみることにします。 まず、Arduino からコンマ区切りのデータを送信するスケッチを作ります。

 *******  送信テスト4 ************

 #define LEDG_PIN 9
 #define Button 5
 void setup()
 {
   pinMode(LEDG_PIN,OUTPUT);
   pinMode(Button,INPUT);
   Serial.begin(9600);
 }
 void loop()
 {
   int voltage1;
   int voltage2;
   int voltage3;
   int current1;
   int current2;
   int current3;
   int vol_pin = 1;
   int cur_pin = 2;
   int input_Button = HIGH;
   while (input_Button == HIGH ) {
     input_Button = digitalRead(Button);
     digitalWrite(LEDG_PIN, HIGH); 
   }
   voltage1 = analogRead(vol_pin);
   current1 = analogRead(cur_pin);
   voltage2 = analogRead(vol_pin);
   current2 = analogRead(cur_pin);
   voltage3 = analogRead(vol_pin);
   current3 = analogRead(cur_pin);
   String buf = String(voltage1) + ","
+ String(current1) + "," + String(voltage2)
+ "," + String(current2)+ ","
    + String(voltage3)+ "," + String(current3)
+ ",E";    Serial.println(buf);    digitalWrite(LEDG_PIN, LOW);    delay(1000);  }
 アナログ入力から電圧と電流を交互に3回呼び込み、コンマ区切りのデータに加工して、一度に送信するようにしました。 左を参照。

 ここでも押しボタンスイッチを利用しています。 シリアルモニタでも動作を確認しました。

 簡単、簡単!
(調子に乗るなよ・・・・!)

 

 次に、幾度が作り直しましたが、Excel 側のマクロを右に示します。 受信待ちとして、受信データの中のコンマ文字を探し、コンマ付きのデータが来るまで待つっているようにしました。
 While InStr(buf$, ",") = 0

の部分です。

 受信されたデータは、コンマを頼りに切り離し、右方向のセルに書き込んで行きます。

 ここで、受信されたデータを、繰り返てし書き出すことは無いのだろうかと心配になり、書き出すたびに、シリアルポートの開閉を実施するようにしています。 ポートを開閉するたびに、バッファの内容がクリアされるのではないかと考えたからです。

 また、テストでをしている途中で気が付いたのですが、マクロが動いている間、例えば受信を待っている間は、Excel の入力処理を受けつれてくれませんし、書き込んでいるはずのセルの表示もされないままです。 これでは、リアルタイムモニタの代わりにはならない様です。

 そこで、この繰り返しは、例えば6回繰り返すと、一応マクロを完了するようにしました。 そして、セル(4、1)に次の書込み行 m を記憶させ、次回はその行から開始するようにしました。 さらに、マクロのスタート処理は、操作ボタンを作って、スタートするようにしました。 これも参考書2を参考にさせてもらいました。

 

 

 

■ 作動状態

 何回かのテストの後、うまく作動するようになりました。 しかし、データを観察していて、不安になってきました。 データが何か変なのです。 そこで、Excel の処理を1行毎に変更して、そのたびに電圧計と電流計の読みを書込み、比較することにしました。 実験装置は上記の写真と同じです。 マクロを受信状態にし、Arduino の送信ボタンを押し、その時の電流と電圧を書込みます。 コントローラで 電流と電圧を変えて同じ操作を繰り返します。

 電圧計と電流計は変化しているのに、受信したデータはそれに比例していないのです。 そこで、電圧データだけを取り出し電圧計との相関をグラフ化してみました。 電流データも同様にグラフ化した。

 

 実際の計測計で計測した値と比例している場合もありますが、それとはかけ離れた値を表示する場合が多くあります。 シリアルモニタで送信データを見てみると、同じ様なデータを示しているので、Arduino 側に原因があることは確かです。

 次回は、この原因探索と対応策を報告致します。