📖

ArduinoからProcessingに可変抵抗器(ボリューム)の値を送信した時の値のブレについて

2022/01/13に公開2

概要と動作環境

初記事です。
ボリュームの値をArduinoからProcessing側にシリアル通信で送信した時の値のブレについて、解決法がわかったので共有します。

使用機材は、

  • ARDUINO UNO R3
  • ジャンパワイヤ × 3
  • ボリューム(TSR-3386T-EY5-103TR)
  • USBケーブル(マイコンとPCを接続する用)
    です。

以下の実態配線図のように配線していました。

生じた問題について

Arduinoでボリュームの値を読み取り、シリアル通信を用いてProcessing側に送信しようとしたところ、的外れな値をランダムに出力し続けてしまうという問題が発生していました。その時のコードが以下の二つです。

Processing側のコード

import processing.serial.*;
Serial my_serial;
int input;

void setup(){
  println( Serial.list() ); 
  my_serial = new Serial( this, Serial.list()[2], 9600 );
  // println(Serial.list())でシリアルポートの一覧が表示されるので
  // その中からArduinoが接続されているポートに
  // Serial.list()[2]の[]の中の数字を書き換えてください。
  // 僕の場合は2番のポートでした。
}

void draw(){
println(input);
}

// シリアルポートにデータが来た時に呼び出される関数。
void serialEvent(Serial port){
input = port.read();
}

Arduino側のコード

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

void loop()
{
int value = analogRead(0); // アナログピン0番の値を読み取る
Serial.println(value);
Serial.write(value);
}

結果として、Processing側ではコンソールでは以下のように規則性のない値が表示されました。この時ボリュームのつまみは動かしてないです。

Arduino側ではシリアルモニタで値を見てみると、ボリュームから得た値の頭に謎の文字がついています。画像ではVが表示されていますが、ボリュームの値を動かすとアルファベットに限らずいろんな文字が数値の頭にくっつきます。

解決法

単純ですが、Arduino側のスクリプトから Serial.println(value); を削除したところ、安定した値がコンソールに出力されるようになりました。

Arduino側のコード

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

void loop()
{
int value = analogRead(0); // アナログピン0番の値を読み取る
Serial.write(value);
}

Processingのコンソール

Arduino側で送信している値を確認する術はなくなりましたが、これで値が安定しました。ボリュームのつまみをいじると正しく値が変化しました。

おわりに

すごい単純な問題でしたが、もしかしたら同じ問題にあたった人の助けになるかと思って記事を書いてみました。もしこの問題の原因がわかる方がいらっしゃいましたら、教えていただけると幸いです。

Discussion

Hideaki TaiHideaki Tai

話を簡単にするため、Ardunoのコードとシリアルモニタでの表示に絞って説明しますね。Serial.write() Serial.print() Serial.println() の違いから理解するのが良いと思います。

  • Serial.write(v): v をバイナリデータ (生の数値) として出力
  • Serial.print(v): v を文字と認識してASCIIデータを出力 (生の数字を文字として表示している)
  • Serial.println(v): print() のASCIIデータに改行 (\r\n) を追加して出力

ごくごく単純化して英数字だけに限定してお話すると、PC上に表示される英数字は、0-127 の数値を文字に読み替えて表示しています。これを ASCII コードと言います。私たちには「文字」として見えていますが、PC の中では単純な数値の羅列なんですね。例えば、10 進数の 65A66B86V になります。値と ASCII コードの対応表はこんな感じです。

https://www.k-cube.co.jp/wakaba/server/ascii_code.html

また、OS 等によって異なりますが、改行には 13 10 という 2 つの数値を使います。13\r10\n と表されるものです。詳しくはこのへんを。

https://ja.wikipedia.org/wiki/改行コード

Arduino のコードに話を戻すと、Serial.println() を使うと、渡した「数値」 86 を勝手に「文字」だと認識し、ASCIIコードの "8" と "6" の2つを出力しようとします。加えて、これに改行が追加されます。
一方で Serial.write() は、渡した「数値」をそのまま「数値」として出力します。
なので、

int value = 86;
Serial.println(value);  // 数値の 56 54 13 10 つまり文字列 "8 6 改行(\r \n)"
Serial.write(value);    // 数値の 86          つまり文字列 "V"

これを loop() で連続して送ると、下記のようになるわけです。

V86 (改行)
V86 (改行)
V86 (改行)
...
RintaroRintaro

本当に長いことお返事が遅れて申し訳ありません...
ありがとうございます!理解出来ました!!