*Having never had the opportunity to personally code an FRC robot, I don’t know all the specifics of what support the various languages and frameworks provide for debugging repeatable or intermittent realtime issues like I see being discussed all the time on CD.
But there is a technique my team and I used to use back in the day when we were developing software for embedded realtime systems.
I present it here for discussion.
put this code at the very beginning of TeleOp and every other periodic thread:
10 temp = time()
20 ptest += temp-tstart-period
30 if(ptest>period){err++; ptest=0}
40 tstart = temp
50 for(i=1;i<=burns;i++){x=1.0/(x+1.0)}
Explanation of line numbers:
Line 10 grabs a system timer. You want to pick one that has low overhead and sufficient resolution. I haven’t visited this issue since January of 2013 so I won’t make a specific recommendation here, but here is a thread worth reading:
Line 20 accumulates the thread start jitter in ptest. In an ideal world this would average out to zero.
Line 30 tests the thread start jitter accumulator ptest. If it exceeds one period (of the thread in question), then you’ve missed a cycle, so increment an error counter and reset the accumulator.
Line 40 updates tstart for the next iteration
Line 50 is something we used to call (way back when I was doing this kind of stuff) a “burn counter”. When burns=0 it does nothing. As you increase the value of burns it starts using CPU time. This is a great way to get a rough idea how much CPU margin you have. Set all the burns to zero (one for each periodic task/thread). Then test each thread one at a time by increasing the burns in that thread until either a) you start seeing the err counter increment, or b) your code starts misbehaving. Repeat for each thread.
Other notes:
I didn’t show initialization or scope of the variables. That will differ with your language. Do whatever is necessary for proper initialization*, and to assure that 1) each thread has its own temp, ptest, err, tstart, period, burns, and x variables, and 2) you can easily set the burns variable and monitor the err variable while the code is running. All variables must retain their values for the next time the thread runs.
temp, ptest, tstart, and period should all be the same type as returned by time()
“period” is the period of the thread
“i” and “burns” are 32 bit unsigned integers
x should be float, and should be initialized to zero.
*by "initialization I mean one-time (at startup) initialization, not initialization each time a thread executes.
*
*