.NetはデスクトップおよびWebアプリケーションのプログラミングに使用されますが、産業施設の管理にフレームワークを使用することは可能ですか?
そのようなソフトウェアを使用できる最初の部分を調べてみましょう。
産業用制御システムは、いくつかのレベルで構成されています。
- センサーレベル
- 制御レベル(PLC、コンピューター)
- 視覚化レベル/ SCADA
視覚化は、情報処理速度に関して最も控えめなACSレベルです。通常、オペレーターパネルには、システム全体の集約に関する情報(数値、ステータスビット(オン/オフ)、値の変化のグラフ)が表示されます。 このレベルでは、.NETのすべての機能を自由に使用して、グラフィカル情報(Win Forms、WPF、SilverLight)を表示できます。
管理のレベルを考慮してください。 ここで、必要な情報処理速度は制御オブジェクトに依存します。LEDを点滅させるか、厳密な時間参照なしでエンジンをオン/オフしたい場合、これは可能です。 厳密に定義された反応時間でオブジェクトを制御する必要がある場合、リアルタイムシステムを使用する必要があります。
リアルタイムシステムにはリアルタイムOSが必要です。 そのようなOSでは、タスクのコンテキストを切り替える時間、つまり 同じ優先度の各ストリームを処理するためのタイムスライスには同じ割り当てが行われます。
「デスクトップ」OSを使用するとどうなりますか?
Windowsと.Netを使用して達成できる速度を検討したいと思います。 この場合、高パフォーマンスには障害があります。
- 並列実行OSプロセス
- バックグラウンドサービス
- .NETアプリケーションガベージコレクター
- マネージコードの実行時にチェックする
タスクを設定します。WindowsXP + FTDIコントローラーに基づくUSB-COMアダプターを搭載したPCがあります。 アダプターのRTS出力を切り替えて、安定した
蛇行を得ることができる速度はどれ
くらいですか(パルス繰り返し周期を変更せずに)? このようなタスクは、PC上のプログラムで外部デバイスを管理するための最も簡単なオプションです。
プログラムのパフォーマンスをリアルタイムモードに近づけるために、プログラムとワークフローの優先度を上げます。
少しのWindowsタスクスケジューラ理論
合計で32の優先レベルがあります。
- 0システムレベル「ゼロページスレッド」
- 1-15の可変レベル
- 16-31のリアルタイムレベル
優先順位の変化の範囲で、クラスはさらに区別されます:
- アイドル(2-6)
- 通常以下(4-8)
- 通常(6-10)
- 普通より上(8-12)
- 高(11-15)
- リアルタイム(22-26)
各プロセスを作成するとき(CreateProcess())、優先度クラスを設定できます;指定されていない場合、プロセスは標準(レベル8)の優先度クラスを受け取ります。 各プロセススレッドには、優先度レベルを個別に割り当てることができます。 ストリームの最終的な基本的な優先度は、プロセスの優先度のクラスとストリームの優先度のレベルの組み合わせによって計算されます。 スレッドの基本優先度がリアルタイム優先度(レベル16-31)のグループに属している場合、動的に変更されません。そうでない場合、スケジューラーは現在のプロセッサーの負荷とイベント(UI、I / O)に応じてスレッドの優先度をわずかに変更します。
各スレッドが機能する時間の量は、1つのプロセッサを備えたシステムでは10ミリ秒、システムがマルチプロセッサの場合は15ミリ秒です。 また、クォンタムはOSのタイプ(通常またはサーバー(「長いクォンタム」がサーバーで使用される))およびアプリケーションの状態(UIスレッドと、入出力デバイスで動作するスレッドの優先順位は、対応するイベントが発生すると一時的に増加します)に依存します。
この例では、「最も厳しい」オプションを使用します-リアルタイムでプロセス優先度クラスを設定し、ワークフローの優先度を最高に設定します。 この組み合わせのスレッドの基本優先度レベルは24です。この優先度レベルでは、スケジューラはコンテキストを他のスレッドに切り替えないでください(システムプロセス以外に、この優先度を持つ他のスレッドはありません)。
プログラム
using System;
using System.Collections. Generic ;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;
using FTD2XX_NET;
private bool _exitThread;
private Thread _workThreadPort, _workThreadPortUnmanaged, _workThreadDriver;
private List < long > _durationsPort, _durationsPortUnmanaged, _durationsDriver;
public FormMain()
{
InitializeComponent();
//System.Diagnostics.Process.GetCurrentProcess().PriorityClass =
// ProcessPriorityClass.RealTime;
// SerialPort
_workThreadPort= new Thread(()=>
{
SerialPort port = new SerialPort( "COM5" );
port.BaudRate = 115200;
port.StopBits = StopBits.One;
port.Parity = Parity.None;
port.DataBits = 7;
port.Handshake = Handshake.None;
port.Open();
bool flag= false ;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//Thread.CurrentThread.Priority = ThreadPriority.Highest;
while (!_exitThread)
{
_durationsPort.Add(stopwatch.ElapsedMilliseconds);
stopwatch.Reset();
stopwatch.Start();
port.RtsEnable = flag;
flag = !flag;
}
port.Close();
});
// (Win API)
_workThreadPortUnmanaged = new Thread(() =>
{
UnmanagedSerialPort unmanagedSerialPort = new UnmanagedSerialPort( "COM5" );
unmanagedSerialPort.Open();
bool flag= false ;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//Thread.CurrentThread.Priority = ThreadPriority.Highest;
while (!_exitThread)
{
_durationsPortUnmanaged.Add(stopwatch.ElapsedMilliseconds);
stopwatch.Reset();
stopwatch.Start();
if (flag)
{
unmanagedSerialPort.On();
}
else
{
unmanagedSerialPort.Off();
}
flag = !flag;
}
unmanagedSerialPort.Close();
});
// API FTDI
_workThreadDriver= new Thread(()=>
{
FTDI myFtdiDevice = new FTDI();
myFtdiDevice.OpenByIndex(0);
bool flag= false ;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//Thread.CurrentThread.Priority = ThreadPriority.Highest;
while (!_exitThread)
{
FTDI.FT_STATUS ftStatus = myFtdiDevice.SetRTS(flag);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
flag = !flag;
_durationsDriver.Add(stopwatch.ElapsedMilliseconds);
stopwatch.Reset();
stopwatch.Start();
}
}
myFtdiDevice.Close();
});
_durationsDriver = new List < long >();
_durationsPort = new List < long >();
_durationsPortUnmanaged = new List < long >();
}
//
private void b_Save_Click( object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter( "Port.csv" );
_durationsPort.ForEach(l => sw.WriteLine(l));
sw.Close();
sw = new StreamWriter( "Driver.csv" );
_durationsDriver.ForEach(l => sw.WriteLine(l));
sw.Close();
sw = new StreamWriter( "PortUnmanaged.csv" );
_durationsPortUnmanaged.ForEach(l => sw.WriteLine(l));
sw.Close();
}
private void b_RunViaPort_Click( object sender, EventArgs e)
{
_exitThread = false ;
_workThreadPort.Start();
}
private void b_Stop_Click( object sender, EventArgs e)
{
_exitThread = true ;
}
private void b_RunViaPortUnmanaged_Click( object sender, EventArgs e)
{
_exitThread = false ;
_workThreadPortUnmanaged.Start();
}
private void b_RunViaDriver_Click( object sender, EventArgs e)
{
_exitThread = false ;
_workThreadDriver.Start();
}
* This source code was highlighted with Source Code Highlighter .
ポートを操作するための3つのオプションを検討してください。
- クラスSerialPort
- アンマネージコード(Win API:GetCommState、EscapeCommFunction、SetCommState)
- FTDIが提供するライブラリ
いずれの場合も、プログラムサイクルでRTSピンの状態を変更し、1サイクルの時間を検出します。 この時間は、ピンが目的の状態に切り替わる時間に対応します。
テスト条件:各オプションは30秒間チェックされ、10秒後にプロセッサに10秒間追加のアプリケーションがロードされます(WinRar-ハードウェアパフォーマンステスト)。 各オプションは、ストリームの通常の(レベル8)優先度(青色のグラフ)とリアルタイム(レベル24、赤色のグラフ)でチェックされます。
結果
クラスシリアルポート
アンマネージコードとFTDIライブラリ
グラフは、標準のSerialPortクラスを使用する場合、「非標準」ソリューションを使用する場合よりもサイクル時間が約5倍長いことを示しています。 ストリームの優先度を上げると、1サイクルの時間が2ミリ秒に短縮されます。このようなストリームは中断されません。
結論
管理された.netコードを使用してPCから外部デバイスを管理する場合、反応時間は1〜2ミリ秒になります。 フローの優先度を上げることにより、並列プロセスの影響を部分的に減らすことができます。 同時に、他のプロセスを忘れてはならず、可能であれば、コンテキスト(Thread.Sleep(0))を他の待機中のスレッドに手動で切り替えてください。 オブジェクトの合理的な作業による不要なガベージコレクション(GC)呼び出しを避け、正しいアプリケーションアーキテクチャを使用します。これは、プロファイラーまたはシステムパフォーマンスカウンターによってトレースできます。 また、マルチプロセッサシステムでは、異なるスレッドを異なるプロセッサに固定できます(SetThreadAffinityMask()を参照)。
この記事の目的は、別の自転車を作ることではなく、PLCまたはマイクロコントローラーなしでは技術プロセスを制御できないことは明らかです。 .NETの場合、特定の範囲の問題を解決するためのアプリケーションを見つけることができることを示したいと思います。この場合、影響に対するシステムの必要な最小反応時間は2〜15ミリ秒です。
Java Real-Time Systemの例に従って、今後N年間で.NET RTを見てみたいと思います。 有名企業(シーメンス、オムロン)のPLCでの.NET Micro Frameworkの産業用途。
Update1参照資料
C#for Real- time-このトピックについて私をプッシュした記事
Real-Time .NET Frameworkの要件 -この記事では、Java Real-timeとの比較に基づいて.NET RTを実装するために必要な原則について説明します。
JavaでのリアルタイムGC- conscellに感謝Thread.Sleep(0)とThread.Sleep(1)の比較:
ここと
ここ -Frozikと
tangroに感謝