ELEGOO:Lesson 10

Lesson 10

超音波による距離センサーです!かっこいい!HC-SR04って型番の、電子工作では定番のセンサーです。

 

裏面にも回路がついてます!


ピンは、電源の5V / GNDと、計測用トリガーピン / エコーピンの4本です。

トリガーピンに10us のHIGH信号を入れると、40MHzの超音波を8回出します。同時に、エコーピンがHIGHレベルになります。音が反射して帰ってくるのを検出したら、エコーピンがLOWレベルになります。

エコーピンがHIGHレベルになっている時間を計測することで、音を出して反射して帰ってくるまでの時間がわかります。音の速度(340m/s)をベースに、かかった時間から距離を求めることができます。

距離 = HIGHレベルになってる時間 x 音の速度(340m/s)÷ 2(往復)ですね。

計測サイクルが短すぎると、正しく計測できないので、60ms 以上間隔を開けたほうがいいですよ、とのこと。

音速は温度によって変わりますので、いつも340m/sってわけではないのですけど、そのへんは今回は気にせずに!


HC-SR04 用の Ardiono ライブラリはいろいろあるみたいですが、Lesson 10 サンプルのファイルに付属していたライブラリを使っています。計測のプログラムはこんな。

#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);
}

トリガーピンとエコーピンの番号を指定して、呼び出しています。

結果はコンソールで確認できます。仕掛け的に、急速に近づいたり遠ざかったりしているものは変な値(上で言うと2329cm)になりますね。

最初シリアル通信が9600bps指定になってること気づかずに、出力が見れなくてちょっとあせりました。


実際の計測処理はライブラリの中で全部行われてますね。ライブラリ側のソースも確認してみます。

SR04::SR04(int echoPin, int triggerPin) {
    _echoPin = echoPin;
    _triggerPin = triggerPin;
    pinMode(_echoPin, INPUT);
    pinMode(_triggerPin, OUTPUT);
    _autoMode = false;
    _distance = 999;
}

エコーピンを入力、トリガーピンを出力に設定

long SR04::Distance() {
    long d = 0;
    _duration = 0;
    digitalWrite(_triggerPin, LOW);
    delayMicroseconds(2);
    digitalWrite(_triggerPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(_triggerPin, LOW);
    delayMicroseconds(2);
    _duration = pulseIn(_echoPin, HIGH, PULSE_TIMEOUT);
    d = MicrosecondsToCentimeter(_duration);
    delay(25);
    return d;
}

計測。まずトリガーピンをLOWに設定。2 マイクロ秒待ってから、トリガーピンを 10 マイクロ秒の間HIGHに設定。これで計測用超音波が出ます。
pulseIn(_echoPin, HIGH, PULSE_TIMEOUT); で、エコーピンがLOWになるまでの時間を計測。
Reference > Language > Functions > Advanced io > Pulsein

https://www.arduino.cc/reference/jp/language/functions/advanced-io/pulsein/

pulseIn() を HIGH に設定した場合, ピンが HIGH になった時点を開始時間とし, LOW になった時点を終了時間とします.そして,そのパルス幅をマイクロ秒で返します.タイムアウト時間を設定し,タイムアウトした場合は,0を返します.

おおー。便利な関数だ!

トリガーピンをLOWにした後の、delayMicroseconds(2) は何だろう…安定待ち?

ちなみに PULSE_TIMEOUT は、SR04.h で

#define PULSE_TIMEOUT 150000L // 100ms

と定義されていました。

MicrosecondsToCentimeter で、時間から距離の変換をしています。

long SR04::MicrosecondsToCentimeter(long duration) {
    long d = (duration * 100) / 5882;
    //d = (d == 0)?999:d;
    return d;
}

340m進むのに1秒。 ということは、1m進むのには
1 / 340 / 100 = (0.002941 / 100)秒 = 2941uS
往復で計測するので、2941uS * 2 = 5882uS の場合に、距離 1m となります。
なので、エコーピンでの計測が duration uS であれば
距離は duration / 5882 m = duration /5882 * 100 cm
てことですね。

「1秒で340cmだから、1uS だと 340 / 1000000 cm」なので
距離 =( duration / 2 ) * ( 340 / 1000000 ) * 100
のほうが、素直な気がする。


この距離センサーも、M5StackのMicroPythonから使ってみようと思ったのですが、マイクロ秒での制御が必要なんですよね。

そんなのできるのかな、と探してみると、先人の方がいらっしゃいました。

HC-SR04 Sensor driver in micropython
https://github.com/rsc1975/micropython-hcsr04

いろいろてすと中:M5Stack × 超音波センサ(HC-SR04)で距離を測る
https://kappazu.com/2018/08/18/m5stack-x-超音波センサhc-sr04で距離を測る/

おおおー。できるんだー!

time.sleep_us() を使えば、マイクロ秒でスリープできるのですね。ミリ秒指定の time.sleep_ms() もある。

せっかくなので接続は、M5Stack Fire から Grove経由で!
…と思ったのですけど、Grove からだと、HC-SR04の動作に必要な 5V電源 が取れないのでした。残念。あきらめて M5Stack Grayから。
単体で外部に繋いでいろいろやりたい人には、MStack5 Fire トップ + M5Stack Normal/Gray ボトム が最強なのかも。
(→ Grove電源のボルト数については勘違いでした!詳しくは下に!)

プログラムはこういう感じです。1秒間隔で計測して画面表示しています。

machine.time_pulse_us(echo_pin, 1, PULSE_TIMEOUT) で Arduino の pulseIn() と同様に時間の計測ができます。

フォントは、こちらのフォントをフォントツールで変換して使っています。

x12y20pxScanLine スキャンライン
http://www17.plala.or.jp/xxxxxxx/00ff/

M5Cloud/examples/Display/font_tool/
https://github.com/m5stack/M5Cloud/tree/master/examples/Display/font_tool


3.3V~5Vで動作する低電圧用の距離センサパーツもありますね。Groveで使いたいならこれか。

GROVE – 超音波距離センサモジュール
https://www.switch-science.com/catalog/1383/


追記:GROVE電源のボルト数について

 

5StackのGrove端子の電源、3.3V だと(なぜか)思い込んでいたのですが、計ってみたところ、

5V でした!!

なので、HC-SR04 も動作可能です。GROVE ポートA を使いました。各GROVE端子の信号はこういう感じ。

接続は、以下の通り。
赤(5V)- Vcc
黒(GND)- Gnd
白(SDA:21)- Trig
黄(SCL:22) - Echo

プログラムのポートを変えて接続。

trigger_pin = machine.Pin(21, machine.Pin.OUT)
echo_pin = machine.Pin(22, machine.Pin.IN)

バッチリだ!

ポートB(26 / 36)に差し替えてもいけました。

trigger_pin = machine.Pin(26, machine.Pin.OUT)
echo_pin = machine.Pin(36, machine.Pin.IN)

あれれ?36ってアナログ入力ポートじゃなかったっけ…?M5Stackの動作、まだまだ理解できてないところ多いです。