2017-05-10 14 views
0

저는 센서에서 데이터를 얻기 위해 매 10ms라는 함수를 사용하려고합니다.Python, Raspberry pi, 정확하게 10 밀리 초 단위로 작업을 호출합니다.

기본적으로 나는 gpio 인터럽트에서 콜백을 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 

그래서 타이머가 몇 초 후에 매우 큰 편견은 0.2 밀리 초 10 밀리 초마다에 의해 derivating된다.

나는 파이썬이 실제로 "실시간"으로 만들어지지 않는다는 것을 알고 있지만, 그것을 할 방법이 있어야한다고 생각합니다.

누군가가 이미 파이썬으로 시간 제약 조건을 처리해야하는 경우 몇 가지 조언을 제공하게되어 기쁩니다.

감사합니다.

+0

타이머 자체가 걸리는 시간과 인쇄를 허용하지 않기 때문에 표류합니다. 실제 시간과 다음 10ms가 끝나는 시간의 차이를 기준으로 타이머를 설정하면 타이밍이 흐트러지지 않습니다. 예를 들어 루프를 시작하고 10ms 씩 증가하는 '목표'를 유지하기 전에 시간을 확보하고 (target-currenttime) 기간 동안 타이머를 시작한 다음 타이머가 만료되면 대상에 10ms를 추가하고 다시 시작합니다 . 지터가 수용 가능한지 직접 확인해야합니다. 즉, 모든 사용 시나리오에서 평균값과 최고치를 측정하십시오. – barny

+0

답장을 보내 주셔서 감사합니다. 타이머 스케줄링 시간을 측정하지는 않지만, 추가하지는 않을 것입니다. 그런 표류. 요점은이 10ms에 대해 매우 정확하고 싶습니다.이 방법의 문제점은 타이머 스케줄링에서 항상 드리프트가 발생한다는 것입니다. – Arkaik

+0

처음에이 값을 한 번만 정의하고 타이머가 만료 된 후 자동으로 다시 시작되도록하는 방법이 있습니까? – Arkaik

답변

0

이 코드는 내 랩톱에서 작동합니다. 목표와 실제 시간 사이의 델타를 기록합니다. 중요한 것은 work() 함수에서 수행되는 작업을 최소화하는 것입니다. 인쇄 및 스크롤 화면이 오랜 시간이 걸릴 수 있습니다.

중요한 것은 해당 호출이 만들어진 시간과 대상 사이의 차이에 따라 다음 타이머를 시작하는 것입니다.

-o :

나는 그래서 thte 타이머() 호출에 음의 값을 전달 문제를 야기은 10ms를 초과 할 수 내 Win7에 x64의에 지터를 참조하는 것이 더 쉽습니다 0.1 초에 간격을 둔화 이렇게하면 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) 

일반적인 출력 (예 :파이썬에서 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

안녕하세요 @ 마침내 내 문제는 time.clock() 사용했을 때 나는 그것을 시도 time.time() 대신 잘 작동했습니다. 나는 오래 머무를 수 있었다 ^^. 귀하의 정보는 내 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 

그래서 우리는 대상이 타이머 지연, 10ms의 당 첫 번째 루프 증가하고 있음을 알 수 좋은 것 같습니다.

점 대신 CURRENT_TIME 다시 시작하는 + 그것은 내가 뭔가를 놓친나요 0.001521 대신

0.01000의 지연을 나타냅니다 0.045622 다시 시작 지연입니까? 내 코드가 당신의 논리를 따르는 것 아닌가요?

+0

타이머를 시작하기 전에 t0를 설정해야합니다. 타이머 호출에서 현재 시간을 사용하는 것이 좋습니다 (예 : threading.Timer (target-time.clock (), ...) – barny

+0

숫자를 문자열로 변환, 인쇄, 화면 스크롤 등은 work() 함수의 소요 시간에 영향을 미친다는 것을 잊지 마십시오. 델타를 1s로 늘리고 기본 원리가 작동하는지 확인한 다음 work() 함수에서 수행 할 수있는 작업이 거의없는 것으로 파악하십시오. 타이머 값을 목록 1000 개에 저장하고 나중에 결과를 인쇄하십시오. 1s 델타를 사용하는 win7 랩탑에서는 지터가 약 5ms이지만, 각 타이머는 절대 목표 시간에서 구동되기 때문에 표류가 없습니다. – barny