Saturday, March 1, 2014

Periodic Tasks

This post looks at periodic tasks. The environment this applies to is the US First Robotics FTC Robot C software running on a Lego NXT brick.

Periodic tasks run at a specific and consistent time interval. For example, a task may be set to run every second or every 50ms. Why are periodic tasks interesting? A periodic task makes filtering signals, counting time, and controlling devices very simple. For example, if I have a periodic task set at 1 second, I can add a simple counter to my task. For example:

int secondsCounter=0;

task Periodic_1_second(){
   secondsCounter += 1;
}

 This will increment the seconds count once each time the task is called. After 60 seconds, I have counted to a minute.

 Periodic tasks make it possible to have signal shaping functions such as a lowPass filter or a rateLimiter. I will talk about these primitive functions in a future blog. For now, here is the Robot C code for the simplest task I can create:


// Periodic Model used to read sensors and control the motors on a NXT brick
//
// As a software programmer, I want my tasks to run at a periodic rate. A periodic rate makes control, filtering,
//    and counting much easier.
//
#pragma DebuggerWindows ("debugStream")// Bring up the debug stream window

int count=0;
int timeLeft=0; // A global variable that sticks around each frame

// ------------------------Foreground Task -----------------------------//
// Run every second
#define FOREGROUND_MS 1000 //I change this to 50 when I control the robot. 1000 is good for testing.
task main(){
 while(true){
  ClearTimer(T1);
  hogCPU(); //Prevent other tasks from running when this one is.

  for(long i=0; i<30000; ++i){} //Add some code to see the time used in the foreground. This takes about 0.5 seconds

  writeDebugStreamLine("Foreground\n"); //Let me know when the foreground runs

   count=count+1; // Count the number of times the foreground runs.

   timeLeft=FOREGROUND_MS-time1[T1]; // Calculate the time used in the foreground
   releaseCPU(); // Let other tasks run now.
   wait1Msec(timeLeft);// The time other tasks have to run before foreground takes control.
   writeDebugStreamLine("Count=[%2i] Time Left = %i\n",count,timeLeft);

   }// While Loop
}// Foreground Task

The next set of code is similar to this one. It has a background task with a low execution priority and a foreground task with a high execution priority.
// Periodic Model used to read sensors and control the motors on a NXT brick
//
// As a software programmer, I want my tasks to run at a periodic rate. A periodic rate makes control, filtering,
//    and counting much easier.
//
#pragma DebuggerWindows ("debugStream")// Bring up the debug stream window

int count=0;
int timeLeft=0;

// ------------------------Foreground Task -----------------------------//
// Run every second
#define FOREGROUND_MS 1000 //I change this to 50 when I control the robot. 1000 is good for testing.
task Foreground(){
 while(true){
  ClearTimer(T1);
  hogCPU(); //Prevent other tasks from running when this one is.

  for(long i=0; i<30000; ++i){} //Add some code to see the time used in the foreground.

  writeDebugStreamLine("Foreground\n"); //Let me know when the foreground runs

   count=count+1; // Count the number of times the foreground runs.

   timeLeft=FOREGROUND_MS-time1[T1]; // Calculate the time used in the foreground
   releaseCPU(); // Let other tasks run now.
   wait1Msec(timeLeft);// The time other tasks have to run before foreground takes control.
 }// While Loop
}// Foreground Task

// -------------------------Main Task----------------------------------//
task main(){
 count=0; //How many

 // Put initilization code here. This code will only run one time

 // Start the forground task with the highest priority
 StartTask(Foreground, 255);

 // This code runs in time left after the foreground task runs
  while(1==1){
   wait1Msec(1000); // This slows the background task down to the same speed as the foreground. Try different numbers.
   writeDebugStreamLine("Count=[%2i] Time Left = %i\n",count,timeLeft);
  }// While Background
}//Main Background
Try changing the wait1Msec statement in the background to 500 or 250. Why does the same number get printed out many times? Try changing the FOREGROUND_MS number to 500 or 250 when the background stays at 10000. Why does the counter count up more than one time? In the next posting, I will show you a simple state machine that moves the robot around in a square. Please give me a shout out if you find this software helpful.