2017-05-10 9 views
0

私は現在、センサーからデータを取得するために10msごとに呼び出される関数を用意しようとしています。Python、Raspberry pi、正確に10ミリ秒のタスクを呼び出す

私はgpio interuptからコールバックをtriggringしていましたが、センサーを変更しました。私が現在使っているコールバックにはINTピンがありません。

私の目標は、タイマーによって生成された内部的な干渉で同じ動作をすることです。

私はこの topic

import threading 

def work(): 
    threading.Timer(0.25, work).start() 
    print(time.time()) 
    print "stackoverflow" 

work() 

からこれを試してみました。しかし、私はそれを実行したとき、私はタイマーが本当に正確ではない、それはあなたが見ることができるように時間をかけてderivatingだことがわかります。

1494418413.1584847 
stackoverflow 
1494418413.1686869 
stackoverflow 
1494418413.1788757 
stackoverflow 
1494418413.1890721 
stackoverflow 
1494418413.1992736 
stackoverflow 
1494418413.2094712 
stackoverflow 
1494418413.2196639 
stackoverflow 
1494418413.2298684 
stackoverflow 
1494418413.2400634 
stackoverflow 
1494418413.2502584 
stackoverflow 
1494418413.2604961 
stackoverflow 
1494418413.270702 
stackoverflow 
1494418413.2808678 
stackoverflow 
1494418413.2910736 
stackoverflow 
1494418413.301277 
stackoverflow 

したがって、タイマーは10ミリ秒ごとに0.2ミリ秒で微分されます。これは、数秒後にはかなり大きな偏りです。

私が知っているのは、実際には「リアルタイム」のために作られたものではありませんが、それを行う方法があるはずです。

誰かが既にpythonで時間制限を処理しなければならない場合は、私はいくつかのアドバイスを持ってうれしいです。

ありがとうございました。

+0

タイマー自体の時間と印刷を許可していないため、漂っています。実際の時間と次の10msが経過する時間の差に基づいてタイマーを設定すると、タイミングがずれなくなります。たとえば、ループを開始する前の時間を取得し、ターゲットを10ms単位で増分して維持し、タイマーを(target-currenttime)の期間開始し、タイマーが満了するとターゲットに10msを追加して再び開始します。ジッタが許容できるかどうかを自分で確認する必要があります。つまり、使用シナリオ全体で平均とピークを測定してください。 – barny

+0

答えがありがとう、私はタイマーのスケジューリングの時間を測定していませんが、そのようなドリフト。 私のポイントは、この10msのために非常に正確でありたいと思っています。この方法の問題は、私がいつもタイマーのスケジュールからドリフトすることです。 – Arkaik

+0

これを冒頭に一度だけ定義し、期限切れ後に再び自動的にタイマーを開始させる方法はありますか? – Arkaik

答えて

0

このコードは私のラップトップで動作します。目標と実際の時間の差分を記録します。主なものはwork()関数で何が行われたかを最小限にすることです。印刷とスクロールの画面に時間がかかることがあります。

重要なことは、その呼び出しが行われた時刻とターゲットとの差に基づいて次のタイマーを開始することです。

私は私のwin7のx64の上thteタイマー()の呼び出しに負の値を渡すことで問題を引き起こす10msのを超えることができ、ジッタを見ることが容易である0.1秒に間隔を鈍化:

-oこれにより100個のサンプルが記録され、印刷されます.CSVファイルにリダイレクトするとExcelに読み込んでグラフを表示できます。

from multiprocessing import Queue 
import threading 
import time 

# this accumulates record of the difference between the target and actual times 
actualdeltas = [] 

INTERVAL = 0.1 

def work(queue, target): 
    # first thing to do is record the jitter - the difference between target and actual time 
    actualdeltas.append(time.clock()-target+INTERVAL) 
# t0 = time.clock() 
# print("Current time\t" + str(time.clock())) 
# print("Target\t" + str(target)) 
# print("Delay\t" + str(target - time.clock())) 
# print() 
# t0 = time.clock() 
    if len(actualdeltas) > 100: 
     # print the accumulated deltas then exit 
     for d in actualdeltas: 
      print d 
     return 
    threading.Timer(target - time.clock(), work, [queue, target+INTERVAL]).start() 

myQueue = Queue() 

target = time.clock() + INTERVAL 
work(myQueue, target) 

PythonでWindowsのミリ秒のタイミングに頼ってはいけません):

0.00947008617187 
0.0029628920052 
0.0121824719378 
0.00582923077099 
0.00131316206917 
0.0105631524709 
0.00437298744466 
-0.000251418553351 
0.00897956530515 
0.0028528821332 
0.0118192949105 
0.00546301269675 
0.0145723546788 
0.00910063698529 
+0

こんにちは@barny、最後に私の問題はtime.clock()の使用でした。私はその長い^^にロックされたままにできる。あなたの情報については、私のアプリケーションに最適な最後のraspbian-liteを使用した私のラズベリー・パイのドリフトと平均ジッタは200です。ご助力ありがとうございます ;) – Arkaik

0

私はあなたの解決策を試しましたが、私は奇妙な結果を得ました。ここで

は私のコードです:

from multiprocessing import Queue 
import threading 
import time 

def work(queue, target): 
    t0 = time.clock() 
    print("Target\t" + str(target)) 
    print("Current time\t" + str(t0)) 
    print("Delay\t" + str(target - t0)) 
    print() 
    threading.Timer(target - t0, work, [queue, target+0.01]).start() 

myQueue = Queue() 

target = time.clock() + 0.01 
work(myQueue, target) 

そしてここでは、出力

Target 0.054099 
Current time 0.044101 
Delay 0.009998 

Target 0.064099 
Current time 0.045622 
Delay 0.018477 

Target 0.074099 
Current time 0.046161 
Delay 0.027937999999999998 

Target 0.084099 
Current time 0.0465 
Delay 0.037598999999999994 

Target 0.09409899999999999 
Current time 0.046877 
Delay 0.047221999999999986 

Target 0.10409899999999998 
Current time 0.047211 
Delay 0.05688799999999998 

Target 0.11409899999999998 
Current time 0.047606 
Delay 0.06649299999999997 

だから我々は、ターゲットは10ミリ秒ごとに増加し、最初のループのためにされていることをタイマーの遅延を見ることができています良いと思われる。

ポイントではなく、CURRENT_TIME +で再び始まるのではなく0.01000

の0.001521の遅延を表す0.045622で再起動遅延され、私は何かを逃しましたか?私のコードはあなたのロジックに従っているようですね?

+0

タイマーを開始する直前にt0を設定するか、タイマーコールの現在の時間、つまりthreading.Timer(target-time.clock )、...) – barny

+0

数字の文字列への変換、印刷、画面のスクロールなどは、work()関数の所要時間に影響します。デルタを(1)に増やして、基本原理が機能するかどうかを確認してから、work()関数で行うことができる方法を見つけてください。タイマー値をリストに1000個のコールに格納し、その後に結果をプリントします。 1sデルタを搭載したwin7ラップトップでは、各タイマーが絶対目標時間から駆動されるため、ジッタは約5msですが、ドリフトはありません。 – barny

関連する問題