Wednesday, 12 April 2017

Sprint #1 - RTOS Basics and Hello World - Padraigh Walsh


Hello there, My name is Padraigh Walsh and this blog post will cover some Real Time Operating Systems (RTOS) basics as well as my Hello World project for the first sprint.


Real Time Operating Systems basically consist of an operating system (OS) and threads. Think of threads as functions in C. But instead of being called sequentially one after another in a massive while(1) loop, all the threads are happen at the same time. But they don't, as there is only one processor. This is where the OS comes in. It dictates which thread is running on the processor and for how long. It does this so fast that the threads all appear to be running at the same time and hence gives the name Real Time. 
    Think of the OS as a toy, the threads as children and the operating system as a mother. All the children want to play with the toy, but the mother has to decide which child gets the toy, while also ensuring the rest of them get their fair share of the toy. Speed this up by a couple of Mega Hertz and you have a RTOS.


Mutexs (Mutual Exclusion) are essentially locks that prevents threads from accessing a shared resource at the same time. A resource, such as an LED, speaker, Accelerator on a car etc.. gets wrapped by a Mutex.lock and a Mutex.unlock command. When a thread needs to use the resource, it gets the lock off of the OS and locks the resource so it can only use it. So even if the OS kicks the thread off of the processor, a different thread can't use the resource and possible cause a disaster. Once the thread is finished with the resource, it unlocks the Mutex and hands the key back to the OS. Now the resource is free to be used by another thread.


Semaphores are like Mutexs but aren't. Whereas a Mutex protects a single resource, A Semaphore protects a multitude of simialr resources, like an array of LEDs, several com ports etc.. If a thread needs to use a resource it gets a Semaphore and uses it. If another threads needs to use the resource it gets another Semaphore. Threads can keep doing this until they run out of Semaphores. If they're no Semaphores available, they thread must wait until a semaphore becomes available.

    Think of Semaphores as a bouncer on a nightclub. The club is the shared resource that can hold, let's say 100 people. The people are the threads. The bouncer knows that it can only allow 100 people in at any one time. So as people want to enter the club, the bouncer has no problem letting them use that resource and keeps track of how many people are inside. When 100 people are inside, the bouncer stops anyone else from entering. When a person leaves, the bouncer see that there's a space available and lets another person in, but never leaves too many people in.


Signals are essentially flags that one thread sends to another. One thread waits for a signal, while a different thread sets the thread. Think of players doing sprints at training. The trainers whistle is the signal. When the trainer blows his whistle, the team sprints and comes back and waits for the next whistle.


Memory Pools and Queues

Memory Queues are used to transfer messages from one thread to another. They can also transfer messages from interrupts and threads. They work on the basis of First In First Out (FIFO). Using message queue functions, you can control, send, receive, or wait for messages. The data to be passed can be of integer or pointer type

Memory pools are fixed-size blocks of memory that are thread-safe. They operate much faster than the dynamically allocated heap and do not suffer from fragmentation. Being thread-safe, they can be accessed from both threads and interrupts.

Hello World Lamp Bot

My Hello World will consist of a vision system using RoboRealm to track the XY of a face. These coordinates will then be transferred serially to the Mbed. Using threads, the coordinates will be then be sent to a pair of motors that represent pan & tilt.

Mbed Code

The Mbed code is trickier than the RoboRealm code as receiving a message is tougher that transmitting it.

The line of code that reads in from the serial is: 
This continuously reads in the serial port until a NULL character is reached. Whatever is read in is then placed in "buffer".
I'll be sending down two coordinates seperated by some sort of special character. knowing that they'll be a special character I can split the message in "buffer" into two:
Message1 = strtok (buffer,","); Message2 = strtok (NULL,",");
"strtok" or store token, copies everything up to a deliminator. In this case the deliminator is ','. So Message1 receives everything up to ','. when it hits ',', it replaces with it with NULL and the command is finished. The next "strtok" command takes everything from NULL up to  ',' and places it in Message2.

Message 1&2 now have the two coordinates, but they are in a string from and not integer and cannot be used by the motors. Therefore the scanf function is used:

sscanf(Message1,"%d ",&x); sscanf(Message2,"%d ",&y);

This command looks at what is in "Message1", converts it to %d or an integer, and sets the address of x to contain the converted string.

Now that the two coordinates are seperated and in integer form, they simply need to be sent to the motors. Using Memory Pools, the coordinates are sent from the receiving thread to the transmission thread.
message->X_coord = x; message->Y_coord = y; queue.put(message); Thread::wait(50);

The coordinates are then received from the Memory Pool using the following lines:

osEvent evt = queue.get(); if (evt.status == osEventMessage) { message_t *message = (message_t*)evt.value.p;

The first line polls the queue and puts whatever is in it into "evt". A check then occurs and sees if anything is in "evt". If there is, its values are placed into "message". Now the two coordinates are in "message" and ready to be sent to the servos.

motor1.write(message->X_coord); motor2.write(message->Y_coord);

The lines above are fairly intuitive, I'll let you figure them out 😉

No comments:

Post a Comment