Much was made of the Mars rover bug but it was just that, a bug. Like all bugs, it shouldn't have happened since the proper design for avoiding "priority inversion" was well known since the early 1970s. The Mars rover problem happened in 1997.
When created, a VxWorks mutex object accepts a boolean parameter that indicates whether priority inheritance should be performed by the mutex. The mutex in question had been initialized with the parameter off; had it been on, the low-priority meteorological thread would have inherited the priority of the high-priority data bus thread blocked on it while it held the mutex, causing it be scheduled with higher priority than the medium-priority communications task, thus preventing the priority inversion. Once diagnosed, it was clear to the JPL engineers that using priority inheritance would prevent the resets they were seeing.
I did become part of the fear factor of using a RTOS. Like this kind of misinformation - "an RTOS shouldn't be used on an Uno since the overhead is too high".
Here is a simple case study for an example I am developing. The problem is to read data from analog pins at regular intervals and write it to an SD card.
The simple solution is a loop like this:
-
Wait till start of period.
-
Read data.
-
Write data to SD.
-
Repeat.
A problem occurs when the period between points is less than about 100 milliseconds. SD cards can have occasional latencies of over 100 milliseconds so data overruns occur.
A possible solution is to use an RTOS with two threads. Can the Uno support the extra overhead?
The answer is that the RTOS solution is far more efficient than the above loop. Here's why.
The RTOS solution has two threads.
The analog read thread runs at high priority and is a loop like this:
-
Wait till start of period.
-
Read data.
-
Write data to a FIFO buffer.
-
Repeat.
The SD write thread is a loop that runs at lower priority.
-
Wait for data in the FIFO.
-
Write data to SD
-
Repeat.
The two thread solution is more efficient than the first single loop solution. CPU time is recovered when the SD is busy and the higher priority thread is scheduled.
Now comes the real payoff. The Arduino analogRead() take about 115 microseconds. Almost all of this is in a busy loop waiting for the ADC conversion.
I wrote an RTOS based replacement for analogRead() that is transparent to users but sleeps during the ADC conversion. This saves over 90 microseconds of CPU time per read after factoring in a context switch.
The result is that the RTOS version can log more than twice as fast and doesn't suffer data overruns. The simple loop version has the high overhead of busy loops that the RTOS avoids.
I have ported three RTOSs to Arduino Google Code Archive - Long-term storage for Google Code Project Hosting..
My favorite for Uno is NilRTOS. Its author, Giovanni Di Sirio, says it's "Smaller than ChibiOS/RT, so small it's almost nil."