気の向くままに辿るIT/ICT/IoT
IoT・電子工作

Arduinoで『距離計』を作る

ホーム前へ次へ
Arduinoって?

Arduinoで『距離計』を作る

Arduinoで『距離計』を作る

2017/12/10

 Arduinoを使って『距離計』を自作してみるページ。

超音波距離計を作る

 超音波測距モジュールHY-SRF05を使って超音波による距離計を作ってみるページ。

 ArduinoとHY-SRF05で超音波距離計を作ることはできました。

 が、温度計を組み合わせたら、謎の失敗に終わったということを記録しておきます。

 超音波は、温度や湿度、気圧などの影響を受けやすいと言われており、モニタに表示した際、値が多少ブレ、常時変動するのは、当然と考えて良いでしょうが、それとは別に微妙な状況に遭遇しました。

 と言うのも...

超音波センサHY-SRF05単体による距離計

 HY-SRF05温度センサ0.96インチOLED(有機EL(パネル))も単独では購入した当初の動作確認はできました。

 今回検証時には、(ちなみに全てAmazon/HiLetgoで買った)Pro Mini、Nano、Uno共に正常に機能することを確認済みです。

 例えば、室温20度でNano互換機+HY-SRF05+LCD 1602(I2Cモジュール接続)だとかなりの精度が出ました。

 超音波の遮蔽物となり得るものが一切ない環境で試したわけではないため、特に最長距離は正確とは言えませんが、実測してみたところ、HY-SRF05の安定した検出可能距離範囲は、2cm〜3.2m(20mm〜3200mm)程度と言ったところかと。

/*
Arduino IDE > [スケッチ] > [ライブラリの管理]で
jm_LiquidCrystal_I2Cをインストールし、インクルード
LiquidCrystal_PCF8574をインストールし、インクルード
*/
 
#include <LiquidCrystal_I2C.h>
#include <LiquidCrystal_PCF8574.h>
 
/*
//LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C: 0x3F or 0x27, 16x2 LCD
LiquidCrystal_I2C lcd(0x3F, 16, 2); // I2C: 0x3F or 0x27, 16x2 LCD
*/
//LiquidCrystal_I2C lcd(0x27);
LiquidCrystal_I2C lcd(0x3F);
 
const int TRIG_PIN = 5;
const int ECHO_PIN = 6;
 
void setup() {
// Serial.begin(9600);
 lcd.init();
 lcd.backlight();
lcd.setBacklight(HIGH);
 lcd.setCursor(0, 0);
 lcd.print("Loading...");
 
 pinMode(TRIG_PIN,OUTPUT);
 pinMode(ECHO_PIN,INPUT);
}
 
void loop()
{
  long duration, distanceCm, distanceIn;
 
 // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
 digitalWrite(TRIG_PIN, LOW);
 delayMicroseconds(2);
 digitalWrite(TRIG_PIN, HIGH);
 delayMicroseconds(10);
 digitalWrite(TRIG_PIN, LOW);
 duration = pulseIn(ECHO_PIN,HIGH);
 
 // convert the time into a distance
 distanceCm = duration / 29.1 / 2 ;
 distanceIn = duration / 74 / 2;
 
 if (distanceCm <= 0){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Out of range");
//  Serial.println("Out of range");
 }
 else {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(distanceIn);
  lcd.print(" inch");
  lcd.setCursor(0,1);
  lcd.print(distanceCm);
  lcd.print(" cm");
/*
  Serial.print(distanceIn);
  Serial.print("in, ");
  Serial.print(distanceCm);
  Serial.print("cm");
  Serial.println();
*/
 }
 delay(1000);
}

 そのスケッチはこれです。

2019/04/04

 Arduino製回転計を見直し、LCD 1602を併用して気づいた点を修正します。

 自身が他のライブラリと勘違いして書き間違えたのか、はたまた当初使っていたjm_LiquidCrystal_I2Cの仕様が変わったようでjm_LiquidCrystal_I2C.hをインクルードしたり、更に追加で2つほどヘッダファイルをダウンロードしてこなくてはならず、いざやってみたら、ちょっとハマりました。

 結果、気づけば、Arduino IDEの[ライブラリ管理]に複数あったLiquidCrystalのI2C系ライブラリの内、LiquidCrystal_PCF8574が使いやすそうなので変更しておきます。

 このライブラリを使う場合、Arduino IDEの[スケッチ] => [ライブラリをインクルード]から[LiquidCrystal_PCF8574](LiquidCrystal_PCF8574.h)をインクルード、スケッチ内に太字で追記しておきますが、インスタンス生成時、LiquidCrystal_PCF8574 lcd(0x27);/LiquidCrystal_PCF8574 lcd(0x3F);のように識別子のみ(表示文字数や行数指定は不要)でOK、また、デフォルトでは、バックライトは消灯のようで明示的にlcd.setBacklight(HIGH);行を追加(既存行lcd.backlight();と差し替え)すれば、あとは、同様に使えます。

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define temp_sensor A0
 
const int trig = 2;
const int echo = 3;
double Duration = 0;
double Distance = 0;
 
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
 
 
#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2
 
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };
 
void setup() {
  Serial.begin( 9600 );
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
 
  display.begin(SSD1306_SWITCHCAPVCC);
 
  display.display();
  delay(2000);
 
  display.clearDisplay();
}
 
void loop() {
 
  int analog_val;
  double temp;
 
  analog_val = analogRead(temp_sensor);
  temp = double((analog_val*500)/1024.0);
//  temp = (analog_val * 500) / 1024;
  Serial.print("analog_val: ");
  Serial.println(analog_val);
  Serial.print("temp: ");
  Serial.print(temp);
  Serial.println(" C");
  //digitalWrite(trig, LOW);
  //delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  Duration = pulseIn(echo, HIGH);
  if (Duration > 0) {
    Distance = Duration/2;
    float sspeed = 331.5+0.6*temp;
    Serial.print("\tspeed:");
    Serial.print(sspeed);
    Serial.print("m/sec");
    Distance = Distance*sspeed*100/1000000;
    Serial.print("\tDistance:");
    Serial.print(Distance);
    Serial.print("cm");
    Serial.println("");
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0,0);
    display.print("Distance : ");
    display.print(Distance);
    display.println(" cm");
    display.display();
    delay(2000);
    display.clearDisplay();
  } else {
    Serial.println("Duration < 0");
  }
}

 が、HY-SRF05に温度センサ・OLED 0.96インチを組み合わせ、温度による超音波精度を計算、かつ、ArduinoボードにPro MiniとNanoを使うと気温17度ほどの時、アナログ入力値の変動がわずかなのに温度誤差がプラスマイナスに激しく変動、そのブレとは別に算出距離が正常値とほぼ一定の値を繰り返し表示したりし、Unoだと算出温度が10度ほど高くはなりますが、多少のブレはあり、絶えず変動はしているものの、距離はある程度安定する

という状況に...。

 とりあえず、検証に使った、切り貼りのラフスケッチを晒しておきます。

 コメントアウトしている部分もありますが、代替しても、外しても結果は同じでした。

/*
https://tkkrlab.nl/wiki/Arduino_KY-013_Temperature_sensor_module
*/
#include <math.h>
int sensorPin = A0; // select the input pin for the potentiometer
 
double Thermistor(int RawADC) {
  double Temp;
  Temp = log(10000.0*((1024.0/RawADC-1)));
  Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
  Temp = Temp - 273.15;            // Convert Kelvin to Celcius
  //Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
  return Temp;
}
 
void setup() {
Serial.begin(9600);
}
 
void loop() {
int readVal=analogRead(sensorPin);
double temp =  Thermistor(readVal);
 
Serial.println(temp);  // display tempature
//Serial.println(readVal);  // display tempature
 
delay(500);
}

 ちなみに温度算出に関しては、これら数値がどこから出てくるのか不明も、こんな式もあるようで試してみましたが、ほぼ正確な値に落ち着くまで一定の時間がかかるため、今回は見送りました。

 Pro MiniとNanoについては、一向に上達する兆しが見えず、いつまで経っても下手くそな自身が半田付けしたのでハンダ不良の可能性が高いんだろうなとも思う反面、Pro MiniもNanoも複数個試してどれも同じような状況になることからして本当にそれ(だけ)が原因と断定してよいのか微妙にも思えます。

 ただ、そういえば、電圧計を作った時、UnoやPro Miniでは誤差はないのに、なぜか、Arduino Nanoでは複数個試してみても、他方、AC100V家電制御時にUno+温度センサを使ってみた際にも約10度程度高くなったのですが、何れのケースもほかが定数値であることから、アナログ入力値が高いか演算誤差が生じていることになりますが、かと言って何れかの個体やArduinoボードだけの現象ではなさ気となると、何らかの複合的な要因によるものなのか...。

 単体ではOKなため、測距モジュールも、また、OLEDやシリアルモニタ上も誤差は誤差として表示されるため、問題ないと思われます。

 スケッチのサイズも変数宣言も40〜50%程度で問題はないと思われます。

 Uno、Pro Mini、Nano共にATmega328Pなので演算や演算時間に関しては仕様上は条件は同じと思われます。

 演算時間が微妙に足りないのか、それとも、これらの内、何か見過ごしているのか、他に何かあるのか、自身の単純ミスや確認ミスか、どのPro MiniやNanoボードも同じ要因を引き起こすような眼には見えないハンダ飛びやハンダ不良があるのか、...互換機メーカーの差、個体差、ロット差などもなくもないのか?んー...。

 ちなみに、この検証時、ケーシングを想定していない状態ながら、一通りできたところで写真を撮ろうと、つい、うっかり、グリップの強いステンレス製洗濯バサミでOLEDのフレキ配線部を挟んでしまったら、当然のようにショートして熱くなり、壊れ...意気消沈、以後、確認作業する気も失せ、中止...。

[2018/03/25]

 あ...、気温を加味した際の加減乗除で優先すべき部分式にカッコがないからか...?

ホーム前へ次へ