オートメーションサーバでオートバランスできない

2024-04-17 · Tomoki Ikegami

"キーエンスのオートメーションサーバ機能で、ひずみ測定ユニットのオートバランスをする方法"

オートメーションサーバ機能とは

 キーエンス製データロガーの専用ソフトウェア「WAVE LOGGER X」を、Python, C#, VBAで操作できる機能です(Webアプリケーションで言うところのAPI? みたいな感じです)。WAVE LOGGER X 自体は、マウスでポチポチ操作できるソフトです(綺麗なGUI)。このようにマウスで操作するところを、他のプログラミング言語(Python, C#, VBA)で自動的に操作するのが、オートメーションサーバ機能です。とても便利です(‘ω’)

WAVE LOGGER X の画面はこんな感じ
☝ WAVE LOGGER X の画面はこんな感じ

オートバランスできない…

 キーエンス製データロガー(今回はNR-500を使用)でひずみ計測ユニット(NR-ST04)を使うときは、測定開始前に必ず「オートバランス」(ブリッジ回路のゼロ点補正)をする必要があります。WAVE LOGGER Xを使っているときは、「オートバランス」ボタンをただポチっとするだけでよいのですが、オートメーションサーバ機能ではこれにかなり苦労しました。

 ネット情報がほとんど見当たらなかったので(現状では驚くほど情報が少ない)、今回はその解決方法を共有したいと思います!

 下の画像は(研究室の)実験室にある、キーエンスのNR-500とNR-ST04です。(NR-ST04がなんかたくさんある ← もちろん理由はあります)

一番左がNR-500、右がNR-ST04(×5個)
☝ 一番左がNR-500、右がNR-ST04(×5個)

解決策

 初めにサンプルコード全体を載せます。他のシステムとの統合を考えていたので、コードはPythonで作成しています。

 基本的にはキーエンスのサンプルプログラム(「C:\program files\KEYENCE\WAVE LOGGER X\samples\Automation.zip」に入ってる)と同じ感じですが、オートバランスを自動で行う、測定データを自動保存する処理を追加しています。

 オートバランスの進捗状態を確認してから、次の処理を実行するというのがポイントです。


⇩⇩⇩ ソースコード ⇩⇩⇩
import os   # ファイルパスの取得などに使用
import time # 待ち時間などを制御するために使用
import win32com.client  # Windowsでアプリを操作するためのAPI
from pathlib import Path    # ファイルパスの取得などに使用

# 初期設定
NR500_USB_ID_START = 0
NR500_USB_ID_END = 3
STATE_START_WAIT = 2
STATE_TRIGGER_WAIT = 3
STATE_RUN = 4
STATE_REPEAT_RUN = 5
STATE_PRE_TRIGGER = 6
STATE_POST_TRIGGER = 7
STATE_STOP_WAIT = 8
STATE_READ_WAIT = 10
STATE_PROCEDURE_WAIT = 12
UNIT_NUMBER = 1
GROUP_NUMBER = 0
CHANNEL_NUMBER = 0

# Pythonファイル名収集設定ファイル名、(ロガーのグループ番号を設定
argv = ["python_file_path", "xdt_file_path", "group_number"]
argv[0] = str(Path.cwd()) + r"\logging.py"   # 収集用のプログラムの場所オートメーションサーバのコマンドを使う側のプログラム
argv[1] = str(Path.cwd()) + r"\logger_test.xdt"     #  WAVE LOGGER X の収集設定ファイルの場所上のプログラムと同じ階層
argv[2] = GROUP_NUMBER                              #  グループ番号NR-500の場合は0」)

# パスとグループ番号の表示絶対パスが正しいか確認
print("argv[0]:", argv[0], "argv[1]:", argv[1], "argv[2]:", argv[2])

def main():
    # ファイルのパスを取得
    file_path = argv[1] # 収集設定ファイル名

    # 収集設定ファイルが存在するか確認
    if not os.path.isfile(file_path):
        print("File not exist")
        return
    
    # グループ番号の取得
    id = int(argv[2])

    # WAVE LOGGER X のアプリ起動初期化
    wave_logger = win32com.client.Dispatch("WaveLoggerX.Application")   # WAVE LOGGER X のアプリを起動
    wave_logger.Initialize()    # アプリ初期化
    wave_logger.Visible = True  # TrueにするとWAVE LOGGERの画面が見えるようになるアプリの画面が起動してくる
    
    # 収集設定ファイルを開く
    print("収集設定ファイルを開きます")
    open_result = wave_logger.OpenFile(file_path)   
    # 取集設定ファイルが開けなかった場合はエラーを表示して終了
    if open_result != 0:
        print("File open error [error code: %d]" %open_result)
        return
    
    # 機器IDを取得(※複数の WAVE LOGGER が起動していると取得に失敗するので注意
    print("IDをセット")
    id_result = wave_logger.SetIdentifier(id)       
    # IDの取得に失敗した場合はエラーを表示して終了
    if id_result != 0:
        print("Failed to set the device ID [error code: %d]" %id_result)
        return

    # オートバランス
    print("オートバランス開始")

    # オートバランスの実行3CH分
    AT_BAL_RESULT = wave_logger.AutoBalance(GROUP_NUMBER, UNIT_NUMBER, 0 | 1 | 2)   # 3つめの引数に 0,1,2 は CH1, CH2, CH3 を表す
    AT_BAL_PROGRESS = wave_logger.GetAdjustStatus   # オートバランスの進捗状況を取得

    # オートバランスの進捗状況を表示しながら処理が完了するまで待つ
    while AT_BAL_PROGRESS != 0:
        AT_BAL_PROGRESS = wave_logger.GetAdjustStatus
        print("オートバランス中です... 進捗:", AT_BAL_PROGRESS , "[%]")

    if AT_BAL_RESULT == True:
        print("CH1,2,3のオートバランスに成功しました")
    else :
        print("CH1,2,3のオートバランスに失敗しました")
   
    # 収集開始
    start_result = wave_logger.Start
    print("収集開始")
    if start_result != 0:
        print("Starting acquisition failed [error code: %d]" %start_result)
        return

    document = wave_logger.GetActiveFile    # 起動しているファイルから情報WAVE LOGGER の起動状態収集しているデータ数などを取得
    state = wave_logger.GetState            # WAVE LOGGER の動作状態を取得この数字によって動作状態が分かる詳しくは公式マニュアルを参照
    print("動作状態:", state)               # 動作状態を表示
    
    # 現在のデータサンプル数を取得
    try:
        while is_running(wave_logger.GetState):
            print("\r"+"The amount of sampling data: " + str(document.GetDataCount) + ", Value:"+str(document.GetCurrentData(UNIT_NUMBER,CHANNEL_NUMBER))+
                  " (Press 'Ctrl + C' to stop acquisition)", end="")


    # キーボードからの割り込み入力Ctrl+Cがあったら収集を停止する
    except KeyboardInterrupt:
        wave_logger.Stop()
        while is_running(wave_logger.GetState):
            time.sleep(1)

    # ループを抜けたら測定データをcsv保存
    document.SaveCsvFile( str(Path.cwd()) + "\\sample_data.csv")
    print("測定データを保存しました")

    # データ数収集停止用のメッセージを表示
    print("\r"+"The amount of sampling data: " + str(document.GetDataCount) + 
          " point (Press 'Ctrl + C' to stop acquisition)")
    print("Press Enter to exit")
    input()

# ソフトの起動状態を調べる関数
def is_running(state):
    return state in {STATE_START_WAIT,
                     STATE_TRIGGER_WAIT,
                     STATE_RUN,
                     STATE_REPEAT_RUN,
                     STATE_PRE_TRIGGER,
                     STATE_POST_TRIGGER,
                     STATE_STOP_WAIT,
                     STATE_READ_WAIT,
                     STATE_PROCEDURE_WAIT}

# ヘルプを表示するための関数
def show_help():
    print("<Operation explanation>")
    print("Reads the specified setting file, "
          "confirms the connection, and starts acquisition")
    print()
    print("<How to use>")
    print("$ python Sample1.py <Settings file path> "
          "<Connection identifier> <IP address(option)> <port number(option)>")
    print("    [Settings file path]")
    print("    xcf, xdt, ycf, ydt, kdt File")
    print("    [Connection identifier]")
    print("    0 : NR-500 USB ID0")
    print("    1 : NR-500 USB ID1")
    print("    2 : NR-500 USB ID2")
    print("    3 : NR-500 USB ID3")
    print("    4 : NR-X100 USB ID0")
    print("    5 : NR-X100 USB ID1")
    print("    6 : NR-X100 USB ID2")
    print("    7 : NR-X100 USB ID3")
    print("    8 : NR-X100 LAN ID0")
    print("    9 : NR-X100 LAN ID1")
    print("    10: NR-X100 LAN ID2")
    print("    11: NR-X100 LAN ID3")
    print("    [IP address]")
    print("    IP address of the NRX-100 to be connected")
    print("    Must be specified in the case of "
          "Connection identifier is 8 to 11 (LAN Connection)")
    print()
    print("<Example>")
    print("Sample1.py C:\\NR-500Sample.xdt 0")
    print("Sample1.py C:\\NR-X100Sample.ydt 8 192.168.100.100 24682")
    print


main()

プログラム解説

 上のプログラムの要点を解説します!

モジュールのインポート

 プログラムで使用するいくつかのモジュールをインポートしています。3つめの win32com.client は 「pywin32」 というモジュールで、pipコマンドなどでインストールする必要があります。

import os   # ファイルパスの取得などに使用
import time # 待ち時間などを制御するために使用
import win32com.client  # Windowsでアプリを操作するためのAPI
from pathlib import Path    # ファイルパスの取得などに使用

初期設定

 NR-500の場合は、ほぼこれのコピペでいいと思います。UNIT_NUMBERとCHANNEL_NUMBERは下のイラストみたいに、データを読み出したい測定ユニットの場所や、使用するチャンネルによって変更します。

NR500_USB_ID_START = 0
NR500_USB_ID_END = 3
STATE_START_WAIT = 2
STATE_TRIGGER_WAIT = 3
STATE_RUN = 4
STATE_REPEAT_RUN = 5
STATE_PRE_TRIGGER = 6
STATE_POST_TRIGGER = 7
STATE_STOP_WAIT = 8
STATE_READ_WAIT = 10
STATE_PROCEDURE_WAIT = 12
UNIT_NUMBER = 1             # 測定器ユニットの構成によって変更
GROUP_NUMBER = 0            
CHANNEL_NUMBER = 0          # ユニットの使用チャンネル数に応じて変更
ユニット番号とチャンネル番号の見方
☝ ユニット番号とチャンネル番号の見方

Pythonファイル名、収集設定ファイル名、(ロガーの)グループ番号を設定

 特に argv[1] のところが大事で、WAVE LOGGER X の収集設定ファイルの絶対パスを出しておく必要があります。このプログラムでは、Pythonファイル(logging.py)と同じフォルダに収集設定ファイルを置いておくことで、プログラムを実行できるようにしています。

argv = ["python_file_path", "xdt_file_path", "group_number"]
argv[0] = str(Path.cwd()) + r"\logging.py"   # 収集用のプログラムの場所オートメーションサーバのコマンドを使う側のプログラム
argv[1] = str(Path.cwd()) + r"\logger_test.xdt"     #  WAVE LOGGER X の収集設定ファイルの場所上のプログラムと同じ階層
argv[2] = GROUP_NUMBER                              #  グループ番号NR-500の場合は0」)

WAVE LOGGER X のアプリ起動&初期化

 ここで pywin32を使って、「WAVE LOGGER X」のアプリケーションを起動します。そして、WAVE LOGGERオブジェクトを、「wave_logger」というオブジェクト名で保存して、保存したオブジェクトを使って初期化(Initialize)を行っています。

wave_logger = win32com.client.Dispatch("WaveLoggerX.Application")   # WAVE LOGGER X のアプリを起動
wave_logger.Initialize()    # アプリ初期化
wave_logger.Visible = True  # TrueにするとWAVE LOGGERの画面が見えるようになるアプリの画面が起動してくる

機器IDを取得

 PCに接続されているNRの機器IDを取得します。このときに、複数の WAVE LOGGER が起動していると取得に失敗するので注意してください。

id_result = wave_logger.SetIdentifier(id) 

オートバランス

 中々うまく行かず、一番苦労した処理です(;‘∀’)。ひずみ測定ユニット(今回はST04を使用)を使うときは、測定前に必ず実行します。

 この処理のポイントは下側のwhileループの部分で、進捗が 0 %(100 % から 0 %に変化します)になるまで、次の処理に行かないようにしているところです。進捗の取得には GetAdjustStatus メソッドを使ってます。

 一番上の行の wave_logger.AutoBalanceの一番右側の引数に、オートバランスの対象にしたいチャンネルを or記号「|」 でつなげて書きます。今回は、3軸加速度計(東京測器:ARF-20A-T)の X, Y, Z軸 方向の出力をそれぞれ、CH1, 2, 3(引数に書くときは、0 | 1 | 2 ) に接続しました。

GetAdjustStatus メソッドは、AutoBalance中のチャンネルで最も遅いチャンネルの結果を返します。

今回の機器接続
☝ 今回の機器接続
# オートバランスの実行3CH分
AT_BAL_RESULT = wave_logger.AutoBalance(GROUP_NUMBER, UNIT_NUMBER, 0 | 1 | 2)   # 3つめの引数に 0,1,2 は CH1, CH2, CH3 を表す
AT_BAL_PROGRESS = wave_logger.GetAdjustStatus   # オートバランスの進捗状況を取得
# オートバランスの進捗状況を表示しながら処理が完了するまで待つ
while AT_BAL_PROGRESS != 0:
    AT_BAL_PROGRESS = wave_logger.GetAdjustStatus
    print("オートバランス中です... 進捗:", AT_BAL_PROGRESS , "[%]")

まとめ

 今回は WAVE LOGGER X のオートメーションサーバ機能で、オートバランスを実行する方法について紹介しました。

 少しでも参考になれば幸いです!

サンプルファイル

 この記事で紹介した、オートメーションサーバ機能を使うPythonコード(logging.py)と、NR-ST04の 1~3CH に加速度計(ひずみゲージを3個つないでるのと同じです)の出力を読み取るための収集設定ファイル(logger_test.xdt)です。動作テストや開発のベースにするなど、自由に使っていただければと思います(‘ω’)