Re: [問題] 如何固定每個迴圈的執行週期?

作者: wtchen (沒有存在感的人)   2016-11-09 04:03:42
自問自答:
可以改用 TIMER_ABSTIME
Example:
#define PERIOD 4000000 // 週期為4000000ns (4ms)
void Drone_Loop()
{
struct timespec pause;
clock_gettime(CLOCK_MONOTONIC, &pause);
while(1)
{
pause.tv_nsec += PERIOD;
if(pause.tv_nsec >= 1000000000) {
pause.tv_nsec -= 1000000000;
pause.tv_sec++;
}
ReadData();
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pause, NULL);
}
}
這樣幹可以不需要用按兩次碼表或暫停期間執行其他thread的方式。
(可以做到lock-free)
不過似乎沒有比較準。
這樣說好了,如果普通的nanosleep(time),那latency一定>0。
使用TIMER_ABSTIME的話,latency會是 -x ~ +x 。
※ 引述《wtchen (沒有存在感的人)》之銘言:
: 開發平台(Platform): (Ex: Win10, Linux, ...)
: Raspberry pi model B+ / Raspberry pi 3 model B
: 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
: gcc 4.9
: 問題(Question):
: 之前希望能固定數據讀取的週期,像這樣:
: while(...)
: {
: ReadData();
: _usleep(3600); // 用nanosleep實作,不過單位換成us。
: }
: ReadData()是讀取sensor的函式,它有可能讀取1-5個sensor
: (共用一個I2C,所以要設lock),
: 因為每個sensor更新資料的週期又不一樣
: void ReadData()
: {
: if (out_of_data0) readSensor0();
: if (out_of_data1) readSensor1();
: if (out_of_data2) readSensor2();
: if (out_of_data3) readSensor3();
: if (out_of_data4) readSensor4();
: }
: 其中Sensor0跟Sensor1的週期最短,到沒啥問題。
: 問題是Sensor2/Sensor3/Sensor4週期比較長,讀取也需要200-400us。
: 只讀0/1跟5個全讀的所需時間有可能會差到500-600us。
: 之前為了固定住ReadData()的週期,我是這樣實作的:
: ....
: pthread_create(thread2, readSensor2); //細節不多寫,會意就好
: pthread_create(thread3, readSensor3);
: pthread_create(thread4, readSensor4);
: void ReadData()
: {
: readSensor0();
: readSensor1();
: if (out_of_data2) pthread_cond_signal(&cond[thread1]); // 喚醒thread2
: if (out_of_data3) pthread_cond_signal(&cond[thread1]); // 喚醒thread3
: if (out_of_data4) pthread_cond_signal(&cond[thread1]); // 喚醒thread4
: _usleep(3600);
: }
: (這幾個thread被設成讀取完自動睡回去,等待下次被喚醒)
: 意思就是說,做完readSensor0/readSensor1就暫停然後開始計時,
: 計時的同時被喚醒的readSensor2/readSensor3/readSensor4可以開始工作。
: 這招讓我的週期變化<1ms
: (使用Preempt RT的情況,我想用xenomai應該會更好,等我程式完成的差不多就試)。
: 不過我不太滿足就是,想找個可以用lock-free的方法。
: 試過一個方法是這樣:
: void ReadData()
: {
: uint64_t time1 = get_nsec(); //使用clock_gettime得到當前時間
: if (out_of_data0) readSensor0();
: if (out_of_data1) readSensor1();
: if (out_of_data2) readSensor2();
: if (out_of_data3) readSensor3();
: if (out_of_data4) readSensor4();
: uint64_t time2 = get_nsec();
: _usleep(4000-(int)(time2-time1));
: }
: 就是按兩次碼表,把執行的時間算出來,然後週期扣掉執行時間就是該暫停的時間。
: 結果發現clock_gettime太頻繁會得到奇怪的結果(不穩定)。
: 不然還有一個辦法:把整個ReadData()丟到可以被喚醒的thread去
: void ReadData()
: {
: if (out_of_data0) readSensor0();
: if (out_of_data1) readSensor1();
: if (out_of_data2) readSensor2();
: if (out_of_data3) readSensor3();
: if (out_of_data4) readSensor4();
: }
: void period()
: {
: while(....)
: {
: pthread_cond_signal(&cond[thread_of_ReadData]);
: _usleep(4000);
: }
: }
: 不過有個極小的風險是如果這個thread沒有在暫停的時間內跑完就....
: 請問還有別的方法可以讓週期的誤差更低?
: 補充說明(Supplement):
: 四軸的程式龜速改寫中,不要催....

Links booklink

Contact Us: admin [ a t ] ucptt.com