0

エンコーダー (QSB を備えた US デジタル S5 光軸エンコーダー) に接続されたシリアル ポートから読み取る各データ エントリに正確な時間 (ms) を必要とするプロジェクトに取り組んでいます。

エンコーダーを小さなカートに取り付け、カートの速度をカウントするために使用しました。

これが私がこれまでにしたことです:

  1. シリアル ポートに接続し、QSB にコマンドを書き込んで、エンコーダーにデータをストリーミングするように指示します。ここで利用可能なコマンド:

    www.usdigital.com/assets/general/QSB%20Commands%20List_1.pdf www.usdigital.com/assets/general/QSB%20Applications%20Examples.pdf

  2. 受信したデータを読み取るには、readline() を使用します。

  3. データのすべての行を 1 つの StringBuilder に入れ、それをファイルに出力します。

出力値のしきい値とインターバル レートをできるだけ速く設定すると、1 ミリ秒の間にデータ エントリを取得できます。これが私が得たものです:

----time stamp(h/m/s/ms)-------value

タイムスタンプが正しいデータ: https://www.dropbox.com/s/pvo1dz56my4o99y/Capture1.JPG

ただし、データが連続している場合は約 200 ミリ秒の突然の「ジャンプ」があります (カートを一定の速度で転がしています)。

タイムスタンプが正しくないデータ: https://www.dropbox.com/s/sz3sxwv4qwsb2cn/Capture2.JPG

これが私のコードです:

private void buttonOpenEncoderPort_Click(object sender, EventArgs e)
    {
        serialPortEncoder.Write("S0E\r\n");//start streaming data
        System.Threading.Thread.Sleep(500);
        serialPortEncoder.Write("W0B0\r\n");//set threshold to 0 so the encoder will stream data a the interval I set.
        System.Threading.Thread.Sleep(500);
        serialPortEncoder.Write("W0C0000\r\n");//set output interval to 0 so it will stream as fast as possible
        System.Threading.Thread.Sleep(1500);
        backgroundWorkerEncoder.RunWorkerAsync();}
        //I am using a background worker to pull data out.


 private void backgroundWorkerEncoder_DoWork(object sender, DoWorkEventArgs e)
    {
        while (serialPortEncoder.IsOpen)
        {
            if (serialPortEncoder.BytesToRead != 0)
            {
                try
                {
                    String s = serialPortEncoder.ReadLine();//read from encoder
                    LazerBucket.Add(getCurrentTimeWithMS(timeEncoder) + "-----" + s + "\r\n");//put one line of data with time stamp in a List<String>
                    richTextBoxEncoderData.BeginInvoke(new MethodInvoker(delegate()
                    {
                        richTextBoxEncoderData.Text = s; })); //update UI

                }
                catch (Exception ex) { MessageBox.Show(ex.ToString()); }                   
            }

        }
    }

private String getCurrentTimeWithMS(DateTime d)//to get time
    {
        StringBuilder s = new StringBuilder();
        d = DateTime.Now;
        int hour = d.Hour;
        int minute = d.Minute;
        int second = d.Second;
        int ms = d.Millisecond;
        s.Append("  ----" + hour.ToString() + ":" + minute.ToString() + ":" + second.ToString() + ":" + ms.ToString());
        return s.ToString();
    }

誰かがタイムジャンプの原因を見つけることができれば、私はそれを歓迎します. 200ms は無視するには多すぎます。

EDIT: 

提案どおり、試してみStopwatchましたが、まだ 200ms の遅延があります。しかし、タイムスタンプと BytesToRead を一緒に出力すると、readLine() が実行されているため、バッファ内のデータが減少していることがわかりました。最終的に BytesToRead は 1 桁に低下し、そこで遅延が発生します。スレッドの実装方法に関するより良い解決策を探しています。遅延の説明も。多分私は速く読んでいるので、バッファが私に追いつくことができませんか?

EDIT:

問題が解決しました。以下の私の答えを見てください。でも返信ありがとう。ストップウォッチは本当に役に立ちます。現在、イベント駆動型とポーリングのどちらが優れているかを調べています。

4

4 に答える 4

3

Web で無限の調査を行った結果、遅延の原因がわかりました。Device Manager --->Port---->advance----> latency を 1ms に変更すると問題が解決します。現在、別のスレッドを使用してデータをポーリングしています。それは非常にうまく機能します。

于 2013-01-15T01:54:03.120 に答える
1

C# 4.5 を使用していますか? もしそうなら、async/ awaitoverを使用することを強くお勧めしBackgroundWorkerます。

また、リアルタイムアプリケーションでDateTimeはあまり正確ではありません。開始時刻として厳密に推奨し、 inを使用して開始時刻からの経過時間を取得することをお勧めします。DateTimeStopwatchSystem.Diagnostics

private void backgroundWorkerEncoder_DoWork(object sender, DoWorkEventArgs e)
{
  var startTime = DateTime.Now;
  var stopwatch = Stopwatch.StartNew();

  while (serialPort.IsOpen && !backgroundWorker.CancellationPending)
  {
    if (serialPort.BytesToRead > 0)
    {
      try
      {
        var line = serialPort.ReadLine();
        var timestamp = (startTime + stopwatch.Elapsed);

        var lineString = string.Format("{0}  ----{1}", 
                                       line,
                                       timestamp.ToString("HH:mm:ss:fff"));

        // Handle formatted line string here.
      }
      catch (Exception ex)
      {
        // Handle exception here.
      }
    }
  }

200 ミリ秒の不一致については、さまざまな可能性があります。おそらく、 のBackgroundWorker優先度が低く、期待したほど多くの CPU 時間が得られない可能性があります。または、実際のシリアル デバイス自体のI/O側にある可能性もあります。SerialPort

于 2013-01-13T23:49:29.880 に答える
0

私には、OSは[あなたの邪魔をしている]ようです。

私は次のことを提案します。

  1. 別のプロセス(またはサービス)または通常よりも優先度の高い別のスレッドでポートからデータを読み取ります

  2. 後で処理できるように、raw(!)データを正確なタイムスタンプとともにキューに格納します。この「タスク」は、GCまたはスケジューラーが開始して、最短時間でも停止しないように、可能な限り軽量にする必要があります。たとえば、文字列の連結やフォーマットはありません。これらの操作には時間がかかり、メモリにストレスがかかります。

  3. そのデータを別のスレッドまたはプロセスで処理します。タイムスタンプが正確であるため、それがしばらくの間保持されても、実際に害はありません。

要するに; 読み取りを処理から切り離します。

WindowsのImoストックバージョンは、RTプロセスにはIOバウンドが多すぎます(スワッピングの概念を愛し、抱きしめています)。差分ボックスで差分OSを使用して、それを読み取り、さらに処理するためにWinboxに送信することも、おそらく検討するオプションになる可能性があります(最後の手段?)

于 2013-01-14T02:01:22.823 に答える
0

正確な測定が必要な場合は、DateTime を使用しないでください。代わりにストップウォッチを試してください。herehereで詳しく説明されているように、DateTime は正確ですが、ミリ秒まで正確ではありません。精度と精度が必要な場合は、測定を開始してストップウォッチからオフセットを取得するときに DateTime.Now を保存します。

200 ミリ秒は長い遅延のように見えますが (DateTime の場合でも)、ストップウォッチが実際に問題を解決する可能性があります。

于 2013-01-13T23:37:26.910 に答える