Groveと産業機器をつないでみよう

#1.はじめに

工場などで使われる産業機器を、GROVEコネクタに接続して、制御できるようにしてみました。

>[昨年のアドベントカレンダー](https://qiita.com/myasu/items/cd173547da7616fdf359)にも同様の記事を投稿していましたが、Grove対応版が結局間に合わず、１年経ってしまいました･･･今回改めて作り直しましたので、紹介します。

#2.ハードウェア

SeeedさんのGroveシリーズには、接続インターフェースのラインナップがありませんので、自作してみました。
外観はこんな感じです。（左：出力用、右：入力用）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/2b6577c1-f69f-365f-9c5c-cbadb179d043.png)
[Grove Base HAT](https://www.marutsu.co.jp/pc/i/1558555/)経由でRaspberryPiに接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/52c1760f-4dcb-e7e4-bb49-e6823c76844a.png)


##(1)考え方

GROVEの制御電圧はDC3.3VあるいはDC5Vです。
一方、産業機器の多くはDC24Vで動作しますので、GROVEコネクタとは直結できません。
「電圧レベルの変換」と呼ばれる工夫が必要です。

今回のユニットでは、フォトカプラを使っています。
[TLP627](https://akizukidenshi.com/catalog/g/gI-07691/)や[TLP222](https://akizukidenshi.com/catalog/g/gI-07672/)は、定格電流が100mA以上流せるので、ランプやリレーは直結して駆動ができます。

**NOTE**
リレーなどコイルを使用しているものをトランジスタ・FETなどに接続する際は、コイルOFF時の逆起電力による破損防止のため「還流ダイオード」[^fd]の接続が必要です。
市販のリレーには、始めからダイオードが内蔵されているものもありますので、購入する際に予め型式を指定しておきましょう。

例）

 - [IDEC DC24Vリレー](https://jp.idec.com/idec-jp/ja/JPY/%E3%83%AA%E3%83%AC%E3%83%BC%E3%83%BB%E3%82%BF%E3%82%A4%E3%83%9E/%E3%83%AA%E3%83%AC%E3%83%BC/RJ%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E3%82%B9%E3%83%AA%E3%83%A0%E3%83%91%E3%83%AF%E3%83%BC%E3%83%AA%E3%83%AC%E3%83%BC/p/RJ1S-CLD-D24)
 - [OMRON DC24Vリレー](https://www.fa.omron.co.jp/product/item/7290/)


[^fd]: 参考資料例　http://sudoteck.way-nifty.com/blog/2010/07/post-c24f.html

##(2)基板を作ってみる

[KiCAD](https://kicad.org/)を使って基板を設計してみました。
ガーバデータや回路図含め、データ一式はGitHubに公開しています。

 - [Digital Input 4ch](https://github.com/trihome/Grv_FAModules/tree/master/DigitalInput4ch)
 - [Digital Output 4ch](https://github.com/trihome/Grv_FAModules/tree/master/DigitalOutput4ch)

READMEで紹介しているとおり、基板裏面のジャンパーを切り替えることで、シンク（NPN）／ソース（PNP）駆動を切り替えることができますので、国内外問わず使用可能です。

基板の製造については、一例としてSeeedさんが運営の「[Fusion PCB](https://www.fusionpcb.jp/)」での発注の例を、下記にまとめていますのでご参考ください。

 - [発注方法](https://github.com/trihome/RasPi_PiFA/blob/master/doc/README_pcb.jp.md)

#3.ソフトウェア

Pythonは多くの例があるので、ここでは敢えてそれ以外の言語で操作してみました。

|言語|制御ライブラリ|
|:--|:--|
|Go|GOBOT|
|Rust|rppal|
|Elixir|Elixir Circuits|

##配線の接続

下記の様に繋いでいます。

|HATのコネクタ|GPIO(BCM番号)|接続先|
|:--|:--|:--|
|D5|5|押しボタン|
|D16|16|ランプ|

##(1)Golang

入出力制御のライブラリ [gobot](https://gobot.io/documentation/platforms/raspi/)を使います。
インストールは上記リンク先の「How to Install」か、[別記事で紹介](https://qiita.com/myasu/items/aa3bf62001b4aaaf9ac7#2%E6%BA%96%E5%82%99)しているものを参考願います。

### ソースコード

押しボタンを押すと、ランプが点灯します。

#### ピン番号指定の注意！！
gobotでの入出力ピン番号指定は**物理ピン番号(Physical)**です。
**BCM番号ではありません**のでご注意ください。

```golang:led.go
package main

import (
	"fmt"

	"gobot.io/x/gobot"
	"gobot.io/x/gobot/drivers/gpio"
	"gobot.io/x/gobot/platforms/raspi"
)

// GPIOを物理ピン番号で指定
const GPIO_LED = "36" //BCM16→Pin36
const GPIO_BTN = "29" //BCM5 →Pin29

func main() {
	r := raspi.NewAdaptor()
	//定義
	led := gpio.NewLedDriver(r, GPIO_LED)
	button := gpio.NewButtonDriver(r, GPIO_BTN)

	//イベントを定義
	work := func() {

		//ボタンがONの時
		button.On(gpio.ButtonPush, func(data interface{}) {
			fmt.Println("button pressed")
			//点灯
			led.On()
		})

		//ボタンがOFFの時
		button.On(gpio.ButtonRelease, func(data interface{}) {
			fmt.Println("button released")
			//消灯
			led.Off()
		})
	}

	//スタート
	robot := gobot.NewRobot("buttonBot",
		[]gobot.Connection{r},
		[]gobot.Device{button, led},
		work,
	)
	robot.Start()
}
```

### 実行

```bash
$ go run led.go
2020/12/20 11:02:18 Initializing connections...
2020/12/20 11:02:18 Initializing connection RaspberryPi-2B0CDE57 ...
2020/12/20 11:02:18 Initializing devices...
2020/12/20 11:02:18 Initializing device Button-649D051A ...
2020/12/20 11:02:18 Initializing device LED-7FCF738D ...
2020/12/20 11:02:18 Robot buttonBot initialized.
2020/12/20 11:02:18 Starting Robot buttonBot ...
2020/12/20 11:02:18 Starting connections...
2020/12/20 11:02:18 Starting connection RaspberryPi-2B0CDE57...
2020/12/20 11:02:18 Starting devices...
2020/12/20 11:02:18 Starting device Button-649D051A on pin 29...
2020/12/20 11:02:18 Starting device LED-7FCF738D on pin 36...
2020/12/20 11:02:18 Starting work...
button pressed
button released
button pressed
button released
button pressed
button released
```

[Ctrl-C]で終了

 - [参考](https://gobot.io/documentation/examples/raspi_button/)

##(2)Rust

RaspberryPiの入出力制御のクレート [rppal](https://docs.rs/rppal/)を使います。

### ソースコード

はじめはランプが0.5sec間隔で点滅している状態になっていて、押しボタンを押すと、ランプの点滅速度が速くなります。

```ini:cargo.toml（抜粋）
･･･（省略）
[dependencies]
rppal = "0.11.3"
```

```rust:src/main.rs
use std::error::Error;
use std::thread;
use std::time::Duration;
use rppal::gpio::Gpio;

// GPIOをBCM番号で指定
const GPIO_LED: u8 = 16;
const GPIO_BTN: u8 = 5;

//メイン
fn main() -> Result<(), Box<dyn Error>> {
    // GPIOの設定・出力
    let mut pin_led = Gpio::new()?.get(GPIO_LED)?.into_output();
    // GPIOの設定・入力
    let pin_btn = Gpio::new()?.get(GPIO_BTN)?.into_input();

    //無限ループ
    loop {
        if pin_btn.is_low() {
            //ボタンを離しているときは0.5sec間隔で点滅
            pin_led.toggle();
            thread::sleep(Duration::from_millis(500));
        } else {
            //ボタンを押しているときは0.1sec間隔で点滅
            pin_led.toggle();
            thread::sleep(Duration::from_millis(100));    
        }       
    }
}
```

### 実行

```bash
$ cargo run
   Compiling led v0.1.0 (/home/pi/gitwork/rust/led)
    Finished dev [unoptimized + debuginfo] target(s) in 1.41s
     Running `target/debug/led`
```

[Ctrl-C]で終了

##(3)Elixir

入出力制御のライブラリ [Elixir Circuits](https://elixir-circuits.github.io/)を使います。

### ソースコード

押しボタンを押すと、ランプが1秒だけ点灯してから消灯します。

```elixir:buttonlamp.ex
defmodule ButtonLamp do
  @moduledoc """
  Documentation for `Button`.
  WebAPI送信とボタン・LEDの連携
  ## Examples
  """

  # 関連するライブラリを読み込み
  use GenServer
  require Logger

  alias Circuits.GPIO
 
  # 定数
  # 押しボタン接続のBCM番号
  @button 5
  # ランプ接続のBCM番号
  @led 16

  @doc """
  GenServer起動
  """
  def start_link() do
    GenServer.start_link(__MODULE__, [])
  end

  @doc """
  初期化の処理
  """
  def init(_) do
    # GPIO入力の初期化（押しボタン用）
    {:ok, button} = GPIO.open(@button, :input, pull_mode: :pullup)
    # 押しボタン入力の割込を許可（押しボタンを押すとhandle_info関数を呼び出し）
    GPIO.set_interrupts(button, :rising)

    # GPIO出力の初期化（ランプ用）
    {:ok, led} = GPIO.open(@led, :output)

    {:ok, %{button: button, led: led}}
  end

  @doc """
  押しボタン入力の割込の処理
  """
  def handle_info({:circuits_gpio, @button, _timestamp, value}, state) do
    IO.puts(" Button On")
    # ランプを点灯
    GPIO.write(state.led, 1)
    # 待機（単位ms）
    Process.sleep(1000)
    # ランプを消灯
    GPIO.write(state.led, 0)

    {:noreply, state}
  end
end
```

mix.exsには、[`circuits_gpio`](https://github.com/elixir-circuits/circuits_gpio)を追記します。

```elixir:mix.exs（抜粋）
･･･（省略）･･･
  defp deps do
    [
      {:dep_from_hexpm, "~> 0.3.0"},    #ここのコメントを外す
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
      {:circuits_gpio, "~> 0.4"}        #ここを追加
    ]
  end
･･･（省略）･･･
```

### 実行

```bash
$ mix deps.get
$ iex -S mix
･･･
iex(1)>  ButtonLamp.start_link
{:ok, #PID<0.289.0>}
 Button On
 Button On
 ･･･
```

[Ctrl-C]二回押し、あるいは[Ctrl-\]で終了。


#4.おわりに

Grove Base HAT経由でRaspberryPiに接続が可能な、産業機器用制御インターフェースを作ってみました。
PLCに取って代わる･･･まではいかないにしても、IT系の方々が気軽にFACTORY系の機器を作れるようになることを願って製作しました。
今後、少しずつ作例を増やしていきますので、お待ちくださいね～