OK, part 2 then I need to do some real work today. This may be a little complex for some here but please don't feel intimidated, it's good to see a more fully developed example once in a while.

−

The previous post contained a very simple example demonstrating RobotC multi-tasking that would flash two LEDs at different speeds, not very exciting but actually useful in some cases. The task, flashLed_1, will keep executing no matter what other code you are running. Perhaps the robot is under driver control, LED_1 keeps flashing, perhaps following a line in autonomous mode, LED_1 keeps flashing. Why it’s flashing I have no idea, perhaps bad battery, that’s up to the programmer.

The previous post contained a very simple example demonstrating RobotC multi-tasking that would flash two LEDs at different speeds, not very exciting but actually useful in some cases. The task, flashLed_1, will keep executing no matter what other code you are running. Perhaps the robot is under driver control, LED_1 keeps flashing, perhaps following a line in autonomous mode, LED_1 keeps flashing. Why it’s flashing I have no idea, perhaps bad battery, that’s up to the programmer.

Revision as of 16:15, 16 May 2012

Contents

RobotC’s ability to run more than one task is IMHO it’s greatest strength, there has been lot’s written describing multi-tasking in it’s different forms but when dealing with RobotC I like to think of it as the ability to run more than one independent program at a time even though these programs are contained within one executable and downloaded together. For some background reading on multi-tasking, wikipedia is not a bad place to start. http://en.wikipedia.org/wiki/Computer_multitasking.

Some will argue that most programs written for the VEX robotics system do not need to use multi-tasking. This to a certain extent is true, back when micro processors were not so powerful much embedded software used a technique where the “tasks”, in this case simply meaning different subroutines, were called one after the other in a so called “main loop”. Each subroutine would determine if it had any actions to take, perform them if necessary and then return. System functions needing immediate attention would be setup to use interrupts but great care had to be taken to make these special interrupt routines fast and efficient. Having said this some of the most complex embedded systems of the 60’s did use a primitive form of multi-tasking, one of the most famous of all was the Apollo guidance computer (AGC), which enabled NASA to land on the moon.

RobotC is, in fact, always using multi-tasking even when you have not created additional tasks yourself. It’s ability to display global variables, sensor values and other parameters is achieved using tasks that are started behind the scenes. These tasks only consume a small amount of the microcontrollers resources, perhaps 5%. We are not going to be concerned with how RobotC switches between tasks for now, perhaps a future post.

Part 1

OK, so much for the history lesson.

The difficulty in creating a simple multi-tasking example is that almost everything proposed can be done without using multi-tasking, however, just to illustrate the principles involved we will create a very simple piece of code to flash two leds on and off connected to different output ports.

RobotC always needs a main task, this is the entry point for the code, it’s the equivalent of the main function in any C program. From the main task we will start a second task using the StartTask command with a single parameter, the name of the task to start. The call to start the second task is:

StartTask( flashLed_1 );

Both the main and flashLed_1 tasks contain an infinite while loop, that is, a loop that never exits until the program is stopped. This loop prevents the tasks from running out of code to execute and therefore stopping. Sometimes allowing a task to finish can be useful but in general I would not recommend it, perhaps we will cover starting and stopping tasks dynamically in another post.

The contents of the while loop of each task is very similar, change the value on the output port and then wait for a preset amount of time, change the output port value back and then wait some more.

The code also includes another example of using the C preprocessor discussed in an earlier post.

#if(_TARGET == "Emulator")

This line is testing to see if the code is running on real hardware or on the PC emulator. The PC emulator can be very usefull but does not simulate real sensors, to overcome this in the example we substitute the real sensors for an array of integers by using a definition. If the code is compiled for a real cortex then

#define SENSOR SensorValue

will be used, otherwise if running on the PC Emulator a different definition is used and an array

If the tasks that you are running do not have ant wait time in them, i.e Wait1Msec(x), then the tasks might not execute properly. When you are not absolutely sure that a task will include wait time, then you must include this command somewhere in the while loop of your task so that it es executed on every iteration: endTimeSlice(); For example:

task flashLed1(){while(true){SensorValue[LED1] = 0;
wait1Msec(500);
SensorValue[LED1] = 0;
wait1Msec(500);
}}//There is no endTimeSlice() needed here because the task always waits//no matter whattask flashLed2(){while(true){if(SensorValue[button1]){SensorValue[LED1] = 0;
wait1Msec(500);
SensorValue[LED1] = 0;
wait1Msec(500);
}
endTimeSlice();
}}//This task needs a endTimeSlice() because if the button is not pressed,//then there will be no wait time in the tasktaskmain(){StartTask(flashLed1);
StartTask(flashLed2);
while(true){motor[port3] = vexRT[Ch3];
endTimeslice();
}}//The command is also needed in the main task here because the//main task does not wait in the while loop.

Part 2

The previous post contained a very simple example demonstrating RobotC multi-tasking that would flash two LEDs at different speeds, not very exciting but actually useful in some cases. The task, flashLed_1, will keep executing no matter what other code you are running. Perhaps the robot is under driver control, LED_1 keeps flashing, perhaps following a line in autonomous mode, LED_1 keeps flashing. Why it’s flashing I have no idea, perhaps bad battery, that’s up to the programmer.

(one caveat here, when using the competition template, RobotC will stop all tasks started in Autonomous mode before entering driver control mode. You need to restart tasks you may want in both phases).

Now for a more complex example, hopefully not too complex but programmers of all abilities are presumably reading the forums.

One thing that I see that always worries me when students are doing motor control is that motors are being switched from full speed forwards to full speed backwards instantaneously. I’ve never seen any damage resulting from this, and I’m sure VEX has designed the motors to handle this stress, but it worries me all the same. To circumvent this situation we are going to use multi-tasking to implement a controlled acceleration and deceleration of the motors, I call this slew rate control, but it goes by other names as well.

To achieve this we will use an intermediate variable to hold the requested speed of the motor and a task to gradually change the current speed of the motor until it reaches the requested speed. As there can be up to 10 motors connected to the cortex microcontroller we need to track this for all 10 motors. We may not want the same acceleration and deceleration for all motors so we will also have a variable for each motor that determines how fast each one can change.

A bunch of definitions used by the task controlling acceleration and deceleration. An array, motorReq, to hold the requested speed for each motor. An array, motorSlew, to hold the change in speed for each motor each time we check it:

This is the task that sends new speeds to each motor. The code before the while statement initializes the variables to a known state. Within the while loop there is a for loop that iterates through each motor. The current motor speed is compared to the requested speed and incremented or decremented as necessary. The motor speed is limited to the exact speed requested and then sent to the motor. The task having checked each motor then goes to sleep for a defined time (15mS in this case) before being woken up again by the RobotC task scheduler.

This is the main task and entry point for the program. The “MotorSlewRateTask” is started, the “ArcadeDrive” is started and then it enters a loop that does nothing. All control is handled by the other two tasks. Implementing main in this fashion allows the code to be moved into the competition template easily, to enter driver control simply start the two other tasks.