[완료] C 프로그래밍 중 질문이 있어서 올려봅니다.
ADC에서 데이터를 받아올때 1초에 12번 정확히 받고 싶은데.
정확하게 받을 방법을 고민해보다가 질문 올려봅니다.
while (1){
usleep ( 83333 - ((et.tv_nsec - st.tv_nsec) / 1000));
clock_gettime(CLOCK_REALTIME, &st);
if (!flag){
flag = 1;
clock_gettime(CLOCK_REALTIME, &tst);
}
// timeCorrect++;
for ( i = 0 ; i < 4 ; i++ ) {
if ( I2C_IO_GetADC( i2cDev, i, &adcVal ))
{
x_next[i] = x[i];
P_next[i] = P[i] + Q;
K[i] = P_next[i]/(P_next[i]+R);
z[i] = -0.37727+adcVal;
x[i] = x_next[i] + K[i] * (z[i] - x_next[i]);
P[i] = (1-K[i]) * P_next[i];
*(ep + i) = x[i];
count[i]++;
}
else
{
LogError( "Failed to retrieve ADC value\n" );
break;
}
}
ep += 4;
}
1초를 12로 나눈 값에 usleep 을 씌우기 위해 상수 83333을 넣었구여
프로그램 동작시간을 빼서.. 나름대로 정확도를 높여보려 했으나;
10초 동안 받으면 120번을 받아야 하는데. 115번 요정도 밖에 못받습니다.
어떻게 정확하게 받을 수 있는 방법이 없을까요?
게임쪽에서도 위처럼
게임쪽에서도 위처럼 Elapsed time 을 보통 사용해서 프레임 유지를 유도합니다.
( 그래도 100% 보장은 안됩니다. 가끔 I/O 같은게 발생하면 약간 끊어지는 경우가 발생하죠. )
그러나 약간 다른 방식을 씁니다.
예를들어 60 fps 를 유지하려면
while(1){
현재 시간이 마지막에 update 했던 시간과 비교하여 1/60 초가 안지났으면 -> Sleep(10)
지났으면 다음 프레임 그린다 ( 그리면서 마지막에 update 했던 시간을 지금 시간으로 한다.)
할일()
}
보통 이렇게 하면 거의 59.7~60.1 정도를 왔다갔다 합니다.
하지만 현재 일반적인 PC 에선 완벽한실시간 시스템은 없습니다. 오차가 생기고 말죠. 특히 하시는 일이 I/O 이므로
응답성이 매우 불규칙 할겁니다. ( 즉 전에 I/O 작업 한 시각과 지금 작업한 시각에는 편차가 생기죠. 게임도
지금 프레임은 우연히 폴리곤을 적게 그려서 빠르게 응답이 돌아왔지만 다음 프레임은 그럴것이란 보장이 없죠. )
따라서 제가 위에 쓴대로 짧은 시간을 자주 Sleep 하면서 원하는 시각이 돌아왔는지 Check 하는것이
120 회수를 더 잘 보장해 줄 것입니다.
Neogeo - Future is Now.
Neogeo - Future is Now.
답글 감사드립니다.
답글 정말 감사드립니다.
근데 지금 구현한 부분도 그런식인데.. 11초에 117번 이런식으로 돌고 너무 불규칙 한 면이 없지않아.
다른 방법이 없을까 고민하고 있습니다 ㅠ_ㅠ
누구에게나 자신의 상황이 제일 힘들다.. 즐기자!
지금 구현
지금 구현 하신부분이 그런식이 아니라서 문제입니다.
usleep ( 83333 - ((et.tv_nsec - st.tv_nsec) / 1000));
앞에서 실행에 걸린 시간만큼을 빼주고 usleep 하시는 방식이시니 문제입니다. 제가 드린 코드는 전혀 다른 방식입니다.
차라리 아주 적은 시간을 sleep 해주시고 시간이 1/10 초가 되었는지 확인해 보시는 방식을 권해드린 겁니다.
자세히 다시 수도 코드를 적어드리면.
예를 들어 I/O 작업이 1초에 10회 수행 되어야 한다면,
while (1)
{
if ( 현재시간 - 마지막 수행시간 < 1/10 초 )
Sleep ( 아주 적은시간 );
else
{
마지막수행시간 = 현재시간;
I/O 작업();
}
}
을 권합니다.
원래 쓰신 코드의 I/O 작업시간을 측정해서 다음 회에 그만큼 쉬어주는 루틴 자체가 문제입니다.
( I/O 작업 시간을 측정해보아야 불규칙하므로 아무 의미가 없습니다. )
즉 무조건 아주 적은 시간을 쉬며 계속 루틴을 체크해보길 권하는 겁니다.
Neogeo - Future is Now.
Neogeo - Future is Now.
네 저 소스를 고쳐서..
답변 감사드립니다. 저 소스를 고쳐서
while ( flag && tmp < 100000000 ) { //10 frame
usleep (1);
clock_gettime(CLOCK_REALTIME, &et);
tmp = et.tv_nsec - st.tv_nsec
+ (et.tv_sec - st.tv_sec) * 1000000000;
}
말씀하신데로 이런식으로 고쳤었는데 그래도 안나오더군요; -0-;;
9.3프레임 정도 밖에는 안나와서.. 또다시 딜레마에 빠져버렸습니다 ㅠ-ㅠ
아무튼 관심 갖어주셔서 감사드려요
누구에게나 자신의 상황이 제일 힘들다.. 즐기자!
구현하신 루틴을
구현하신 루틴을 제대로 올리셨는지 모르겠네요...
처음에 이런 부분이 있는데,
et 를 구하는 부분이 없고,
이 부분은 위 루틴상에서 전혀 의미가 없네요.
대개는 다음과 같은 정도가 되지 않을까 싶은데요.
이렇게 하면, clock_gettime 을 한다음 발생하는 오버헤드가 잘 감안될 겁니다.
Orion Project : http://orionids.org
답글 감사드립니다(_ _)
부분만 올린다는게 디버그 하는 부분을 .. 따로 안올렸네요.
문제가 다른데 있더라구여;
ADC 에서 데이터를 받아올때 간혹 12프레임을 못따라가서.. 함수에서 이미 12프레임 이상을
대기하고 잇는 시간이 생겨버려서 12프레임을 만들지 못하는 거더군요;;;
누구에게나 자신의 상황이 제일 힘들다.. 즐기자!
음... 약간의 문제가
음... 약간의 문제가 더 있어보이는군요.
두 시간차를 구할 때 tv_sec 을 무시할 수 없습니다.
tv_sec 까지 고려해서 시간차를 구하는 것까지 구현하시거나, 정확성이 좀 떨어질 지 몰라도 clock 함수를 쓰는 방법 등을 고려하시기 바랍니다.
Orion Project : http://orionids.org
감사합니다!(_ _)
이래저래 찍어보니 저 문제가 있더라군요; 그래서 그부분을 수정했습니다.
근데 ADC 값을 받아오는 함수가. 간혹 딜레이를 많이 잡아서.. 12프레임을 따라가지 못하네요;
이게 불규칙적이라서;;
아무튼 감사드립니다 ( _ _)
누구에게나 자신의 상황이 제일 힘들다.. 즐기자!
댓글 달기