Program Flow and Control in LegOS

Note: at the moment, this is pretty rudimentary. The original (and still primary) aim of this document is to allow students with a basic knowledge of C to get up to speed in LegOS quickly. For the most part, the functions and discussion I include here are designed for that purpose.

Probably the best way to learn code is to read other people's code. There is some in the demo/ directory in your LegOS directory. rover.c is a good place to get a feel for what is going on in simple movement and bumper input. Alternately, as already mentioned, tm-and-ir.c gives you a look at the internals of the IR system. There are also a few examples on the LegOS homepage. Demo.c, which I have already referenced, ties together some of the concepts in this section.

I've tried to do this listing by general concepts, so that people can find within them the functions they need for a particular task. If you are looking for documentation on specific snippets of code, look at the API again first, then come here. I've tried to include some general ideas for using the code, so that others can benefit from new ways of looking at the same old function. Hopefully, others will contribute to this as well.

Basic thread and process control

To do many things in LegOS you need at least a basic grasp of threading. Why? Because robotics, unlike most basic programming tasks, is not a linear task. Robots usually have to perform a certain set of uninterrupted tasks repeatedly, while at the same time waiting for specific inputs from the outside world. This is difficult at best with similar linear programming, since you have to run a loop, check for something, and then fork, while still maintaining the original behavior in the new fork. With threads, you can maintain one behavior in one thread while using other threads to maintain or modify other behaviors.

In a nutshell (in case you are really inexperienced) threading allows multiple processes to run side-by-side on the same chip. The OS executes part of one thread, part of the next, and so on and so forth. In the Section called Demo.c, one thread waits for button input and controls which other thread is running, while the others execute the various examples as they are called. This process is controlled internally by tm.h in LegOS. The interface for the LegOS programmer is unistd.h, a reduced version of the standard C library for Unix. For starters, execi() is the most important function in unistd.h.

execi(&function_name, int argc, char argv, int prior, DEFAULT_STACK_SIZE) calls the function function_name and assigns it the priority int prior. execi() immediately returns a pid_t, which you don't need to store, but you may wish to if you intend to manipulate it later. execi() immediately returns, and then you can start other threads by calling execi() from within main (or within other functions), without waiting having to wait for the original function_name to run to completion.

Several things should be kept in mind when starting a thread with execi:

kill(pid_t) allows you to pass the process id returned by execi() to kill a thread.

Unlike 0.1.x, in 0.2.x, when your program is killed by the OS, all motors, sensors, etc., are turned off by the OS, so you no longer need to worry about that in threaded programs. However, you still have to turn them off after individual threads are killed.

You can see all of this (both execi() and kill()) in action in task_swapper() in the Section called Button Demo Code. Basically, each button press kills the previous thread (using it's pid_t), does some cleanup (making sure the motors are stopped, for example) and then uses execi to start the next thread.

Timing and Event Control

Three basic functions are used in LegOS to control time-related issues: sleep(), msleep(), and wait_event().

sleep(X) and msleep(X) do exactly what their names imply- they put a thread to sleep for an integral number of seconds or milliseconds X, repectively. Because these functions are limited to exact amounts of time and cannot be tied to specific events, their uses are limited. I find them most useful in debugging loops, where I output to the LCD and then pause the bot briefly so that I can read a string or value. If you've been looking at the code in the Section called Sample Code, then you've already seen this. If not, check out the Section called Motor Demo Code, where msleep() is used to control timing of the LCD and sleep() is used to time the behavior of the motors for extended periods (well, 3 seconds).

For more sophisticated waiting, there is wait_event(function_name, data). wait_event() allows you to create a function of type wakeup_t in your code, which will return zero under normal conditions (say, the button has not been pressed) but then will return a non-zero value when whatever condition you want to wait for has occurred (say, the button has been pressed.) In order to test your function, pass it to wait event (along with a string or other necessary data). The OS will activate the function every time it touches the thread until the function returns a non-zero value, at which point the non-zero value is returned by wait_event() and can be used or ignored as necessary. Obviously, this is one of the most important functions in the OS: you will want to use it (for example) to monitor bumpers, or check for button presses, or to activate the robot when light values change suddenly. the Section called Demo.c uses this to wait for a button press, so that it knows to change functions. You can see this in the Section called Button Demo Code.

Semaphores

Semaphores are sort of complex, and I'm no expert in them (yet) so I won't discuss them in much detail here. However, they are there- and POSIX 1003.b compliant (just like Linux.) So, take a look at include/semaphore.h to see the interface, or, if you want more detail and run Linux, use man sem_init to see a more full description of what the semaphores are supposed to do. Since both implementations (Linux and legOS) attempt to be POSIX compliant, the documentation for the one is good documentation for the other.