VR-Forces 4.0.4 Class Documentation
The Component Manager

Table of Contents

The Component Manager, DtSimComponentManager (compMgr.h), is a top-level class owned by a DtVrfObject that is responsible for managing the object’s DtSimComponent instances.

It creates, connects, and maintains the lists of DtSimComponents for an entity. Entities that are configured with a Component Manager have an instance of a DtSimComponentManager. (For information about configuring an object with a Component Manager, please see "Local and Remote Subcomponents" in VR-Forces Configuration Guide.) Only local entities have a Component Manager.

The DtComponentManager has-a DtComponentSystem data member that holds all DtComponentSystem and DtSimComponent instances for the entity. It is implicity created (so it will be present even if no systems are explicitly configured as part of an entity in its parameter database). This base system has-a DtComponentNetwork member that performs much of the actual management work on behalf of the DtComponentManager.

Immediately after creating and initializing the Component Manager in DtVrfObject::init(), the object invokes DtVrfComponentManager::addComponents(). This function:

The Component Manager ticks the system, sensor, controller, and actuator lists, which in turn iterate through their list of systems and components and call their tick functions. The component lists are ticked in the order: system, sensor, controller, actuator. The order in which individual components are ticked is the same order as the list of corresponding component descriptors in the entity’s parameters member. The tick order of components and component lists can affect the priority of components. (For details, please see Setting the Priority of Components.)

Configuring a Component Manager

The DtSimComponentManager is owned by a DtVrfObject. The Component Manager is created as part of the DtVrfObject via the standard factory mechanism. (For details, please see The DtSimComponent Class.) If you want to simulate an entity using the component architecture, you must specify that a Component Manager be created as part of the entity.

To configure a DtVrfObject to be created with a Component Manager, specify a Component Manager in the object’s entry in the object parameter database, for example:

(ground-vehicle-parameters
   (parameter-type "ground-vehicle-param")
   ...
   (local-objects 
      (state-repository  "ground-entity-state-repository")
      (state-repository-min-tick-period  -1.000000)
      (state-repository-min-tick-period-variance  -1.000000)
      (net-interface  "individual-local-entity-net-interface")
      (net-interface-min-tick-period  -1.000000)
      (net-interface-min-tick-period-variance  -1.000000)
      (task-manager  "local-task-manager")
      (component-manager  "component-manager")
      (plan-manager  "vrfobject-plan-manager")
   )
   ...
)
Note:
Component Managers should only be created for locally simulated objects. Do not specify a component-manager in the remote-objects list.

Looking Up a Component

You can look up a component by name in the Component Manager. Since it returns a pointer to the base class DtSimComponent, the caller is responsible for knowing or determining the actual type of the component. Components have a type() member function that returns the type of a component (the same string used by the component factory to create it). For example, to look up an automotive actuator component in an M1A2 entity (named "powertrain" in the M1A2 object parameter database entry):

DtSimComponent* actuator = vrfObject->componentManager()->
lookupComponent("powertrain");

// Make sure the component that was found is of the type we expect 
if(actuator && actuator->type() == DtAutomotiveActuatorType)
{
   . . .
}

If the entity has been configured with systems, lookupComponent() will search recursively for the component. It searches first through the entity’s immediate components and then inside its systems. It returns the first component that matches the given name.

You can also search for a DtComponentSystem by name, by calling lookupComponentSystem() in the DtComponentManager. The ability to look up a component system by name can be useful when there are multiple DtSimComponents with the same name, but which are in different DtComponentSystems. For example, consider a situation in which an entity has multiple weapon systems. To find the particular component you want, look up the weapon system you want first; then look up the DtSimComponent in that DtComponentSystem directly, by calling its lookupComponent() member.

Creating Components

An entity’s DtComponentSystems and DtSimComponents are created in the DtSimComponentManager::init() function. The Component Manager creates the entity’s systems and components from the entity’s component descriptor lists. (For details, please see Component Descriptors.)

Sensor and actuator components for an entity are placed on DtSimComponentLists. Components are indexed on the lists by component name.

Note:
If an entity is not configured with any systems, the name of the component must be unique within the entity. If the entity has been configured with one or more systems, then the name of the component must be unique within its system. The name is normally specified as part of the component descriptor that defines the component. Component descriptors are described in "ComponentDescriptors.

Controller components are placed on a DtControllerComponentList (ctlrCompList.h), which is derived from DtSimComponentList. The DtControllerComponent list adds member functions that call a corresponding member function for each controller component on the list. These include taskNotify() and skipTask(). These member functions are described in "ControllerComponents.

They are typically invoked by the Task Manager, which manages the overall execution of tasks by an entity.

Note:
Components are created and added to the Component Manager in the order that they appear in the object parameter database. The order in which components are created and added to the lists is important, because it can affect the priority of one component over another when both provide inputs to the same target component. Please see Setting the Priority of Components for more details.

Connecting Components

After the system and components are created, they are connected in the Component Manager’s createConnectionsFromList() function. It takes the list of connections from the entity’s local parameter entry and walks through the list, looking up the ports and port groups to be connected to one another. Each item in the connection list contains one of the following:

The name of each component or system is the name in the descriptor. The names of the port and port groups are hard-coded in each component. (Please see the component’s header file to find out the names of the port and port groups.)

Note:
For each output port and input port that it connects, the Component Manager sets the priority of the connection to be the priority of the output port’s component. Priority is represented as an integer value starting at 1. Increasing values represent decreasing priority. The priority of the connection affects how multiple inputs to the same port are arbitrated. For details, please see Setting the Priority of Components.

For example, in the following excerpt from the ground-tracked.sysdef system defintion (a component system used by tracked ground vehicles, such as the M1A2), the move-to controller’s automotive-control output port group connects to the powertrain’s automotive-control input port group.

(tracked-movement-system
   ...
   (controllers
      ...
      (move-to
         (component-descriptor-type "ground-move-to-descriptor")
         (component-type "ground-auto-move-to-controller")
      )
      ...
   )
   (actuators
      (powertrain
         (component-descriptor-type "automotive-component-descriptor")
         (component-type "automotive-actuator")
      )
      ...
   )
   (connections
      ...
      (connect move-to:automotive-control powertrain:automotive-control)
      ...
   ) );; end connections

You can connect systems to other components or other systems in a similar manner. Ideally, systems should be able to be treated as ‘black boxes’. Connections between components defined within a system can be thought of as ‘private’ connections, while connections between the system and external components or systems can be thought of as ‘public’ connections. You create a ‘public’ connection endpoint for a system by configuring a mapping between the system and a given component:port or component:port-group. This enables you to ignore the complexity of the components and connections contained within the system and work with a typically much smaller set of of public connections. The mapping between a system connection endpoint and an actual component connection endpoint are resolved at runtime, when an entity’s components have been instantiated and are being connected.

Ticking Components

By default, each component of every entity is ticked each simulation frame. VR-Forces allows you to specify a minimum tick period for a component, or all the components of a given entity type in the object parameter database. This minimum tick period can also be changed through the API. The minimum tick period is used to determine the next tick time that the component may be ticked. The time can be expressed as either real time (wall clock time) or simulation time, depending on the value of the tick-period-uses-real-time parameter.

The tick-period-uses-real-time parameter specifies whether or not the tick-period parameter should use wall-clock time or simulation time. If your simulation requires repeatability, set tick-period-uses-real-time to False for all components. For more information about repeatability, please see "Repeatability", in "VR-Forces Simulation Concepts," in VR-Forces Users Guide.

You can also specify a minimum tick period variance, which specifies the range that the next tick time may vary by (this helps to distribute the individual component’s ticks more evenly across different simulation frames).

Each simulation frame, the Component Manager is ticked. It in turn ticks the component systems list, the sensor list, the controller component list, and then the actuator component list. Each component list calls DtSimComponent::timedTick() for each component on that list, in the order that the components were specified in the object parameter database (or otherwise placed on the list). The timedTick() member function checks to see if the current time is greater than or equal to the next tick time for that component, which can be accessed via the nextTickTime() member function. If it is, then dT (delta time) is calculated for that component and the component’s tick() member function is called.

Following the call to tick(), a new next tick time is calculated. To calculate the new next tick time, VR-Forces determines a random value between +/- minTickPeriodVariance/2, then adds it to the current time + the minimum tick period. The next tick time is never less that the current time.

You can set the next tick time for a component by calling DtSimComponent::setNextTickTime(). Use a next tick time equal to the current time to guarantee that the component will be ticked on the next simulation frame. Setting the minimum tick period and minimum tick period variance to 0.0 causes the component to be ticked every simulation frame (the default, unless modified by the object parameter database).

Note:
Because components are not necessarily ticked every simulation frame, do not use the value returned by DtExerciseClock::dT() in components, because this is not necessarily the time that has passed since the last call to a particular component. Use the DtSimComponent::dT() member function instead.

Setting the Priority of Components

When multiple components can provide data to the same receiving component, they connect to the component based on their priority.

When a component that wants to provide data (by sending data through an output port owned by the component) to another component (receiving data through an input port owned by the component) is ticked, it calls its output port’s attemptToActivate() member function. The attempt to activate is made using the priority assigned to the component with the output port. The attempt to connect will succeed if one of the following conditions is true:

The connection’s priority was established when the components were connected. (For details, please see Connecting Components.) Each connection between an output port and an input port is assigned the same priority as the priority of the output port’s component. Component priority is set in the context of a given DtComponentSystem. For components that are not explicitly configured as part of a system, priority is set in the context of the entity’s implicit base DtComponentSystem.

If the call to the output port’s attemptToActivate() returns true, the component typically computes its new data values (if necessary) and puts the resulting values on the output port. When the rest of the components get ticked, because they are ticked in priority order, highest to lowest, no other component will be able to establish an active connection to the input port this tick.

If the call to the output port’s attemptToActivate() returns false, then there is not a valid connection to the input port (another component with a higher priority is probably already connected.) Most components do not bother to run their algorithms if they cannot establish an active connection between their output port and the input port they need to furnish the results to (although this is up to the implementer of the component in question).

The receiving component gets ticked. In the receiving component’s tick() member function, it checks for a valid connection to the relevant input port by calling the input port’s activeConnection() member. If that returns a valid pointer (indicating an output port is currently connected to the input port), it retrieves the value on the input port and uses the data in computations for this tick.

When a component providing data through an output port wants to release an active connection to another component’s input port, it calls the output port’s deactivate() member. This allows any other component to successfully connect to the input port. This call is often made by task controllers when they have completed their tasks. For example, once the move-to controller has reached its goal, it no longer needs to provide data to the automotive actuator input ports. At that point it deactivates its output ports.

A component providing data may also choose to remain connected, but temporarily reduce itself to the lowest priority (which allows any other interested component to connect). This is done by calling the output port’s allowDeactivation() member function. The connection to the input port remains in place, but the output port’s connection is assigned a special priority of -1 (lower than any component’s assigned priority). In this way a component can continue to provide data inputs to another component until some third party component determines it wants to take over the connection and start providing inputs.

[<< Component Systems] [Home] [Top of Page] [The Aggregate Multiresolution Model >>]


Document ID: Generated on Fri Jun 29 16:33:32 EDT 2012 from SVN revision 116588
Copyright © 2005-2012 VT MÄK Inc. All Rights Reserved (www.mak.com)