Arduino RTOS - RobotCasserole1736/RoboSim GitHub Wiki

Background

There are currently two implementations of the RoboSim arduino-side software, one with an RTOS and another without (aka, "big loop" method).

What's an RTOS?

Glad you asked! RTOS stands for "Real Time Operating System". An operating system, as you probably know, is simply the software which runs other software.

Windows and Linux are Operating Systems. They are pieces of software which get installed on a computer, and then coordinate running other pieces of software. This coordination involves running multiple programs at once, facilitating communication between programs, overseeing access to hardware resources (ie, memory, disk drives, network cards, sound cards, etc.), and ensuring each piece of software doesn't step on another software's work.

All operating systems have overarching design goals, and therefore must make tradeoffs. For example, on your desktop PC, the operating system's primary job is coordinating many pieces of software which don't know about each other. This drives them to make choices to keep each application secure (ie, Evil program Foo can't read bank account info out of web browser Bar), and ensure no one program hogs precious resources like processor time or memory. What this leads to is non-deterministic operation - we do not know frequently a given piece of software will be run. This is manifested every time your PC hangs slightly - the program you want to run is not getting enough resources to run as fast as you want.

A Real-Time operating system makes different assumptions. In a real time operating system, we assume that all the programs (or processes, to be more specific) are under our control, so we don't need to worry about malicious programs hogging resources. Therefore, an RTOS allows each program or process to dictate exactly how often it needs to be run, and even interrupt lower-priority processes to guarantee a certain call-rate.

Why do we need an RTOS?

Well, we strictly don't need one. However, the RoboSim Arduino software is a great case for one. Some of the basic tasks which need to be performed are: -Sample IO (read inputs, set outputs) -Talk to PC (read/write serial) -Blink a status light.

Because of the way the math of control systems works out, we MUST sample IO at a very regular rate. Late samples are not acceptable. Talking to the PC also needs to happen pretty fast and on a fairly tight schedule, but slightly late transmissions are acceptable because serial communications are buffered. Blinking a status light is pretty low priority - although it needs to happen, if the blink rate is irregular, who cares.

Moreover, what we don't want is the serial read or write to slow down the IO sampling. If we just do the tasks one-after-another all the time, a glitch in the host PC (which does NOT have an RTOS) could make a serial packet late, which could make a sample late, which would throw off the plant model (very bad).

To get around this, we divide each of those tasks into independent processes, and assign priorities. Sampling io has the highest priority, followed by serial, followed by status light blink. Each has a target schedule that we should run the process on, but if we suddenly need to run two processes at the same time, the higher-priority one always wins out. This guarantees that we always sample the IO at the prescribed rate, while still being able to do the other tasks.

For the terminology-obsessed, this priority yielding property is called "Preemption" .

FreeRTOS and Arduino

Just as there are many versions of Linux or Windows, there are also many RTOS's. We have chosen FreeRTOS, a free and open-source real time operating system. It's very well commented and complies with many safety standards, and gets you all the features you'd like to see in an RTOS without being too bloated. There are core code files for the OS which implement most of the abstract concepts (process scheduling, memory management, semaphores, process switching, etc.), and some files which are specific to the hardware and processor you're running on. For the latter files, some dude online already had a "port" of the OS done for arduino, so we picked it up and it worked.

Main Function Overview

All of the files for the RTOS version of the RoboSim software are located in \RoboSim\ArduinoSrc_RTOS\RoboSim_rtos.

The main file to start looking at is "RoboSim_rtos.ino" It's the standard arduino main .ino file, with the required setup() and loop() functions.

Prior to setup, you'll see the functions we use to define the processes. These are like the different pieces of software on your PC. Each is an independent task which performs a specific action or set of actions. All tasks currently do not return ever, since they should run for the duration of the time RoboSim is turned on.

Task Function Details

Task functions must take the format:

static void vTaskFcnName(void *pvParameters)

Within each task function, you'll see the first few lines where the task does initialization of any variables it needs before it starts running.

After initializing, the task should go into an infinite loop. This is the main content of the task:

for(;;)
{
  vTaskDelayUntil( &xLastWakeTime, xFrequency );

  <Task Actions>

}

Obviously, "Task Actions" consists of some code which is run by the task.

Important to note is the vTaskDelayUntil call. This is a special RTOS function which allows the task to tell the operating system "I don't need to always run! Put me to sleep and don't run me until after some amount of time", where "some amount of time" is related to the interval at which the task should be called, minus the time it took to complete the task. In this way, there is a sort-of handshaking between the RTOS and its tasks. The RTOS wakes up a task, the task does its thing, then tells the RTOS when to wake it up again. In this way, the tasks will yeild the processor resource to whatever other tasks need it.

Additionally, because the RTOS allows for preemption, the OS will force put to sleep a process if a higher-priority process needs to wake up.

setup()

This is the place the Arduino starts running code at boot. There are some global initilizations we do before we turn the tasks loose.

Then, there are a number of calls to a special function xTaskCreate(). There are one of these calls per task, and they tell the RTOS about the tasks we want to create, along with what function contains the task's code, how much stack space the task needs, and the task's priority.

Finally, we call "vTaskStartScheduler();", which starts the operating system running. This function should never return, as the OS's Scheduler will take over and begin running tasks at the prescribed rates and priorities.

loop()

Since all the action happens in the task functions, loop only exists because the Arduino IDE requires it. FreeRTOS uses it as part of the "idle task", which is the task which gets run whenever no other task needs to be running. It doesn't have to do anything, but it does have to exist.

Processes We Define

Currently, due to memory constraints, we're only running three processes:

vHWIOSample reads the IO board and analog inputs and sets outputs. vPCSerialTx sends serial packets to the PC. vPCSerialRx gets any packets from the PC.

Potential Future Improvements

Our biggest limitation at the moment is that the Arduino Uno only has 2KB of RAM (2KB!!!! TINY!!!). Therefore, we are pretty much limited to 3 processes before we run out of memory or overflow our runtime stacks. A Mega has 8, so that might work a lot better.