OPC UAサーバーがすでにインストールされ、正しく設定されていることを前提とします。サーバーの設定や実際のプラント機器への接続については、本書の対象範囲外です。
SUMOはOPC UAサーバーに2つの方法で接続できます:
dmqclient.pyモジュールを使用してSUMO PythonAPIから重要な点として、SUMOのOPC機能は現時点ではWindowsでのみ利用可能です。GUIによる接続は今後もWindows専用ですが、Pythonによる接続は将来的にLinuxでも利用可能になる可能性があります。
免責事項:
SUMOのOPCダッシュボードは、テストおよび変数マッピング目的のみのものです!
OPC接続機能に最初に触れるのは、SUMOアプリケーションのAdvanced/OPC Dashboardメニューです。
OPC UAサーバーに接続する前に、いくつかの準備が必要です:
sumo.iniファイルで接続を設定する。OPC UAサーバーに以下の新しいデータタグを作成する必要があります:
FastModeMultiplier - リアルタイムシミュレーションを高速化する(デフォルトは0)MasterSumo - Sumoが時刻の提供元であることを指定する(デフォルトはfalseまたは0)SumoContinue - 停止したシミュレーションを継続するためのフラグを指定する(デフォルトはfalseまたは0)次の例では、必要なデータタグの設定方法を示すためにKEPServerEX OPC UAサーバーを使用します。他のOPCサーバー製品を選択することも可能です。
KEPServerEXの設定ツールで、まだ存在しない場合はChannel1という名前の新しいチャネルを追加します。チャネルを作成する際には、プラント機器と互換性のあるいわゆるドライバーを使用できます。この例では、テスト目的に適したSimulatorを選択しました:

図1 - Channel1プロパティ
Channel1の下にSumoControlという名前の新しいデバイスを次のプロパティで追加します:

図2 - SumoControlデバイスのプロパティ
SumoControlデバイスの下に必要なデータタグを追加すると、次のようになります:

図3 - KEPServerEX設定ツールのSUMOデータタグ
通常はユーザーのAppData/Roaming/Dynamita/Sumo24フォルダーにあるsumo.iniファイルに、いくつかのエントリを追加する必要があります(SUMOのインストール方法によって場所は異なる場合があります)。必要なエントリは次の通りです:
OPC_UA_Url = opc.tcp://localhost:49320
OPC_FastModeMultiplier = Channel1.SumoControl.FastModeMultiplier
OPC_MasterSumo = Channel1.SumoControl.MasterSumo
OPC_SumoContinue = Channel1.SumoControl.SumoContinue
OPC_Time = Server.ServerStatus.CurrentTime
OPC_UA_UrlエントリにはOPC UAサーバーのアドレスが含まれています。SUMOはこのアドレスをOPCダッシュボードに入力します。
次の3つのエントリは、前のセクションで紹介したデータタグです。OPC UAサーバー内で異なる構造を使用してもよく、必ずしもこのセットアップに従う必要はありません。ただし、データタグの完全な名前を把握し、sumo.iniに指定する必要があります。
KEPServerEXでは、次の画像のようにデータタグのプロパティのタイトルバーに完全名が表示されます:

図4 - プロパティのタイトルバーにおけるデータタグの完全名
最後のOPC_Timeエントリは、システムの現在時刻を表すデータタグである必要があります。これはほとんどのOPC UAサーバー実装に存在し、Server.ServerStatus.CurrentTimeという名前です。このシステムタグがサーバーにない場合は、Dynamitaにお問い合わせください(support@dynamita.com)。
システム時刻は、SUMOシミュレーションのリアルタイム同期にとって重要です。
sumo.iniの準備が完了したら、SUMOアプリケーションから接続をテストできます。OPCダッシュボードを起動するには、コンパイル済みのプロジェクトが必要です。Tutorial plantの例を開き、AdvancedメニューからOPCダッシュボードを開いてみましょう:

図5 - OPCダッシュボード; ヘルプポップアップを得るためにiアイコンにマウスをホバー
Connectボタンを押すと、指定したアドレスでアクセス可能なOPC UAサーバーに接続できます。接続に成功すると、次の画像のように、サーバー内のすべてのデータタグがダッシュボードの右側に一覧表示されます:

図6 - 指定されたサーバーへの接続が成功した; SUMOアプリケーション専用タグが右側に表示される
Disconnectボタンを押すか、SUMOを閉じることで、OPC UAサーバーとの接続を切断できます。SUMOを閉じると、開いている接続は自動的に切断されます。
OPCサーバーのデータタグに接続する入力パラメータと出力変数のリストを用意する必要があります。
テスト目的では、流入流量を入力パラメータとして、処理水の総リン(total phosphorus)を出力変数として選択できます。お気づきのとおり、SUMOでは入力データをパラメータ、出力データを変数と呼びます。SUMOでは、外部から変更できるのはパラメータ型のデータのみです。
サーバーへの接続をテストすることに加え、ダッシュボードのもう一つの重要な機能は、SUMOとOPC UAサーバーの間にデータマッピングを作成することです。手順は次のとおりです:
Saveボタンを押してマッピングを保存する。マッピングはプロジェクトフォルダーに保存されるため、マッピングの完了後はSUMOプロジェクトも合わせて保存する必要があります。マッピングをプロジェクトフォルダーの外に保存することもできます。その場合、そのマッピングは他のSUMOプロジェクトからも利用できるようになります。デフォルトの動作はプロジェクトフォルダーへの保存です(プロジェクトフォルダーは一時的なものであることに注意してください)。SUMOのシンボルにマッピングしたいパラメータと変数について、OPCサーバー側でデータタグを準備する必要があります。この例では、OPCサーバーにPlant_Q(完全名はChannel2.SumoMapping.Plant_Q)とPlant_TP(完全名はChannel2.SumoMapping.Plant_TP)を用意しました。
Qパラメータ(完全名はSumo__Plant__Influent__param__Q)を入力テーブルにドラッグし、次に右側からPlant_Qを同じ行にドラッグしてみましょう。ダッシュボードが完全名をテーブルに自動入力します。

図7 - Influent/paramノードの下にQが見つかり、SumoMappingの下にPlant_Qがある
次に、TPシンボル(完全名はSumo__Plant__Effluent__TP)を出力テーブルにドラッグし、右側からPlant_TPを同じ行にドラッグしてみましょう。

図8 - Effluentノードの下にTPが見つかり、SumoMappingの下にPlant_TPがある
Saveを押してマッピングを保存し、Hideボタンでダッシュボードを非表示にします。
マッピングが設定できたら、シミュレーションをリアルタイムで実行できます。その条件はOPC UAサーバーに接続されていることです。サーバーから切断すると、シミュレーションはフルスピードで実行されます。繰り返しになりますが、OPCダッシュボードは接続のテストと、SUMOシンボルとOPCデータタグ間のマッピング作成のためのものです。
StopTimeをデフォルトの1日から1分に、DataCommを5秒に変更します。これは、意味のある時間間隔(5s)でデータの変化を確認するために必要であり、またシミュレーションが「いつまでも」実行されず、リアルタイムで1分間だけ実行されるようにするためです。
さらに、入力パラメータのInfluent Qと出力変数のEffluent TPを含む新しいテーブルを追加します。これにより、パラメータ値が実際にOPC UAサーバーから取得され、出力変数がサーバーに書き込まれることをテストできます。

図9 - リアルタイムシミュレーションの結果。OPC UAサーバーで流入流量を18000 m3/dに変更しました
出力TPは、次の図のようにOPC UAサーバーに書き込まれ、サーバーの設定アプリケーション(Toolsメニュー)から起動したQuick Client Toolで確認できます。マッピングファイル内で、処理水QにマッピングされたPlant_Qを変更します。次の画像が示すように、Plant_TPデータタグはSUMOから処理水TPの値へと更新されます:

図10 - OPC UAサーバーのQuick Client Toolでデータタグを更新および確認する
シミュレーションを開始すると、データが5秒ごとに更新され、シミュレーションの実行には1分+5秒かかることが分かります(最後のDataCommを待つためです)。
DTTのPythonモジュールについて詳しく知るには、当社のDTTガイドを参照してください。
SUMO向けのPython開発環境の設定については、当社のガイドを参照してください。
DTTアドオンをインストールすると、SUMOのインストールフォルダーにPythonAPIサブフォルダーが作成され、この例で使用するSUMOモジュールが含まれます。
この例では、MLE-demo.sumoプロジェクトを実行し、OPCダッシュボードで作成したmapping.csvファイルを処理します。マッピングを処理するとは、OPCサーバーから入力パラメータを読み取り、出力変数をOPCサーバーに書き込むことを意味します。
この例では、出力変数をOPCサーバーに書き込むだけで、読み取りは行いません。ソースコードは次の通りです:
import dynamita.dtcontrol as dtcontrol
import dynamita.tool as dtool
import dynamita.dmqclient as DMQ
import time
import os
CURRENT_WORKING_DIR = os.getcwd()
SUMO_PROJECT = os.path.join(CURRENT_WORKING_DIR, "MLE-demo.sumo")
SUMO_STOPTIME = "1minute"
SUMO_DATACOM = "5second"
SUMO_STATE = os.path.join(CURRENT_WORKING_DIR, "sumo_state.xml")
OPC_SERVER_ADDRESS = "opc.tcp://localhost:49320"
OPC_CONFIG = os.path.join(CURRENT_WORKING_DIR, "Sumo.Config.xml")
OPC_MAPPING = os.path.join(CURRENT_WORKING_DIR, "mapping.csv")
TIME_TAG = "_System._Time_Second"
TIME_TICKS = 5
SIM_STEP = TIME_TICKS*dtool.sec
OPC_FREQ : float = 0.1
def sumo_to_opc(dtc):
if dtc.GUI.is_running() :
dtc.GUI.core_command_sync(f'save "{SUMO_STATE}"', "530045")
data = dtool.read_sumocore_xml(SUMO_STATE)
dtc.OPC.write_mapped_variables(dtc.OPCMapping, lambda x: x.io_type == "Dynamic" and x.io == "O", data)
def main():
dtc = dtcontrol.DTControl()
dtc.start_Sumo_GUI(SUMO_PROJECT, SUMO_STOPTIME, SUMO_DATACOM)
dtc.OPC = DMQ.OPCClient(OPC_SERVER_ADDRESS, OPC_CONFIG)
dtc.Tick_OPCTag = TIME_TAG
dtc.Tick_TickToStep = TIME_TICKS
dtc.SimulationStep = SIM_STEP
dtc.Tick_CheckFrequency = OPC_FREQ
dtc.OPCMapping = dtool.read_opc_mapping_csv(f"{OPC_MAPPING}")
dtc.GUI.onstart(f"load \"{SUMO_STATE}\"; maptoic; set Sumo__LimitTime 1;")
dtc.Tasks = [dtcontrol.DTTask(action=sumo_to_opc, starttime=TIME_TICKS, looptime=TIME_TICKS)]
dtc.run()
dtool.log_print("GUI closed")
main()
まず必要なモジュールをインポートします。SUMOのモジュールは次のとおりです:
インポートの後、SUMOモジュールが必要とする定数をいくつか定義します。ほとんどの定数の意味は明快ですが、一部は説明が必要です:
TIME_TAG - OPCサーバーのシステム時刻の秒成分。これはサーバーのシステムデータタグです。TIME_TICKS - シミュレーションを進めるまで待機する秒数。この時間まではシミュレーションは停止しています。SIM_STEP - シミュレーションを進める秒数。この例ではTIME_TICKSと同じです。OPC_FREQ - dtcontrolがOPCサーバーからTIME_TAGをポーリングする間隔(秒単位)この例では、シミュレーションは0sから開始し、dtcontrolは実時間で5秒待機してからシミュレーションをシミュレーション時間の5秒目に進め、続いて10s、15sと進めていきます。
20行目には、後でdtcontrolにタスクとして渡されるコールバック関数があります。これはTIME_TICKごとに呼び出されます。
26行目にはメイン関数があります。その中で、dtcという名前のdtcontrolオブジェクトを作成します。これを使って28行目でGUIを起動し、プロジェクト名、ストップタイム、DataComm間隔を渡します。
29行目ではOPC接続オブジェクトを作成し、サーバーアドレスと構成XMLファイルを渡します。
31〜34行目では定数をdtcontrolに渡します。36行目ではマッピングファイルを読み込み、それをdtcontrolに渡します。
37行目ではGUIへのコアコマンドを指定し、38行目では指定した時間間隔で実行されるタスクを設定します。
最後に、40行目でdtcontrolを起動します。
コールバック関数の22行目では、シミュレーションの状態を保存するために、GUIに同期コアコマンドを送信します(つまり、処理が完了するまで待ちます)。その後、その状態を変数に読み込み、マッピングファイルで指定された出力変数の値を検索するために使用します。
24行目では、出力変数をOPCサーバーに書き込みます。
Pythonスクリプトは、SUMOアプリケーション(GUI)を閉じると停止します。