ElixirでDYP-A01超音波距離センサー

[English](https://dev.to/mnishiguchi/use-dyp-a01-ultrasonic-distance-sensor-in-elixir-bp4)

## はじめに

たまたま先日@piacerex さんが距離センサー探されていたのがきっかけで、ちらっと検索してしてみて面白そうだったので、興味本位に６メートル程まで計測できる超音波距離センサーを購入しました
せっかくなのであえて既存の[Elixirライブラリー](https://hex.pm/)の無いものを選んで自分でデバドラを書いてみることにしました

[![](https://cdn-shop.adafruit.com/1200x900/4664-03.jpg)](https://www.adafruit.com/product/4664)

[DYP-A01]: https://www.adafruit.com/product/4664
[DYP-A01超音波距離センサー]: https://www.adafruit.com/product/4664
[Elixir]: https://elixir-lang.org/
[Nerves]: https://www.nerves-project.org/
[Raspberry Pi Zero]: https://www.sparkfun.com/products/15470
[Raspberry Pi 4]: https://www.raspberrypi.org/products/raspberry-pi-4-model-b/
[dypa01]: https://hex.pm/packages/dypa01

## できたもの

- [Elixir]で[DYP-A01超音波距離センサー]をいごかすコードをHexパッケージ[dypa01]としてリリースしました
- [Raspberry Pi Zero]と[Raspberry Pi 4]に[DYP-A01超音波距離センサー]を接続し距離測定に成功しました
  - Raspberry Pi Zero
    - UART Rxピン (GPIO 15)
  - Raspberry Pi 4
    - UART Rxピン (GPIO 15)
    - USBポート

## ファームウェア

ファームウェアについてここでは特にお話しませんが、[Elixir]プログラミングでRaspberry Pi等で使える組み込みLinuxファームウエアが作れる[Nerves]というプラットフォームを利用しました
もしまだ[Nerves]を使ったことが無い方は、いろんな資料がありますのでぜひ[Nerves]をお試しください

ドキュメント

- [Nerves documentation](https://hexdocs.pm/nerves/getting-started.html)
- [Nerves • Elixir School](https://elixirschool.com/en/lessons/specifics/nerves/)

サンプルファームウエア

- [Nerves Livebook firmware](https://github.com/fhunleth/nerves_livebook)
- [Nerves example firmware collection](https://github.com/nerves-project/nerves_examples)

Nerves作者[Frank Hunleth](https://twitter.com/fhunleth?lang=en)さん解説YouTube

- [Elixir in Embedded Systems using Nerves Livebook](https://youtu.be/P_xryjmG35I)
- [Elixir Wizards Live: Frank and the Wizards](https://youtu.be/qp56tIEnYH4)

## 使用した部品

|   |   |
|---|---|
|[DYP-A01 超音波距離センサー](https://www.adafruit.com/product/4664)   | ![](https://cdn-shop.adafruit.com/970x728/4664-04.jpg)  |
|[USB〜TTL 変換シリアルケーブル](https://www.adafruit.com/product/954)   | ![](https://cdn-shop.adafruit.com/970x728/954-02.jpg)  |
| [ジャンパーワイヤー](https://www.google.com/search?q=jumper+wires&tbm=isch)  | ![](https://cdn-shop.adafruit.com/970x728/1956-02.jpg)  |
| [Raspberry Pi 4](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/)  | ![](https://www.raspberrypi.org/homepage-9df4b/static/raspberry-pi-4-labelled-2857741801afdf1cabeaa58325e07b58.png)  |
|[Raspberry Pi Zero W (ヘッダー付)](https://www.sparkfun.com/products/15470)   | ![](https://cdn.sparkfun.com//assets/parts/1/4/0/5/9/15470-Raspberry_Pi_Zero_WH-01.jpg) |

## 配線

USBを使う場合と、GPIOピンを使う場合との２通りが可能なようです

### USB を使う場合

カタログの説明を見た印象では簡単に USB に接続できそうに見えましたが、実際に品物が届いたときに少し戸惑いました
距離センサーのコネクターと USB〜TTL 変換シリアルケーブルの先端部とが全く異なる形状をしてるのです

![](https://cdn-shop.adafruit.com/970x728/954-02.jpg)

結局、ジャンパーワイヤーでハックできることを知り、一旦わかれば即解決しました
４本のうち１本は使いません
[データシート](https://cdn-shop.adafruit.com/product-files/4664/4664_datasheet.pdf)によると「UART auto output」という機能だそうで、センサー側が自動で定期的に 250msごとに計測データをコントローラ側に送ってくれるとのことです

![20210831_173325](https://user-images.githubusercontent.com/7563926/131585666-806f64b5-4f76-49e0-875d-9f12a48427c0.jpg)
![20210831_173120](https://user-images.githubusercontent.com/7563926/131585661-4fdbd79a-7b2a-4bd1-87f6-024e6119f01a.jpg)

| DYP-A01            | USB to TTL Serial Cable |
| ------------------ | ----------------------- |
| 赤 (3.3-5V)        | 赤 (5V)                 |
| 黒 (Ground)        | 黒 (Ground)             |
| 橙 (RX / Receive)  | -                       |
| 白 (TX / Transmit) | 白 (RX / Receive)       |

### GPIO を使う場合

GPIOを使い場合も同様に全部で４本あるうちの３本を配線します

| DYP-A01               | Raspberry Pi           |
| --------------------- | ---------------------- |
| 赤 (3.3-5V)          | 5V                     |
| 黒 (Ground)        | Ground                 |
| 橙 (RX / Receive) | -                      |
| 白 (TX / Transmit) | GPIO 15 (RX / Receive) |

[Raspberry Pi pinout](https://pinout.xyz/pinout/uart)

## DYP-A01をいごかすためのElixirコード

[DYP-A01]をいごかすためのコードはHexパッケージ[dypa01](https://hex.pm/packages/dypa01)としてリリースしましたので、ファームウエアの`mix.exs`ファイルに依存関係に追加してインストールできます

```elixir
def deps do
  [
    {:dypa01, "~> 0.1"}
  ]
end
```

## シリアルポート名を探す

Raspberry Piと[DYP-A01]センサーとで通信するためには先ずRaspberry Piのどのシリアルポートを使用しているのか、シリアルポート名で把握する必要があります
[dypa01](https://hex.pm/packages/dypa01)ライブラリーはシリアル通信に[circuits_uart](https://hex.pm/packages/circuits_uart)ライブラリーをしようしています
シリアルポート名を探すには`Circuits.UART.enumerate/0`関数が便利です

```elixir
iex> Circuits.UART.enumerate
%{
  "ttyAMA0" => %{},
  "ttyS0" => %{},
  "ttyUSB0" => %{
    description: "CP2102 USB to UART Bridge Controller",
    manufacturer: "Silicon Labs",
    product_id: 60000,
    serial_number: "0001",
    vendor_id: 4292
  }
}
```

複数リストに上がる場合がありますが、デフォルトで使用されるポートは設定ファイル `/boot/config.txt`に記述されているようです

```elixir
iex> cmd "cat /boot/config.txt | grep tty"
# Enable the UART (/dev/ttyS0)
0
```

[Raspberry Pi Zero] は`ttyAMA0`、[Raspberry Pi 4]は`ttyS0`がGPIO 14~15ピンに割り当てられているようです
[Raspberry Pi GPIOを使用したシリアル通信 by Indgenious](https://www.ingenious.jp/articles/howto/raspberry-pi-howto/gpio-uart/)によると機種によって設定がことなるようです
[Raspberry Pi 4] でUSBを使う場合は、`ttyUSB0`で通信ができるようです

## 距離測定

あとは以下のような簡単なElixirコードで距離測定ができます

```elixir
iex> {:ok, pid} = DYPA01.start_link(port_name: "ttyAMA0")
{:ok, #PID<0.1407.0>}

iex> DYPA01.measure(pid)
{:ok, %DYPA01.Measurement{distance_mm: 1680, timestamp_ms: 321793}}
```

## さいごに

@piacerex さんのおかげで新しいことが学べました
距離センサーを使って何をされるのかが気になります
たのしみですね