gordon@drogon.net wrote:the latest wiringPi is capable of reasonably accurate 5-10uS timings, however it will consume 100% CPU while its doing it and the rest of the system really isn't up to it. The Pi is not a "hard" real-time controller suitable for flight control IMO. There is just too many things to go wrong in the time-scales involved - the kernel will interrupt you, you might have a delay of a few milliseconds on reading the IMU and before you know it, you're upside down which is not a good place to be in a quadcopter....
The best case timing accuracy is certainly orders of magnitude better than the worst case preemption/interrupt latency.
The C program for Linux below calls gettimeofday in a tight loop during even seconds, and reports its biggest delays; in other words, time that it has lost due to hardware interrupts or software preemption. In odd seconds it sleeps so that other processes can catch up and we can exercise the SD and USB subsystems. (It is also important that a realtime process not use 100% cpu for a long period, or the kernel may throttle it to avoid deadlock.)
With the program running under sudo, interactive performance for the rest of the system is obviously abysmal. Not even the echoing of input characters will happen until the start of the next odd second. Nevertheless it is possible for other processes to access the network and SD card, and the consequences of this will spill into the even seconds.
The absolute worst delay I have ever seen is 502µs, and cases over half that are extremely rare. I suspect that if we wanted to improve on this we could do so by disabling subsystems, or changing the kernel command line or configuration. I have not yet investigated that.
Anyway, I believe that microsecond timing should be possible in the best cases, and nearest-millisecond timing even in the worst.
- Code: Select all
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sched.h>
int main()
{
struct sched_param param;
struct timeval tv[2];
int i, elap, max = 0, maxx = 0;
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_setscheduler(0, SCHED_FIFO, ¶m) < 0)
perror("warning: sched_setscheduler");
if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0)
perror("warning: mlockall");
for (;;) {
gettimeofday(tv, 0);
for (i=1; ; i=!i) {
gettimeofday(tv+i, 0);
elap = (tv[i].tv_sec-tv[!i].tv_sec)*1000000 +tv[i].tv_usec-tv[!i].tv_usec;
if (elap > maxx) maxx = elap;
if (elap > max) printf("delayed by %dµs, max %dµs\n", max=elap, maxx);
if (tv[i].tv_sec & 1) break;
}
usleep(1000000 - tv[i].tv_usec);
max = max*7/8; // next second, report delays that are nearly as big
}
}