TwinCAT内部のシステム時計#

IPC上には、マザーボード上にボタン電池とクロック回路があり、これによってReal Time Clock 略して RTCと呼ばれるハードウェア上の時計があります。ここから、Windows等のOS用の時計、TwinCAT内部の時計、そしてEtherCATのDistributed clock用の時計を個別に3つのソフトウェア時計が生成されます。

参考InfoSys

TwinCAT time sources

これらのソフトウェア時計は、次の通り初期化時に同期されて以後、CPUの割り込みタイマを基に時刻計測を行います。基本的にCPUの割り込みタイマは単一の発振子によるクロックを基にカウントを行っていますので、個別の時計であっても差が生まれる訳ではありません。しかし、次の要因により差が生まれます。

OSの機能によるシステム時刻の変更

WindowsやLinux等は、OSの機能として時刻調整機能を持ちます。また、NTP(Network Time Protocol)を用いてインターネット時刻と自動的に時刻合わせすることもできます。CPUクロックによる時刻カウントでは温度等の影響で誤差が生じますが、これらの手段により時刻合わせする事で常に正しい時刻に合わせることが可能です。対してTwinCATやEthernet DCクロックは、その時刻を用いた制御を行う必要がありますので、標準時刻への追従性や正確性よりも、RUNモードに移行後の時刻連続性が重要視されます。したがって自動的に補正される事はありません。

RTCの時刻変更

Windowsは、OSのシステム時刻を変更すると、自動的にBIOSに働きかけてRTCの時刻も変更します。(レジストリで無効化することは可能ですがデフォルト有効です)また、Windowsの由来がデスクトップ向けOSであるように、UTC(世界標準時)ではなくローカルタイムとしてRTCに反映されます。Linuxの場合は次のコマンドを入力しなければOS上のシステム時刻をRTCへ自動反映させることはありません。

# hwclock --systohc --utc(local)

また、デフォルトでRTCはUTCとして解釈するため、クラウド等のようにコンピュータの設置場所に依存せず時刻設定することが可能です。代わりにこのコンピュート機能ををユースポイントにおいて、ローカルタイムへの変換を行うことが求められます。

このようにOSがRTCを書き換えることによって、TwinCAT内部のシステム時計やEtherCAT DC時計がRTCとの間においても差が発生します。

TwinCAT内部のシステム時計の仕様#

TwinCAT time sourcesの “TwinCAT/TC time” 列に記載されている通り、次の通り動作し、参照することができます。

  • CONFIGモードからRUNモードへ移行する際に、Windowsのシステム時計(NTファイルタイム)と同期してシステム時計が初期化されます。

  • RUNモード移行後は、現在動作しているPLCタスクのCPUコアのベースタイム割り込みを用いて時刻カウントを続けます。この時刻は、F_GetSystemTime()ファンクションにより取得することができます。

  • TwinCATシステム時計の精度は 100\(ns\)です。ただし、カウンタはCPUコアのベースタイム割り込みを利用していますので、カウンタのステップはPLCタスクが動作しているCPUコアのBase time設定に依存します。

OSと同期した時刻をPLCに読み出すには#

PLC内部で時刻を管理し、これらを基にIoTやイベント管理機構における時刻情報はどのように生成すれば良いでしょうか。先述のとおりTwinCATのシステム時刻はCPUクロックのみに頼り、OSの時刻は自動調整されたもので稼働時間が長くなればなるほど両者の間に差が生じます。とはいえ、この差を埋めるために、RUN中にTwinCATのシステム時刻を変更するのはタイミング同期に時刻を使う処理に影響が出ますので行ってはいけません。(というよりもこれを実現する機能は提供されていません。)

このため、TwinCATシステム時刻には影響を与えず、アプリケーション上でOS時刻を取り出して活用するためのいくつかのファンクションやファンクションブロックが用意されています。

たとえばイベントロガーとアラーム管理の仕組みを用いる場合、TwinCATの制御上で発生した各種アラームの発生、解除時刻は、IoTやデータベースと連携するためWindowsやLinux等のOS上の時刻を取り出してその時刻でイベントが発生したことを記録する必要があります。次節ではイベントロガーによるアラーム発報、確認、解除を例にその使い方を説明します。

イベントロガーの3つのイベント記録メソッド#

イベントロガーのうちアラームを管理するFB_TcAlarmファンクションブロックには、アラームの発生を通知するRaise()メソッド、確認したことを通知するConfirm()メソッド、解除するClear()メソッドが用意されています。それぞれのメソッドには引数のnTimeStampがあり、TwinCATシステムタイムの形式であるT_FILETIME64型の 64bit 符号なし整数でイベント発生時刻を設定します。

Tip

T_FILETIME64型 は ULINT型 の別名となっていますので、各イベントのメソッドの現在時刻引数が求めるULINT型のシステム時刻を代入可能です。

この引数が0設定の場合は、F_GetSystemTime()ファンクションにより取得した値と同じ値として記録されます。

このままではWindowsやLinux側の時刻とズレのある時刻でイベント記録されますので、次の処理によってWindowsのシステム時刻を明示的に引数へ与える必要があります。

  1. OS時刻を収集

    FB_LocalSystemTimeファンクションブロックにより、IPCのOS時刻を収集します。このファンクションブロックの実行中は、設定したサイクル(デフォルト設定5秒)毎にOS側のシステム時刻を周期的に反映します。取り出した時刻はTwinCAT上のTIMESTRUCT型変数上に展開します。

  2. UTCに変換する

    Windowsの場合内部システム時刻はローカルタイムとなっています。ここからTwinCATシステム時刻の仕様であるUTCに変換する必要があります。まず、FB_GetTimeZoneInformationファンクションブロックにより、現在動作しているWindowsのタイムゾーン設定をST_TimeZoneInformation型変数で取り出します。 このタイムゾーン情報と、FB_LocalSystemTimeで取り出したOSのローカル現在時刻を、FB_TzSpecificLocalTimeToSystemTimeファンクションブロックによってUTC(世界標準時)に変換したTIMESTRUCT型変数を取り出します。

  3. TIMESTRUCT型をT_FILETIME64型へ変換する

    TwinCATシステム時刻の形式であるT_FILETIME64型へ変換するため、SYSTEMTIME_TO_FILETIME64ファンクションを用います。これをFB_TcAlarmの各イベントメソッドの引数に用います。

注釈

Linuxの場合はRTCおよび内部システム時計はUTCです。この場合手順 2 のローカルタイムからUTCへの変換処理は不要です。

以下にプログラム例を示します。//Alarm処理行までのcurrent_timeを取得するプログラムはPLCの全体で一つで構いません。最短周期のPLCタスクサイクル上で常時実行してください。これにより取り出したcurrent_timeをアラームの各種イベント時刻として指定します。

PROGRAM MAIN

VAR
    fbGetTimeZoneInformation    : FB_GetTimeZoneInformation := (bExecute := TRUE);
    localTime                   : FB_LocalSystemTime := (bEnable := TRUE);
    tzinfo                      : FB_GetTimeZoneInformation := (bExecute := TRUE);
    getSystemtime               : FB_TzSpecificLocalTimeToSystemTime;
    current_time                : T_FILETIME64; // TwinCATシステム時刻形式での現在時刻

    // Alarm
    fbSomeAlarm                 : FB_TcAlarm;
END_VAR

// OS現在時刻の取得。bExecuteがTRUEであれば、RUN以後デフォルト5秒おきにWindowsのシステム時刻を取得して systemTime へセットする。
localTime();
// 現在のOSのタイムゾーン情報を収集する。
tzinfo();
// OSの現在時刻からUTCであるシステムタイムへ変換が行われる。
getSystemtime(in := localTime.systemTime, tzInfo := tzinfo.tzInfo);
// T_FILETIME64形式へ変換
current_time := SYSTEMTIME_TO_FILETIME64(getSystemtime.out);

// Alarm処理

IF <<アラーム発生要因>> THEN
    fbSomeAlarm.Raise(current_time);  // アラーム発生時刻をOSの時刻として記録
END_IF

IF <<アラーム確認動作>> THEN
    fbSomeAlarm.Confirm(current_time);  // アラーム確認時刻をOSの時刻として記録
END_IF


IF NOT  <<アラーム発生要因>> 
    AND  <<アラーム解除操作>> THEN
    fbSomeAlarm.Clear(current_time, TRUE);  // アラーム解除時刻をOSの時刻として記録
END_IF

警告

コード例には記載していませんが、Event loggerにてFB_TcAlarmを使用可能にするには、事前にCreate()メソッドにてTMCエディタで登録したイベントクラスの各イベントの何れかと関連付けておく活性化処理が必要です。