• Aucun résultat trouvé

Writing a Multitask Program

Dans le document Creating Cool MINDSTORMS® (Page 171-176)

You can transform the program for the Omni-Biped to use multitasking. The overall behavior will remain the same, except that the legs will be aligned simultaneously, and not one after another.

The preprocessor definitions are the same as before for the single-task program, and so they are omitted. In Listing 5-6 you can view the first part of the multitask program.

Listing 5-6. The Declaration of Global Variables and the Functions of the Multitask Program for the Omni-Biped

if (dir==LEFT)

{

Off (BOTH_LEGS);

Release(Rmotor);

Release(Lmotor);

}

In the preceding code the global variables are declared, together with the mutex variables that will act as semaphores, to regulate the concurrent tasks’ access to the shared resources.

Tip

You should note that global variables are a good way to let many tasks communicate with one another. On the other hand, they must be seen as shared resources, so the access to those variables must be well disciplined to avoid corrupting their value, in case more than one task wants to write them. Notice that such a conflict does not exist, if a task only writes a global variable, while the others just read it.

The Smessageand Nmessagefunctions are a bit different from the previous version, because the NXT display is now a shared output device. So, you must put the TextOutand NumOutAPI functions inside a critical section, delimited by the Acquire(display)and Release(display) statements. The AnnounceDirand Biped_initfunctions are pretty much the same as before.

However, the RealignLegssubroutine is completely different. It doesn’t move motors directly, but is used to discipline the realignment tasks’ access to the motors. Before continuing the discussion, read the code in Listing 5-7.

Listing 5-7. The main() and Walk() Tasks of the Omni-Biped Multitask Program task main ()

while (!obstacle && timer<TURN_TIME)

In this multitask program, the maintask simply calls the Biped_initsubroutine and exits.

This leaves space for all other concurrent tasks in the program that contain the statement Follows(main). The concurrent tasks are as follows:

• Sight: Reads the Ultrasonic Sensor continuously and shares information about obstacles using the global variable obstacle, the output of the hysteresis cycle filter.

• Walk: Contains the loop corresponding to the main loop in the single-thread program.

The robot goes straight until it sees an obstacle. It then backs up until the obstacle fades away, turns randomly, and then starts the loop again.

• AlignRightLegandAlignLeftLeg: This time, the legs are reset in separate tasks, so that the duties can be accomplished simultaneously, thus saving time.

As mentioned before, some of these tasks share the same resources. In particular, Walk shares the motors with AlignRightLegand AlignLeftLeg. To avoid conflicts, when one of these tasks wants to use the motors, it must first acquire the corresponding mutex, use the motors inside the critical section, and release the mutex when done. For example, the Walktask calls the AcquireLegs()and ReleaseLegs()functions (see Listing 5-6) to enclose the critical section where it uses the motors. In Listing 5-8, you can see the code of one of the alignment tasks (the code for the other leg is similar and thus omitted).

Listing 5-8. The Code of the Task to Realign the Right Leg Position task AlignRightLeg ()

{

These realignment tasks run forever, and they would try to realign the legs continuously, conflicting with the Walktask. So, they must be kept quiet until realignment is required. To accomplish this and also to avoid any unwanted behavior, use the mutex-like Lresetand RresetBoolean variables.

Note

These Lresetand RresetBoolean variables have a different function from the Rmotorand Lmotormutexes, because they discipline a larger-scale mechanism: mutexes are used to avoid low-level conflicts, while these Boolean variables prevent the tasks from becoming stuck waiting for one another.

When you want to reset, say, the right leg, you must set the Rresetvariable to true, unblock-ing the realignment task. In fact, the AlignRightLegtask hangs at the while (!Rreset) Wait(100) statement until the RealignLegsfunction sets Rresetto true(see Listing 5-6). Once free to do its duty, the task acquires the right leg mutex and aligns the leg as described before. When the realignment is completed, the Rresetvariable is set to false, so that at the next loop iteration the task will stop, waiting for the Rresetvariable to be set to trueagain.

Finally, the Sighttask implements, in its last lines, the hysteresis cycle described in the previous paragraph (see Listing 5-9).

C H A P T E R 5■ O M N I - B I P E D 162

Listing 5-9. The Code of the Task Used to Measure the Obstacle’s Distance Continuously

if (d < NEAR) obstacle = true;

else if (d > FAR ) obstacle = false;

} }

Tip

Try to set both the FARand NEARconstant thresholds to the same value, and download the program to the Omni-Biped. You should notice a jerky behavior, meaning that the robot switches constantly from for-ward to backfor-ward motion. This undesirable effect comes about because the hysteresis cycle is made idle by the identical values of the thresholds. After having experimented, fix the program by setting the FARconstant higher than the NEARconstant value.

Dans le document Creating Cool MINDSTORMS® (Page 171-176)