ツールの作り方 – 通信基礎編

ツール

今回は実際にPLCと通信するための基本的なことをソースコード(VB)を交えて説明します。
※プログラム言語の基本中の基本については特に説明しません。コードの意味が分からない場合はグーグル先生に聞くと優秀なサイトを教えてくれるハズです。

Ethernet通信の場合

まずはEthernetのTCPで通信する場合の例です。

Imports System.Net
Imports System.Net.Sockets

    Private Sub TestTCP()
        Dim sock As Socket
        Dim tx() As Byte
        Dim rx() As Byte
        Dim rxLen As Integer

        ' 通信回線の接続
        sock = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        sock.Connect("192.168.1.1", 5000)   ' IPアドレスとポート番号

        ' 送信
        ReDim tx(4095)
        ' ※本来はココでプロトコルに応じた送信データを作る
        sock.Send(tx, 100, SocketFlags.None)    ' 送信バイト数を指定

        ' 受信
        ReDim rx(4095)
        rxLen = sock.Receive(rx, SocketFlags.None)
        ' ※本来はココでプロトコルに応じた受信データをチェック

        ' 回線回線の切断
        sock.Close()
        sock = Nothing

    End Sub

次にEthernetのUDPで通信する場合の例です。

Imports System.Net
Imports System.Net.Sockets

    Private Sub TestUDP()
        Dim sock As Socket
        Dim tx() As Byte
        Dim rx() As Byte
        Dim rxLen As Integer

        ' 通信回線の接続
        sock = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
        sock.Bind(New IPEndPoint(0, 0))     ' Bindは基本不要。三菱E71の自動オープンUDPポート以外だと指定が必要な場合がある。
        sock.Connect("192.168.1.1", 5000)   ' UDPはコネクションレス通信なので本来は不要だがConnectしないと送受信はSendTo/ReceiveFromを使う

        ' 送信
        ReDim tx(4095)
        ' ※本来はココでプロトコルに応じた送信データを作る
        sock.Send(tx, 100, SocketFlags.None)    ' 送信バイト数を指定

        ' 受信
        ReDim rx(4095)
        rxLen = sock.Receive(rx, SocketFlags.None)
        ' ※本来はココでプロトコルに応じた受信データをチェック

        ' 回線回線の切断
        sock.Close()
        sock = Nothing

    End Sub
天の声
天の声

実際には接続してから送信→受信を繰り返して最後に切断という流れになります。また例外処理も抜けているので上記をそのまま使ってはいけません。

PLCと通信する際は通常、
 PLC=サーバー
 PC=クライアント
となります。

上記のサンプルでは通信にSocketクラスを使っていますが
 TCPならTCPClientクラス
 UDPならUDPClientクラス
でも可能(なハズ)です。
ただ、、TCP/UDPで別クラスにすると切り替えて使いたい場合にいろいろ面倒なのでSocketクラスを使うほうが無難です。

また当然ですが、ケーブルが抜けていたりIPやポートなどで設定間違いがあると通信が出来ません。これらのミスはありがちですぐ気付きますがTCPの場合は正常にConnect出来ないと自動的に再試行するため失敗となるまで約21秒ブロックされます。(Windowsのデフォルト設定の場合)

あきらかに失敗の原因が分かっていても何も出来ない約21秒は地味に苦痛です。かといってOSの設定を変更するのは愚の骨頂(ブラウザなど他のインターネット通信にも影響が出る)なのでツールの通信プログラム側に工夫すると使い勝手が良くなります。

シリアル通信の場合

今のご時世にあえてシリアル通信でPLCと接続することはほとんど無いと思いますが、20~30年前に作られた装置の調査・解析・改造であればシリアル通信を余儀なくされるかもしれません。
もしくはPLCにシリアル通信のユニット(通常2ポートある)で1つ空いているからなんとかしろ、とか。。(いや、さすがに無いか)

とりあえずシリアルで通信する場合の例です。

Imports System.IO.Ports

    Private Sub TestSerial()
        Dim com As SerialPort   ' コンポーネントのSerialPortをフォームに貼り付けたほうが楽。
        Dim tx() As Byte
        Dim rx() As Byte
        Dim rxLen As Integer

        ' 通信回線を開く
        com = New SerialPort("COM1", 9600, Parity.None, 8, StopBits.One)    ' 通信パラメータはプロパティで変更可
        com.Open()

        ' 送信
        ReDim tx(4095)
        ' ※本来はココでプロトコルに応じた送信データを作る
        com.Write(tx, 0, 100)   ' 送信バイト数を指定

        ' 受信
        ReDim rx(4095)
        rxLen = com.Read(rx, 0, com.BytesToRead)
        ' ※本来はココでプロトコルに応じた受信データをチェック

        ' 回線回線の切断
        com.Close()
        com.Dispose()
        com = Nothing

    End Sub

Ethernetとはクラスとメソッドは違いますが、やるべきことは基本的に同じです。
ただしシリアルの場合は送受信データに俗に”チェックサム”と呼ばれるデータが付加されることが多いです。

ノイズ等の影響により送受信データが正常かどうかをチェックするためのものですが、○○バイト目~△△バイト目までのデータを全て足した値の下位1バイトとする、ようなものが多いです。
たまにデータを足すのではなく排他的論理和(EORとかExORとかXORとか表記されるヤツ)を使うものもあります。(その場合チェックサムではなく別の名称となる)

でも実は名称は違えどEthernetの通信でもこのようなデータは送受信されています。ユーザ側が意識する必要がないだけのことなのですが、私も詳しいことは知りません(笑)
(いくつかのプロトコルが階層的に積み重なったうえにあるのがソケット通信、、程度の理解)
興味のある方は”プロトコルスタック”などをキーワードにグーグル先生に聞くとよいでしょう。

コメント