はじめに
Nerves Livebook で Raspberry Pi 用スターター電子工作キットを楽しんでいます
SunFounder Raspberry Pi 用のスターター電子工作キット
これまでの記事
- Nerves Livebook で Raspberry Pi 4 のLチカ
- Nerves Livebook + Delux で簡単Lチカ
- MacBook 上の Livebook から Raspberry Pi 上の Livebook に接続してLチカする
- Nerves Livebook から GPIO 拡張ボードの LED を点滅させる
- Nerves Livebook から RGB LED を制御する(ソフトPWMもやってみる)
- Nerves Livebook から LED 棒グラフを制御する
- Nerves Livebook でボタンとLEDを連動させる
- Nerves Livebook で 7 セグメントディスプレイに文字を表示する
- Nerves Livebook で 4 桁 7 セグメントディスプレイに文字を表示する
- Nerves Livebook で LED ドットマトリックスにアニメーションを表示する
- Nerves Livebook でアクティブブザーを鳴らす
- Nerves Livebook でパッシブブザーを演奏しドレミの歌を奏でる
- Nerves Livebook でポテンショメーターからアナログ値を取得してデジタル値に変換する
- Nerves Livebook でフォトレジスター(光センサー)からアナログ値を取得してデジタル値に変換する
この記事では超音波センサーを使い、対象物までの距離を計測します
実装したノートブックはこちら
超音波センサー
超音波(人間の耳に聞こえない音)を正面に向けて出力し、跳ね返ってきた超音波を検出します
出力してから跳ね返ってくるまでの時間によって、正面にある物体がどれくらい離れているか、つまり距離を計測することが可能です
イルカや蝙蝠がやっているエコーロケーションですね
回路の組み立て
オンライン説明書の通りに回路を組みます
ノートブックの実装
Nerves Livebook を開き、以降のコードを実行していきます
ピンを開く
超音波センサーを制御するためのピンを開きます
{:ok, trig} = Circuits.GPIO.open("GPIO23", :output)
{:ok, echo} = Circuits.GPIO.open("GPIO24", :input)
trig
を超音波発信用の出力、 echo
を超音波検出用の入力にしています
モジュール定義
超音波センサーの制御用モジュールを定義します
defmodule UltrasonicSensor do
def distance(trig, echo) do
Circuits.GPIO.write(trig, 0)
Process.sleep(1)
# 1 msec の超音波を送信
Circuits.GPIO.write(trig, 1)
Process.sleep(1)
Circuits.GPIO.write(trig, 0)
# 最初は 0 の状態を確認
time_1 = wait_for(echo, 0)
# 1 になるまでの時間を取得
time_2 = wait_for(echo, 1)
during = Time.diff(time_2, time_1, :microsecond)
# 空気中の音速を使って距離(cm)に変換(往復なので半分にする)
during * 340 / 2 / 10000
end
defp wait_for(echo, value) do
1..10000
|> Enum.reduce_while(nil, fn _i, _acc ->
if Circuits.GPIO.read(echo) == value do
{:cont, Time.utc_now()}
else
{:halt, Time.utc_now()}
end
end)
end
end
Circuits.GPIO.write(trig, 1)
によって超音波を発します
Process.sleep(1)
で 1 ミリ秒待ってから Circuits.GPIO.write(trig, 0)
にすると、 1ミリ秒だけ超音波を出していたことになります
Circuits.GPIO.read(echo)
の結果が 0 から 1 に変化したときが、超音波の跳ね返ってきたときです
跳ね返ってくるまでの時間と音速(340 m/s)を使うと、正面の物体までの距離が計算できます
距離の計測
実際に距離を計測してみます
100 回連続して計測している間、超音波センサーの前で手のひらを前後させてみました
1..100
|> Enum.map(fn _ ->
UltrasonicSensor.distance(trig, echo) |> IO.inspect()
Process.sleep(100)
end)
距離のグラフ化
数字だけだとピンとこないので、グラフで距離をリアルタイムにプロットしてみました
distance_plot =
VegaLite.new(width: 700)
|> VegaLite.mark(:line)
|> VegaLite.encode_field(:x, "index", type: :quantitative)
|> VegaLite.encode_field(:y, "distance", type: :quantitative)
|> Kino.VegaLite.new()
Kino.VegaLite.clear(distance_plot)
1..300
|> Enum.map(fn index ->
distance = UltrasonicSensor.distance(trig, echo)
IO.inspect(distance)
plot_data = %{
index: index,
distance: distance
}
Kino.VegaLite.push(distance_plot, plot_data)
Process.sleep(100)
end)
今度はリバテープの箱を対象物にしています
ピンを閉じる
遊び終わったらピンを閉じます
Circuits.GPIO.close(trig)
Circuits.GPIO.close(echo)
まとめ
手の平だと計測があまり安定せず、 Qiitan ぬいぐるみだとほとんど正しく計測できませんでした
リバテープの箱のように、超音波をしっかり跳ね返してくれるものでないと上手くいかない、ということが分かりました