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の動作、まだまだ理解できてないところ多いです。