ラダー言語を用いて「大石泉すき」を出力する方法を模索する。

この記事は[「大石泉すき」アドベントカレンダー](https://qiita.com/advent-calendar/2019/ohishi-izumi-suki)24日目の記事です。
他の記事で書かれている多くのいわゆるハードウェア記述言語とは違い、基本的にブール値（真/偽、1/0）のみを扱います。
# ラダー言語とは。
ラダー言語とはプログラマブルロジックコントローラ（PLC）で多く用いられるプログラミング言語で、本来電磁リレーを使用した論理回路を記述するためのものです。
複雑なオートメーションシステムで多数必要になる電磁リレーをプログラム上の仮想電磁リレーに置き換えることで単価を抑え、接点数を増やすことを目的に登場し、本質的には電気回路と同等です。
電磁リレーとは接点を物理的に開閉することで回路のON/OFFを切り替えるための部品で、電気制御機器には必ずと言っていいほど使用されている部品です。
そのため外部装置を動かすことが主な目的で、LCD等の画面を接続すれば大石泉すきと表示することは造作もないことです。（一例として一番最初に紹介します。）
今回はLCD以外の方法をメインに模索しつつ大石泉すきしていきたいと思います。

また、ラダー言語はPLCメーカによってさまざまなツールが提供されており、ほとんどの場合において互換性がない点にはご留意ください。今回は概ね三菱、GX Works2を使用しています。
#### ラダー言語の表記方法について
ラダー言語では並行するレール（母線・左右の縦線）の間に結ばれたラング（横線）の間に接点を配置して回路を構成します。
出力までの回路が真（ON）であれば出力が動作します。
回路には

- a接点（常時偽・OFF）
- b接点（常時真・ON）
- タイマー（オンディレイタイマー、ONになって規定秒数後ON）
- PLS（立ち上がり1stepのみ真・ON）
- PLF（立ち下がり1stepのみ真・ON）
- 論理回路（比較演算子等を用い条件が真であれば真・ON）

などがあります。
出力にはリレーや関数書き換え実行、PLCに実際に接続されている装置等を置くことができます。
今回は

``` cpp:a接点,b接点,PLS,PLF,出力
 |    a     b    PLS   PLF                                      |
0|---] [---]\[---]↑[---]↓[------------------------------(   )---|
 |------------------------------------------------------[END  ]-|
```
と表記することとします。（本来の表記ではb接点の斜線は逆向き|/|です。）

#### 記述例
単純な回路を例示すると

``` cpp:例1
 |   X0                                                         |
0|---] [------------------------------------------------( Y0  )-|
2|------------------------------------------------------[END  ]-|
```
のように記述され、入力a接点X0（押しボタン等）がONしている間のみY0が動作する回路となります。

``` cpp:例2
 |   X0       X1                                                |
0|---] [--+---]\[---------------------------------------( M0  )-|
 |   M0   |                                                     |
 |---] [--+                                                     |
4|------------------------------------------------------[END  ]-|
```
この例では、入力a接点X0がONになると常時ONのX1もONなのでラダー内の仮想電磁リレーM0が動作し、a接点M0がONとなります。その結果、入力X0がOFFとなってもa接点M0がONになっているので電磁リレーM0が動作し続けます。また、b接点X1が回路上にあるのでX1が動作するとX1はOFFとなるのでM0は動作を停止します。

また、カウンターやタイマー、レジスタ等の機能もあり特に論理回路を構成する際にはレジスタに数値を格納して比較することがよくあります。

こうした電気回路に似たラダー言語を用いて今回大石泉すきを表示する方法を模索します。
# LCDに大石泉すきと表示する。

```cpp:画面遷移
 |    B0                                                        |
0|---] [------------------------------------------[MOV K1 D1]---|
# ボタン1　　　　　　　D1(ポップアップウィンドウ)に1ページ目を表示させる。
3|-----------------------------------------------------[END   ]-|   
```

入力全てが真（今回はボタン1が押されているとき）であれば出力（今回はMOVE関数[MOV K1 D1]）が動きます。
D1はデータレジスタで、内部に実数を格納できます。
LCD側でポップアップウィンドウのレジスタをd1とします。
K1は実数1を意味し、move関数が動くとK1をD1に移動させD1の格納値が1となります。

対応する画面デザインソフト（三菱の場合GX WORKS3）で画面デザインを行うので、ラダー言語として書き入れるプログラムはボタン1（B0）が一度押されればD1の実数が1となり1のページを呼び出しポップアップウィンドウとして表示する、という単純なものとなります。

ただ、これだけでは外部デザインに頼りきりなのでラダー言語が主体となる出力方法を考えましょう。

# ラダー言語で出力できるもの
ラダーの出力は元がリレーであることから非常に豊富であり、主にモーター、シリンダ、リレー、ソレノイド等様々な構成を取ることができます。
しかし今回は画面を用いず可能な限り簡素で文章伝達に適したものを選びたいのでまずは発光信号、すなわちモールスで出力してみましょう。

# モールス版大石泉すき

モールス信号は短点と長点の比率が1:3だそうなのでこれに倣い短点を0.5秒、長点を1.5秒としましょう。
また、各点の間隔は短点1つ分、文字と文字の間は短点3つ分です。
PLCではタイマーの時間が0.1秒基準なのでK5,K15,K5,K15となります。
和文での「大石泉すき」は

```
オ　・－・・・
オ　・－・・・
イ　・－
シ　－－・－・
イ　・－
ズ　－－－・－　・・　 #ス+゛
ミ　・・－・－
ス　－－－・－
キ　－・－・・
```
となります。
このうち、オとイ、濁点の有無を除けばスの3文字は同じ符号ですので同一化できます。
今回は短点を打つ時、長点を打つ時をそれぞれ今までの文字数と打った回数でパターン分けして順番に短点、長点、短点、短点、短点…のように組み合わせていきたいと思います。

### 実回路

```cpp:モールス版大石泉すき
   |   X0       M100                                                |
  0|---] [--+---]\[--------------------------------------( M0 )-----|
   |   M0   |                                                       |
   |---] [--+                                                       |
   |                                                                |
   |   M6                                                           |
  4|---] [--+--------------------------------------------( m100 )---|
   |        |                                                       |
   |        +--------------------------------------------[ RST D0 ]-|
   |        |                                                       |
   |        +--------------------------------------------[ RST D1 ]-|
   |        |                                                       |
   |        +--------------------------------------------[ RST D2 ]-|
   |   M3                                                           |
 12|---]↑[--+--------------------------------------------( M1 )-----|
   |   M4   |                                                       |
   |---]↑[--+                                                       |
   |                                                                |
   |   M1    M2       T1       T3                                   |
 15|---] [---]\[--+---]\[------]\[--+--------------------( M2 )-----|
   |   M1    M2   |                 |   M5                          |
   |---]\[---] [--+                 +---]\[--------------( T1 K5 )--|
   |                                |   M5                          |
   |                                +---] [--------------( T3 K15 )-|
   |                                                                |
   |   M0    M2                                                     |
 35|---] [---]\[-----------------------------------------( Y1 )-----|
   |                                                                |
   |   T0                                                           |
 38|---] [--+--------------------------------------------( M3 )-----|
   |        |                                                       |
   |        +--------------------------------------------[ INCP D0 ]|
   |                                                                |
   |   T2                                                           |
 42|---] [--+--------------------------------------------( M4 )-----|
   |        |                                                       |
   |        +--------------------------------------------[ INCP D1 ]|
   |                                                                |
   |   M0                                           M2              |
 46|---] [--+[= D2 K0 ]-+-[= D0 K0 ]---[= D1 K0 ]-+-]\[--( T0 K5 )--|
   |        |           |                         |                 |
   |        +[= D2 K1 ]-+-[= D0 K1 ]---[= D1 K1 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K2 ]---[= D0 K1 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K3 ]---[= D0 K1 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K2 ]-+-[= D0 K0 ]---[= D0 K0 ]-+                 |
   |        |           |                         |                 |
   |        +[= D2 K4 ]-+                         |                 |
   |        |                                     |                 |
   |        +[= D2 K5 ]-+-[= D0 K0 ]---[= D1 K3 ]-+                 |
   |        |           |                         |                 |
   |        +[= D2 K7 ]-+-[= D0 K1 ]---[= D1 K4 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K2 ]---[= D1 K4 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K6 ]-+-[= D0 K0 ]---[= D1 K0 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K1 ]---[= D1 K0 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K2 }---[= D1 K1 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K8 ]-+-[= D0 K0 ]---[= D1 K1 ]-+                 |
   |                    |                         |                 |
   |                    +-[= D0 K1 ]---[= D1 K2 ]-+                 |
   |                    |                         |                 |
   |                    +-[= D0 K2 ]---[= D1 K2 ]-+                 |
   |                                                                |
   |   M0                                           M2              |
196|---] [--+[= D2 K0 ]-+-[= D0 K1 ]---[= D1 K0 ]-+-]\[--( T1 K15 )-|
   |        |           |                         |                 |
   |        +[= D2 K1 ]-+                         |                 |
   |        |                                     |                 |
   |        +[= D2 K2 ]-+-[= D0 K1 ]---[= D1 K0 ]-+                 |
   |        |           |                         |                 |
   |        +[= D2 K4 ]-+                         |                 |
   |        |                                     |                 |
   |        +[= D2 K3 ]-+-[= D0 K0 ]---[= D1 K0 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K0 ]---[= D1 K1 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K1 ]---[= D1 K2 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K5 ]-+-[= D0 K0 ]---[= D1 K0 ]-+                 |
   |        |           |                         |                 |
   |        +[= D2 K7 ]-+-[= D0 K0 ]---[= D1 K1 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K0 ]---[= D1 K2 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K1 ]---[= D1 K3 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K6 ]-+-[= D0 K2 ]---[= D1 K0 ]-+                 |
   |        |           |                         |                 |
   |        |           +-[= D0 K3 ]---[= D1 K0 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K8 ]-+-[= D0 K0 ]---[= D1 K0 ]-+                 |
   |                    |                         |                 |
   |                    +-[= D0 K1 ]---[= D1 K1 ]-+                 |
   |                                                                |
   |   M0                                                           |
324|---] [--+[= D2 K0 ]-+-[= D0 K4 ]---[= D1 K1 ]-+------( M5 )-----|
   |        |           |                         |                 |
   |        +[= D2 K1 ]-+                         |                 |
   |        |                                     |                 |
   |        +[= D2 K2 ]-+-[= D0 K1 ]---[= D1 K1 ]-+                 |
   |        |           |                         |                 |
   |        +[= D2 K4 ]-+                         |                 |
   |        |                                     |                 |
   |        +[= D2 K3 ]---[= D0 K2 ]---[= D1 K3 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K5 ]---[= D0 K3 ]---[= D1 K4 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K6 ]---[= D0 K3 ]---[= D1 K2 ]-+                 |
   |        |                                     |                 |
   |        +[= D2 K7 ]---[= D0 K1 ]---[= D1 K4 ]-+                 |
   |        |                                                       |
   |        +[= D2 K8 ]---[= D0 K3 ]---[= D1 K2 ]--------( M6 )-----|
   |                                                                |
   |   M5    T3                                                     |
404|---] [---]↑[--+--------------------------------------[ INCP D2 ]|
   |              |                                                 |
   |              +--------------------------------------[ RST D0 ]-|
   |              |                                                 |
   |              +--------------------------------------[ RST D1 ]-|
   |                                                                |
412|--------------------------------------------------------[END  ]-|

```
### 回路の解説

##### Step0~4：動作の開始と停止

Step0の回路は自己保持回路となっています。モールスを打つ間、入力が入ったことを記憶し保持するための回路です。
Step4の回路は終了時の処理です。最後にあるM6が動作すると使用したレジスタにリセットをかけ、停止用リレーであるM100が動作します。

##### Step12~42：出力Y1の実働回路

Step12～35の回路が実際に外部に動作を及ぼすためのメイン回路になります。今回は基本的に常時動作とし、動作を阻害するタイミングをM2に与えています。
Step12～15はJK-Flip-Flop回路となっています。この回路はM1が動作するたびにONとOFFが切り替わり、その入力を保持し続けます。また、動作すると同時に文字間時間として設定されているT1がカウントを開始し、0.5秒後の動作したタイミングでY1への阻害を終了し再びY1は点灯へと戻ります。
1文字ごとの区切りは1.5秒後ですので、1文字が終了したタイミングか否かをM5のON/OFFで切り替え、T3への条件分岐としています。

Step38とStep42の回路は以降の条件分岐で動作したタイマーを検知しFlip-Flopを動作させるM3,M4を動作させると同時に、D0,D1にそれぞれ短点、長点を点灯させたことをレジスタに記憶させます。INCPはINCREMENT PLSの略でidol++でおなじみ1加算の意です。

##### Step46~404：条件分岐

Step46,196の回路はそれぞれ短点、長点の動作判定です。何文字目か、短点を何回打ったか、長点を何回打ったか、その組み合わせによってT0かT2、動作すべき方を動作させるようになっています。また、消灯中にカウントを開始しては正しい点灯時間が確保できないのでタイマーの動作にはM2の阻害がY1同様に働くよう設定します。
Step404の回路は文字ごとの終了検知になっています。既定の短点数、長点数に達したら文字数加算、短点長点のリセットによって1文字の終了動作を行い、最後の文字の終了判定が動作すると先頭のStep4の回路のM6に伝わり全体の動作を終了させます。

####動作

今回外部媒体がないなので内部シミュレーションの様子です。
![ohishiizumisuki (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535995/b5e61f41-4658-2e9f-df9e-a57644ae1783.gif)

#後記
ネタ被りしないだろうということで多少経験のあるラダー言語をチョイスしましたが想定以上の縦長回路となり、また初めての記事ということもあり読みづらい箇所が多分にあるかと思います。~~あと純粋に使えそうな場面がない。~~
とはいえ、ひとまず大石泉すきできたことに一安心と、大いに満足しています。
皆様も是非さまざまな形式で大石泉すきしていただければ幸いです。