VR-Forces 4.5 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
12.1 - Tasks and Set Data Requests

Table of Contents

Simulation objects can be assigned tasks, and their state can be changed using set data requests.

You can issue tasks and set data requests from the front-end, as part of plans, and programmatically. Tasks and set data requests are wrapped in data messages and sent over the network to other VR-Forces applications.

12.1.1 Tasks

Tasks represent an action for a simulation object to perform. Tasks can be sent to simulation objects using DtVrfObjectMessages (vrfObjectMessage.h). One or more controller components typically register for specific tasks. You can add new tasks by deriving from DtSimTask (simTask.h) and using the standard factory mechanism. Tasks always contain the task type (task types are listed in radioMsgTypes.h) and whatever arguments are needed, such as the name of a control object. Once you have created a new kind of task, you must create a new controller or controllers that can implement that task.

All tasks are derived from the abstract base class DtSimTask. A task commands a simulation object to execute a particular action, such as moving to a waypoint or patrolling along a route. DtSimTask inherits from the DtReaderWriter (rdrWritr.h) class. This gives a task message the ability to save itself to and restore itself from a file. To enable the read/write capability, a derived class registers its readable/writable member data items. Classes derived from DtSimTask add the parameters needed to completely specify the task, such as the name of the waypoint in a Move To Waypoint task, or the name of the entity to follow in a Follow Entity task.

DtSimTasks also need to be able to be included in DtTaskMessages, so they can be sent over the network in the form of radio messages. They also may be included as part of a DtIfPlan message, which also is sent over the network. To provide this capability, classes derived from DtSimTask implement functions to provide a platform-independent network representation of the task data.

The DtSimTask class has a static pointer to an instance of a DtSimTaskFactory (taskFactory.h). This is a factory for creating new instances of DtSimTask, given a string task type. The DtSimCreator class, which is responsible for creating all of the various object factories in VR-Forces, creates the DtSimTaskFactory instance and then sets a pointer to it in the DtSimTask class.

Simulation objects that can respond to and execute tasks, typically register an interest in task messages in their DtTaskControllerComponents. For example, ground vehicle entities register for Move To tasks in their DtGroundMoveToControllerComponent.

The Task Manager manages the execution of tasks (skipping a task, reporting task completion, and so on). (For details, please see 4.8 - The Task Manager.)

12.1.2 Types of Tasks

VR-Forces understands the following types of tasks:

12.1.3 Subtasks

Subtasking is a mechanism by which a task controller that handles a particular type of task (behavior) can implement that behavior in terms of one or more subtasks. Rather than including the logic for handling all of the behavior in a single controller, parts of the behavior can be managed by different controllers. A task controller can delegate parts of a behavior to other controllers by issuing subtasks to the simulation object. Through subtasking, developers can write higher-level or more complex behaviors composed of existing behaviors. It can reduce the amount of code a developer has to write, and may help simplify the logic when writing higher-level controllers.

Subtasks can be nested, so it is possible for a task controller to be implemented in terms of one or more subtasks, and these subtask controllers to be implemented in terms of one or more subtasks, and so on.

Note
You do not have to use subtasking when developing new behaviors. Many task controller components in VR-Forces do not issue subtasks (they are for the most part simple behaviors). If your behavior is simple, or you want to keep all of the logic associated with a behavior in one place in the code, then it may be more appropriate not to use subtasking.

12.1.4 How to Use Subtasks

The subtask example (./examples/subtask) demonstrates how to develop a task controller that implements a new behavior in terms of subtasks. In the example, a HMMWV is configured with a controller that knows how to handle a new kind of task, a turn-and-move task. The turn-and-move task directs an entity to 1) turn toward a destination point, and 2) move to the point. To implement this new behavior, it has a new type of controller, the DtTurnAndMoveController, that responds to turn-and-move tasks, and implements the behavior in terms of a turn-to-heading subtask and a move-to subtask.

Note
To use subtasking in a controller component, you must derive your task controller from DtTaskControllerComponent or one of its subclasses.

12.1.4.1 Starting a Subtask

To issue a subtask, create and fill out the desired DtSimTask, and call sendSubtask(). It returns an integer identifier for the subtask. This identifier will be included in the task-complete report issued by the subtasking controller and is used to determine when a particular subtask is complete.

In the example, the first subtask issued is a DtTurnToHeadingTask, issued at the beginning of the turn-and-move behavior. This task is received and executed by another controller (for the entity in this particular example that is the DtGroundTurnToControllerComponent).

turnTask.setHeading(desiredHeading);
int id = sendSubtask(turnTask);
myProcessState->setSubtaskId(id);
Note
In the example, the subtask ID is saved in the process state repository. It is usually a good idea to cache the subtask ID in the process state repository, so it can be saved as part of a scenario or checkpoint.

12.1.4.2 Determining when a Subtask is Complete

To determine when a subtask is complete, you must listen for the task complete report associated with that subtask. The task-complete report contains the integer identifier returned by the sendSubtask() call when the subtask was issued. To identify the correct task-complete report, check to see that the report was issued by this simulation object and contains the matching subtask ID.

Note
Subtask IDs are unique within a single simulation object, but are not unique between simulation objects. When processing task complete reports for subtasks, make sure the task complete report you are processing is from your simulation object.
When you receive a task complete report from your simulation object with the correct subtask ID, you must remove this subtask ID from the list of pending subtask IDs by calling void removePendingSubtaskId(int subtaskId).

In the subtask example, when the task-complete report for the Turn-to-Heading subtask is received, the controller issues a Move-To subtask. As with the Turn-to-Heading task, it caches the subtask ID and waits to hear when this task is done. When this final subtask is complete, the top-level turn-and-move behavior is considered complete and the controller calls taskComplete(). For details, please see the implementation of DtTaskControllerComponent::processTaskComplete().

12.1.4.3 Canceling a Subtask

If you want to prematurely stop execution of a subtask for some reason, call clearSubtask(int subtaskId).

Note:
  • Subtasks are automatically cleared if the top-level task is canceled for some reason (for example, upon receipt of a skip-task message).
  • Do not call skipTask() to stop a subtask. skipTask() is intended for top-level (non-subtask) tasks.

To see a demonstration of the turn-and-move behavior, run the VR-Forces GUI as you would normally, but replace the vrfSim executable with the subtask executable for the back-end. Load the scenario ./examples/subtask/scenario/turnAndMove.scn. It contains a HMMWV configured with a simple plan containing a turn-and-move task.

12.1.4.4 Limitations of Subtasking

An simulation object can only execute one top-level task at a time. It can however, execute any number of subtasks at the same time.

Subtasks should only be issued by a task controller if the controller is currently executing a (top-level, or non-subtask) task.

Simulation objects should never be tasked to execute more than one type of task at a given point in time. Task controllers are only designed to handle one instance of a given task at any point in time. There are two cases to be considered:

Note
It is perfectly acceptable to issue a sequence of the same type of subtask, as long as the previous instance of the subtask is complete before issuing the next one. For example, suppose you have a movement controller that breaks a complicated maneuver down into a sequence of move-to-location behaviors. As long as the task-complete report for a given move-to-location subtask is received before issuing the next move-to-location subtask, having the controller issue multiple subtasks of this same type (move-to-location) is fine.

12.1.5 Set Data Requests

You can set several specific data values for a simulation object, including:

Set data requests are very similar in structure and usage to tasks, and are treated as a type of radio message, so controllers can register for set data request messages just as they do for task messages. Set data requests use the standard factory mechanism, so you can add your own.

[Home] [Top of Page] [Task Messages >>]


Document ID: Generated on Thu Mar 23 18:54:12 EDT 2017 from SVN revision 174804
Copyright © 2005-2017 VT MÄK. All Rights Reserved (www.mak.com)