気の向くままに辿るIT/ICT
webzoit.netウェブサイトホームページ
IoT・電子工作

Arduinoで『距離計』を作る

ウェブ造ホーム前へ次へ
サイト内検索
カスタム検索
Arduinoって?

Arduinoで『距離計』を作る

Arduinoで『距離計』を作る

2017/12/10

 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をインストールし、インクルード
*/
 
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x3F, 16, 2); // I2C: 0x3F or 0x27, 16x2 LCD
 
const int TRIG_PIN = 5;
const int ECHO_PIN = 6;
 
void setup() {
// Serial.begin(9600);
 lcd.init();
 lcd.backlight();
 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);
}

 そのスケッチはこれ。

#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]

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

EasyWordMall Arduino UNO R3互換ボード(USBケーブル付属)

EasyWordMall Arduino Pro Mini互換ボード Atmega328 5V 16MHz

Rasbeeオリジナル FT232RL互換 3.3V/5V FTDI/USB/TTL変換アダプタ

KKHMF Arduino Nano Ver 3.0互換ボード ATmega328P CH340G 5V 16MHz

KKHMF DC 5V 1602 LCD ディスプレイモジュール 16×2キャラクタ LCDブルーブラックライト

HiLetgo HD44780 LCD 1602(16×2) バックライト:ブルーブラックライト

SODIAL(R) LCDモジュール白文字ブルーバックライト HD44780 16文字×2行 6個

HiLetgo IIC/I2C/TWI/SPIシリアルインタフェースモジュール

EasyWordMall IIC/I2C/TWI/SPI シリアルインタフェースモジュール LCD 1602/2004対応

HiLetgo 0.96インチ I2C/IIC/SPI 128×64 OLED/有機EL LCD SSD1306 ブルーイエローフォント

Rasbee 400穴 ブレッドボード 8.5*5.5cm 1個

HiLetgo 400穴 ブレッドボード 8.5*5.5cm 5個セット

HiLetgo 400穴 ブレッドボード 8.5*5.5cm 10個セット

Rasbee SY-170 ミニブレッドボード カラフルブレッドボード 5個

HiLetgo 金属皮膜抵抗 1/4W 41種類x20=820個

HiLetgo ジャンパーワイヤー(オス-オス) 20cmx40本 5セット

Rasbee ジャンパーワイヤー(オス-オス) 各種長さx65本