ラダーでシーケンスを正しく組む

## ラダー言語とは

スイッチを入れるとランプが点灯するような回路から、ある条件をトリガとしてデバイスのON/OFFを行うといった制御を比較的簡単に表現できる言語です。スイッチやリレーを組み合わせ、リアルな電気回路で実現していた制御をソフトウェアに置き換えたものなので、工作機械や設備制御の世界では昔からよく使われており、これらの業界今でも（恐らく）主流の方法です。大昔は回路（ロジック）を描いてから言語（ニーモニック）へ脳内変換しながら制御装置（コントローラ）へ入力したものですが、早くから、既に昭和の終わりから平成初期にはGUIでの編集環境が整っており、回路をそのまま制御装置へ入力することができていました。

後述しますが、順次・分岐・反復を正しくプログラムするにはラダー言語の性質をよく理解した上で、セオリーに則った記述が必要になります。この部分は教科書らしいものがなく、先輩からの口頭伝承であったり、実績のあるロジックを読み解く中で身につけていくものでしかありませんでした。最近ではSFC言語やST言語といった、順次・分岐・反復を書きやすい、C言語との親和性が高い方法で制御することが増えてきているのも、セオリーやテクニックを後継者へうまく引き継げないという業界の実情を反映しているのだと思います。

今回の私の投稿では、ラダーでシーケンス制御のロジックを組むための、私なりのセオリーを紹介させていただきます。どんな言語もそうですが、インプットに対するアウトプットを結果オーライ的に処理したロジックは、メンテナンスがひじょうに困難です。プログラミングの手法は人それぞれですが、ロジックの良し悪しは製品がフィールドへ出てから、故障したときの対応や機能変更、追加のときにわかるものです。仕様設計に基づいたフローチャートどおりのロジックを書いておけば、後が楽です。

### ラダーでは電気回路と（ほぼ）イコールのロジックを組めます。

```言語:ふたつのスイッチを同時に押すとランプが点灯する回路（実体配線図）
+----(BATT)----(SWITCH1)----(SWITCH2)----(LAMP)----+
|                                                  |
+--------------------------------------------------+
```

電池、スイッチ、ランプが直接に接続されている回路をイメージしてください。ちょっと表現が貧弱で申し訳ないのですが、2行目と3行目は電池とランプがつながっている感じを表しています。ランプを点灯させる、単純なAND回路です。

```言語:ふたつのスイッチを同時に押すとランプが点灯する回路（ラダー図）
(+)                                               (-)
|                                                   |
|  SWITCH1     SWITCH2                     LAMP     |
+----| |---------| |----------------------(    )----+
|                                                   |
|                                                   |
|                                                   |
```

この図では電池を外に出して、左の母線を電源、右の母線をグラウンドとして表現しています。これがラダー図です。左右の母線の間に回路を描いていくと、それが Ladder（はしご）のように見えることから、ラダー図といいます。スイッチは単純な平行線で表現されます。

```言語:ふたつのスイッチいずれかを押すとランプが点灯する回路（ラダー図）
(+)                                               (-)
|                                                   |
|  SWITCH1                                 LAMP     |
+----| |----+-----------------------------(    )----+
|           |                                       |
|  SWITCH2  |                                       |
+----| |----+                                       |
|                                                   |
```

こちらは、単純なOR回路になります。ラダー図とはつまり、ANDとORの組み合わせという単純なロジックで機器や装置の制御を行うための仕組みということになります。なぜ、このような制御方式が工作機械や設備制御の世界で広く使われているのかというと、やはりリアルな電気回路との親和性が高く、プログラムは解らなくても電気回路なら読めるし配線もできる人の間で広く普及したからでしょう。組込のプログラムならいくらでも組める若い人が多い中、いざこの世界に飛び込むとこんな感じなので、ラダーという言語の特徴やセオリーをぜひ知っていただきたいのです。

### ニーモニックには方言があります。

ラダー図のままではソフトウェアとして扱いにくいので、ニーモニックが存在します。ラダー図は電気回路そのものなので、見てのとおりですが、ニーモニックには制御装置メーカごとに方言があります。

例えば、今の回路をニーモニックで表すと、

```言語:ふたつのスイッチを同時に押すとランプが点灯する回路（ニーモニック）
LOAD  SWITCH1
AND   SWITCH2
OUT   LAMP
END
```

であったり、


```言語:ふたつのスイッチいずれかを押すとランプが点灯する回路（ニーモニック）
READ  SWITCH1
OR    SWITCH2
WRITE LAMP
END
```

だったりします。
ただし、設計からデバッグまでGUIで行うことがほとんどですので、ニーモニックの違いはほとんど意識することはありません。ただ、資産管理やバージョンコントロールを行う上でテキストのニーモニックは便利です。制御装置の専用ソフトウェアにはラダー図とニーモニックの変換機能があります。

### 処理は上から下へ。ただし短時間で繰り返されます。

他の言語と同じように、ラダーも上から下への順番で処理されます。ただ、プログラム単位で、短時間の繰り返し（スキャン）を繰り返しています。ふたつのスイッチを同時に押すとランプが点灯する回路の場合、先頭からENDまでの間を短時間のうちに繰り返すことで、あたかもリアルタイムに反応しているような挙動を示します。短時間、というのは、数μ秒であったり、数ミリ秒であったり、制御装置の仕様とプログラムの長さによります。クイズの早押しボタン、電気回路で組めば不公平はありませんが、ラダーで組むと不公平が生じます。しかしスキャンタイムは、現代の制御装置においては、その不公平を無視できる程度に短時間です。

### ちゃんと意識しないとシーケンス制御を書くことができません。

順次（シーケンス）として考えたとき、他のプログラム言語が先頭から順番に処理していくのに対し、ラダーではそうではない、という点をまず理解する必要があります。一般的なプログラミングにおいて、「順次」は特に意識する必要がほとんどないかと思います。プログラムという概念自体に、「順次」は当たり前のように含まれているからです。
一方、ラダーでプログラムする場合、この「順次」（シーケンス）は意図的に表現してやる必要があります。電気回路はその性質上、あれも、これも、イベントを同時発生させることが可能です。一般的なプログラムにおいて、プログラムの流れは基本的に１本なので、他の流れはあまり意識していないと思いますが、ラダーは次のような制御が繰り返し行われていることを最初に理解する必要があります。

・入力（スイッチ）の状態がどうなっているか、レジスタに取得
・ラダープログラムを処理し、レジスタを操作
・レジスタの状態に基づき、出力（ランプ）を操作

つまり、ラダーが行っているのは中間の処理であって、フローチャートやロジックの流れとは違うんだということを理解できると思います。ただしロジックの書き方次第で、いま、どのロジックが効いているのか、どのシーケンスが流れているのか、明確に表現することは可能です。

### 例題を使って説明します。

```言語:順次動作
|  TRIGGER     CONDITION   PROHIBIT    COMPLETE
+----| |---------| |----+----|/|---------|/|---------(PROCESS1)  00000001
|                       |
|  PROCESS1(KEEP)       |
+----| |----------------+
|
|　FINISH1      PROCESS1
+----| |----+----| |---------------------------------(PROCESS2)  00000011
|           |
|  PROCESS2 |
+----| |----+
|
|　FINISH2      PROCESS2
+----| |----+----| |---------------------------------(PROCESS3)  00000111
|           |
|  PROCESS3 |
+----| |----+
|
|　FINISH3      PROCESS3
+----| |----+----| |---------------------------------(PROCESS4)  00001111
|           |
|  PROCESS4 |
+----| |----+
|
|　FINISH4      PROCESS4
+----| |---------| |---------------------------------(COMPLETE)  00011111
|
|
```

処理1から処理4まで順次動作するロジックです。これが基本になります。右の母線（グラウンド）は省略しています。
スイッチ（接点）の平行線の間に斜線のあるものはB接点（NC接点、常時ONとも言う）、つまり反転を示します。
先ほどの単純なスイッチとランプとは異なり、例えばPROCESS1というのはリレーのコイルと接点を示しており、コイルのONに反応して接点が変化します。この処理がプログラムの1スキャン中で、上から下の順に処理されます。

### ポイント

基本的にコイルはプログラム中に1個だけ。同じアドレス(ラベル)のコイル複数書いてしまった場合、後方のコイルが有効。複数の同じコイルを書くことはダブルコイルといって、禁忌事項。
いっぽう接点は、制御装置のメモリ容量内でいくつでも書ける。

### この回路が何をしているか説明します。

TRIGGER .... 動作トリガ。実際の入力（スイッチ）であったり、プログラム中、他のところで書かれた結果であったり。例えばエンジンのスタートボタン。
CONDITION .... 動作条件。同じく、スイッチであったり、他の処理結果であったり。例えば、パーキングレンジとフットブレーキ。
PROHIBIT .... 禁止または中断条件。これが入っているとロジックの動作を禁止する。例えば、運転手が飲酒している場合にONするとか。
FINISHn .... 各プロセスの終了条件。
COMPLETE .... 完了条件。シーケンス処理が最後まで進んだときにこれでロジックを切る。

右端の数字はレジスタの状態を示しています。LSBがPROCESS1です。

### 大事なことを言います。

先頭の一行目を論理式で書くと
(( TRIGGER and CONTIDION ) or PROCESS1 ) nand PROHIBIT nand COMPLETE
こんな感じかと思います。フローチャートに書くことも容易でしょう。
IF ((( TRIGGER and CONTIDION ) or PROCESS1 ) nand PROHIBIT nand COMPLETE ) THEN PROCESS1=1
ELSE PROCESS1=0
ラダーでは、何も書かなくてもこのIFをひたすら短時間のうちに繰り返しています。

理解していただきたいのは、これは制御のロジックを意味するのではなく、ある時点での状態から結果を得ているだけということです。処理1、その次は処理2、処理3・・・と順次のプログラムを構成する一部でしかありません。

WHILE (( TRIGGER and CONDITION ) nand PROHIBIT nand COMPLETE ) THEN PROCESS1=1
WHILE ( FINISH1 and PROCESS1 ) THEN PROCESS2=1
WHILE ( FINISH2 and PROCESS2 ) THEN PROCESS3=1
WHILE ( FINISH3 and PROCESS3 ) THEN PROCESS4=1
WHILE ( FINISH4 and PROCESS4 ) THEN COMPLETE=1

実際にはこんな書き方しませんが、シーケンス制御のイメージとしてはこんな感じということで書いてみました。この違いを感覚的に理解することができれば、ラダーでシーケンス制御を行うことは、そう難しくはないでしょう。

### 続いて、分岐。

```言語:分岐動作
|  TRIGGER     CONDITION   PROHIBIT    COMPLETE
+----| |---------| |----+----|/|---------|/|---------(PROCESS1)
|                       |
|  PROCESS1(KEEP)       |
+----| |----------------+
|
|  CONDITIONa  CONDITIONb   PROCESS1
+----| |---------|/|----+----| |---------------------(PROCESSa1)
|                       |
|  PROCESSa             |
+----| |----------------+
|
|　CONDITIONb   CONDITIONa   PROCESS1
+----| |---------|/|----+----| |---------------------(PROCESSb1)
|                       |
|  PROCESSb             |
+----| |----------------+
|
|　FINISHa1     PROCESSa1
+----| |----+----| |---------------------------------(PROCESSa2)
|           |
|  PROCESSa2|
+----| |----+
|
|　FINISHa2     PROCESSa2
+----| |----+----| |---------------------------------(COMPLETEa)
|           |
|  COMPLETEa|
+----| |----+
|
|　FINISHb1     PROCESSb1
+----| |----+----| |---------------------------------(PROCESSb2)
|           |
|  PROCESSb2|
+----| |----+
|
|　FINISHb2     PROCESSb2
+----| |----+----| |---------------------------------(COMPLETEb)
|           |
|  COMPLETEb|
+----| |----+
|
|　COMPLETEa
+----| |----+----------------------------------------(COMPLETE)
|           |
|  COMPLETEb|
+----| |----+
|
```

処理aと処理bの排他制御のロジックです。処理a、処理bのいずれかの流れへ進み、それぞれの完了で処理全体を切っています。どんなに複雑な分岐であっても、完了によってロジックを切らない限り、どう流れてきたかを記憶しておくことが大切です。

### 他にもいろいろと説明したいことはあるのですが…

今回、「令和時代の基礎文法最速マスターアドベントカレンダー」参加企画として初めてラダー言語を説明してみましたが、まったく経験のない方への説明としては不十分だったと思います。もしラダーについて、ほんとうに初歩の初歩からやってみたいという方には、三菱電機さんが発行している「初めてのシーケンサ」というチュートリアルをおすすめします。

https://www.mitsubishielectric.com/fa/assist/satellite/data/jy997d41501e.pdf
こちらからダウンロードできます。

お話したいことはまだあるのですが、ここQiitaでどれだけ需要があるのかわからないので、今回の説明はここまでとさせていただき、もしLGTMが伸びるようなら、また何かテーマを考えて、投稿してみたいと思います。

最後までお読みいただきありがとうございました。