#027 Arduino 黄帯認定プロジェクト LCDを使わないで、複数のLEDを使った距離計を作る

#027 Arduino 黄帯認定プロジェクトLCDを使わないで、複数のLEDを使った距離計を作る



(手元に空いているLCDがなかった事と、LED使った方がセクシーで安い気がする)I-02551.jpg


 土壌湿度センサーの試験運用中で余った部品を利用してLEDインジケーターの勉強がてら、距離計を作りました。楽勝と思ったら、ハードとソフトの両面で課題の多いテーマと結局なってしまいました。


結果: 5つのLEDを利用した遠近(距離ではない)測定は成功。但し、センサー有効限度付近にmappingの最大値に対応する値が集中。mapを使って平均的に値を与えるはずだが、上手くいくっていない。センサーの感度というか、距離測定スポットの特定と安定した測定のための条件が謎。分かりやすくいうと安定していない。データーシートによる距離と出力の直線ではない。測定距離は10−80cmになる。従ってスケッチにて10cm以下は10cmとして80cm以上は80cmとした。


部品
  1. Arduino Nano 互換機 15,99 Eur / 5個
  2. LED x 5
  3. 抵抗510オーム x 5
  4. 電解コンデンサー 100μ x 1
  5. ブレッドボード x 1
  6. 配線 x 適当


総費用: 多分1000円ぐらい。上記の部品で特に記載されていないのはこちらの2つのキットからの流用です。Arduino エントリーキット(Uno版)- Physical Computing LabArduino拡張キット- Physical Computing Lab


配線時の注意:キットに付属しているセンサーに繋ぐ線の色が、センサーの端子とあっていません。センサーは検出出力、GNDそしてVCCとなっています。付属の線をそのまま利用すると、青、赤そして黒となります。通常はGNDが黒、そしてVCCが赤ですから、注意します。


まずやったこと:センサーの有効数値の確認をした。定規を利用して実際の距離とシリアルポート出力値を確認。次に計算する結果と近似していればよし。テストは大体OK。安定した数値を測定するのは容易ではなかった。センサーの感度や測定環境が理由と思われる。


データーシートから数値を計算: 計算結果 R = (6787 / (V-3)) -4
cm
10
20
30
40
50
60
70
80
Val
488
286
203
157
129
109
95
84


 


テスト用スケッチ: これがテスト用のスケッチでシリアルで生の計測結果が確認出来ます。シリアル出力は本当に便利ですね。これにProcessingをつなげると、グラフ表示が出来るのでしょう。


// Seral output test for Sharp GP2D12 infrared distance sensor

#define DIST_S     0
void setup() {
Serial.begin(9600);
}

void loop() {
Serial.println(analogRead(DIST_S));
delay(500);
}


本番スケッチ(失敗): テストの結果を踏まえて、本番スケッチを書きましたが、失敗しました。うまく行きません。測定結果条件によるLED点灯をしたいのですが、測定結果の上下を制限すること、その値を複数に切り分けて、条件分岐によって点灯させるが、上手に行きませんでした。ifを使って制限値の設定を行いましたが、そこで挫けました。上手に設定できません。シリアルで結果を見ても、狙い通りに行きませんでした。ifによる生数値による条件分岐も上手に行きませんでしたので、きっとifの使い方が間違っていると思います。とりあえずこのスケッチは捨てます。


注意事項
  1. 生計測値>= 488は488とする
  2. 生計測値<=84 は84とする
  3. 3回の計測の平均値を読み取り表示(結局しなかった)
  4. センサーの測定限度に合わせて、最小値と最大値を決めるが、うまくいかない。
  5. ifの設定がうまくいかないようだ。if条件での値の設定はp112を参照した
// Seral output test for Sharp GP2D12 infrared distance sensor
// Set up min and max val
// Issue: min val can not be fixed.

#define DIST_V     0
void setup() {
Serial.begin(9600);
}

void loop() {
 int ADJ_DIST_V;
 int temp;
 int distance;
   
 temp = analogRead(DIST_V);

 Serial.print("Distance Sensor Val: ");
 Serial.println(analogRead(temp));

 if(temp>488) ADJ_DIST_V=489;
 if(temp<84) ADJ_DIST_V=83;
 else ADJ_DIST_V=temp;

 Serial.print("Adjusted Sensor Val: ");
 Serial.println(analogRead(ADJ_DIST_V));
 
 distance = (6787 / (ADJ_DIST_V - 3)) -4;
 Serial.print(distance, DEC);
 Serial.println("cm ");
 delay(5000);
}


スケッチ最終版: 一応いいと思います。単純なことなのにえらくスケッチが長いので、きっともっと短くなると思います。ここでもifを使って最小と最大値の制限をかけました。うまく行っているようです。その後mapとswitchを使って、条件分岐をしています。前回のスケッチからここまで2日かかりました。2日間でしたことは、ネットで「LED 複数点灯」「LED Indicator」や「led level indicator arduino 」をキーワードに色々探し、調べました。ひと段落済んだ後、さらに調べると、ArduinoのサイトでBarGraphの例があり、これが一番役に立つ例だったと後から思いました。


//name: p110_Sharp
//2017.07.05
//距離を5つLEDで示すという仕組み
//LEDは距離によってきちんと変化するが、LED点灯のための距離配分がうまく行っていない
//mappingの配分が不明。
//mappingの5の時が80の付近になり、ちゃんと分配出来ていない。
//mapping を(1,6)として、5から6に変更したら、少しはよくなった気がするが
//シリアルモニターの値は相変わらずきちっと分かれていない
//(80-10)/5=14なので、値分布はこのようになるはずだ。
//1: 10-23
//2: 24-37
//3: 38-51
//4: 52-65
//5: 66-80

#define DIST_S     0
#define LED_GREEN  2
#define LED_YELLOW 3
#define LED_RED1   4
#define LED_RED2   5
#define LED_RED3   6

void setup() {
 Serial.begin(9600);
 Serial.println("Reading the sensor...After calcu / min /max / mapping");
 pinMode(LED_GREEN, OUTPUT);
 pinMode(LED_YELLOW,OUTPUT);
 pinMode(LED_RED1,   OUTPUT);
 pinMode(LED_RED2,   OUTPUT);
 pinMode(LED_RED3,   OUTPUT);  
}

void loop() {
 int temp;
 int distance;
 int val;
 //float voltage;

 temp = analogRead(DIST_S);

 if(temp<4) temp=4;
   Serial.print("Distance Sensor Val: ");
   Serial.print(temp, DEC);
   Serial.print(" / ");   
 distance = (6787 / (temp - 3)) -4;
 
 //voltage = (float)temp * (float) 0.005;

 Serial.print(distance, DEC);
 Serial.print("cm");

 if(distance<10) distance=10;
   Serial.print(" / ");
   Serial.print(distance, DEC);
   Serial.print("cm ");

 if(distance>80) distance=80;
   Serial.print(" / ");
   Serial.print(distance, DEC);
   Serial.print("cm");

 val=map(distance,10,80,1,5);
   Serial.print(" / ");
   Serial.println(val, DEC);
   
 switch(val){
   case 1:
     digitalWrite(LED_GREEN,HIGH);
     digitalWrite(LED_YELLOW,HIGH);
     digitalWrite(LED_RED1,HIGH);
     digitalWrite(LED_RED2,HIGH);
     digitalWrite(LED_RED3,HIGH);
     break;

   case 2:
     digitalWrite(LED_GREEN,LOW);
     digitalWrite(LED_YELLOW,HIGH);
     digitalWrite(LED_RED1,HIGH);
     digitalWrite(LED_RED2,HIGH);
     digitalWrite(LED_RED3,HIGH);
     break;
     
   case 3:
     digitalWrite(LED_GREEN,LOW);
     digitalWrite(LED_YELLOW,LOW);
     digitalWrite(LED_RED1,HIGH);
     digitalWrite(LED_RED2,HIGH);
     digitalWrite(LED_RED3,HIGH);
     break;

   case 4:
     digitalWrite(LED_GREEN,LOW);
     digitalWrite(LED_YELLOW,LOW);
     digitalWrite(LED_RED1,LOW);
     digitalWrite(LED_RED2,HIGH);
     digitalWrite(LED_RED3,HIGH);
     break;

   case 5:
     digitalWrite(LED_GREEN,LOW);
     digitalWrite(LED_YELLOW,LOW);
     digitalWrite(LED_RED1,LOW);
     digitalWrite(LED_RED2,LOW);
     digitalWrite(LED_RED3,HIGH);
     break;

   default:
   break;
 }
 
 delay(500);
}



おまけ:

 Sharp距離センサー GP2D12 450円 の代わりに、超音波距離センサー HC-SR04 (有効距離 2-400cm) 約200円を利用して、スケッチの再利用をしました。HC-SR04のライブラリーを利用することで、cmに換算した数値を6行書き加えるだけで利用出来ます。感覚的にはこちらの方が測定値が安定していること、ライブラリーが提供されていること、その上安いので、こちらの利用をお勧めします。Youtube等でこのセンサーを利用して障害物を避けたり、物理的なmappingをしているケースがありました。今ではこちらの方がメジャーなような気がします。こちらが購入元から提供されているサンプルコードです。


//www.elegoo.com
//2016.12.08
#include "SR04.h"
#define TRIG_PIN 12
#define ECHO_PIN 11
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long a;

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

void loop() {
  a=sr04.Distance();
  Serial.print(a);
  Serial.println("cm");
  delay(1000);
}


おまけ: arduino if文では1行の命令は{}を省く

後日、失敗したスケッチの原因がわかったような気がしました。ヒントは「変数の初期化は必ず必要なのでしょうか?」にありました。「if文では1行の命令は{}を省く」が問題となるケースについて説明があります。お馴染みの「Arduino 日本語リファレンス」を再度読み、複数のifを利用したスケッチが記載してある「Arduinoで遊ぶページ/制御構造」を見つけることができました。要するに{}を利用する必要があるということです。そこで改めてスケッチを書き直しました。


動画で一部作業を見ることができます。




#028 Arduino黄色帯認定プロジェクト 簡易防水型携帯土壌センサー制作失敗、そして仕様変更

コメント