リモートターミナル RiT


はじめに

MH ソフトウェア&サービスのUDP通信を利用した、リモートターミナルの紹介です。
工場の制御機器や画像センサは、UDP出力に対応してる機器があります。
これらの機器から出力される信号を、リモートで監視できます。

UDPとは

User Datagram Protocolの略で、ウィキペディアより

TCPとは異なり、UDPはコネクションレス型であり、通信相手の応答を待つことなくデータを送り続けるプロトコルである。

TCPとは

Transmission Control Protocolの略です。コネクションします。つまり相手がいないと、エラーとなります。

UDPのメリット

あくまでも自分の感覚ですが、
1. TCPより全体の通信時間が短い
2. 相手がいなくても送信できるため、エラー処理が簡素化できる
3. 簡素化できるため、スマホでも送受信が簡単にできる

リモートターミナルRiT

Pythonを使用して作成されています。Pythonですので、WindowsPCやAndroidスマホで動作します。
もちろんMac環境、iPhone環境でも動くと思いますが、機器を持ち合わせておりませんので、未確認です。
GUIはtkinterです。

Windows Python 3.8.6

Android Pydroid 3 4.01_arm64

Pydroid 3では、アイコンが出ません。タイトルに日本語が使えません。設定があるのかもしれませんが、不明です。
アドバイス頂けますと、幸いです。

Raspberry Pi 4 と Kuman K82

サーマルカメラ(サーモ AI デバイス TiD) 紹介編で紹介しました、Physical Computing Lab / Raspberry Pi4 Model B DIYメタルケースにRaspberry Piを入れて、Kuman K82を差し込んだだけの、シンプルな構成です。

Rootクラス

Form初期化

class Root(mhtk.Form):
    def __init__(self):
        self.__version__ = __version__

        self.root = self
        self.ini = Ini(fullpath=__file__)
        self.LANG = 'ja'

        self.id_name = self.ini.udp.id_name
        self.udp_port = self.ini.udp.port
        self.destination = self.ini.udp.destination

        minsize = (400, 180)
        super().__init__(
            dialog=True,
            font=('system'),
            icon=self.icon_file,
            minsize=minsize,
            name='main',
            position=self.ini.get_geometry(
                self.ini,
                self.ini.config,
                minsize),
            title=(lambda: 'Remote Terminal'
                   if self.LANG == 'en' else 'Remote Terminal')(),
            udp_port=self.udp_port,
            )

        # NOTE: Output Bit. This value is binary.
        self.output = tk.IntVar(value=0)
        self.output.trace('w', self.output_changed)

        self.create_io()

        self.menu = Menu(self)

        self.indicator = Indicator(self)
        self.indicator.pack(anchor=tk.CENTER)

        # NOTE: Logo
        self.logo = mhtk.IconFramePack(self)
        self.logo.pack(anchor=tk.CENTER)

minsizeを指定して、サーマルカメラ(サーモ AI デバイス TiD) Python Form編で紹介しましたFormクラス(form.py)を使用しています。

I/O

create_ioで、GPIO用のクラス(mhrp.gpio)からI/Oを作成しています。

    def create_io(self):
        """
        for K82.
        CH1 GPIO19 PIN35
        CH2 GPIO26 PIN37
        CH3 GPIO20 PIN38
        CH4 GPIO21 PIN40
        ================
        self.force_* value is
            -1: Not forced.
             0: Forced off.
             1: Forced on.
        """
        #self.input_list = [29, 31, 33, 35, 37]
        #self.output_list = [16, 18, 32, 36, 38, 40]

        self.input_list = [11, 13, 16, 18]
        self.force_input = []
        for _ in range(len(self.input_list)):
            self.force_input.append(-1)

        self.output_list = self.ini.config.output_io_list
        self.force_output = []
        for _ in range(len(self.output_list)):
            self.force_output.append(-1)

        self.io = mhrp.gpio.IO(
            'PIN',
            self.input_list,
            self.output_list,
            mhrp.gpio.BOTH,
            )
        self.io.input.bin.trace('w', self.io_callback)

mhrp.gpio -> input/outpu.py -> bit.py

mhrpはMH ソフトウェア&サービスのRaspberry Pi用のライブラリです。
この中には、input/output.pyから各クラスがインスタンス化されます。
さらにinput/output.puは、bit.pyのBitクラスをインスタンス化しています。

bit.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tkinter as tk


class Bit(list):
    def __init__(self, count, callback):
        self._count = count
        self._callback = callback
        for bit in range(count):
            self.append(tk.BooleanVar(value=False))
            self[bit].trace('w', self.BitChanged(bit, self._bit_changed))

    def _bit_changed(self, *args):
        self._callback(*args)

    class BitChanged():
        def __init__(self, index, callback):
            self._index = index
            self._callback = callback

        def __call__(self, *args):
            self._callback(self._index)

Bitクラスはlistを継承しています。
入力・出力の数だけlistにBitChangedをインスタンス化し、追加します。
各BitChangedクラスは、自分が何番目かのindexを持っています。オン/オフが切り替わった場合、callback関数を実行します。

tkinterの trace 最強!

MH ソフトウェア&サービスでのPython GUIは、主にtkinterとなっています。
変数が変わった時に、関数を実行できる.traceがあります。

bit.py内で

self[bit].trace('w', self.BitChanged(bit, self._bit_changed))

があります。

self._bit_changedは、self.BitChanged(bit, self._bit_changed)の部分で、インスタンス化されて、trace属性が付きます。

これはbitが変更された時、self.bit_changedが実行されます。
self._bit_changedはBitChangedクラスで、
call_によりインスタンスを関数の様に実行する事が出来ます。

class BitChanged():
    def __init__(self, index, callback):
        self._index = index
        self._callback = callback

    def __call__(self, *args): # ここが実行されます
        self._callback(self._index)

単純なクラスですが、インスタンス化時に自分のビットとコールバック関数を覚えておいて、ビットが変更になったら、ビットをinput/output.pyへ戻すという感じです。

その他、traceは文字変数でも可能です。


YouTube: リモートターミナル RiT
web: RiT リモートターミナル (URLが変更されました)