Vortex Studio SDK: Creating an Application

Topics

 

The ApplicationConfig

An ApplicationConfig is a document (VXC extension) which allows you to set up or configure a Vortex® application without doing it all manually in code.

It can be passed to an application which will parse it (like the SimApp) and automatically configure itself based on the file's content. Through it, you can set some global parameters for the application (such as the default log level, the simulation frame rate, the starting application mode) but most importantly you can specify which modules and extensions will need to be created along with the application and on which node.

Note
In the Vortex Studio Editor, what the SDK calls an "ApplicationConfig" is referred to as an "Application Setup". Both terms represent the same concept but to avoid any confusion this guide will use the SDK terminology.

Content of the ApplicationConfig

An ApplicationConfig can contain the following elements:

Nodes

A node in a simulator represents, at the OS level, a process which will perform some tasks as part of your simulation.

A simulator can be composed of a single node (what we call standalone or desktop) or multiple nodes. In the case of multiple nodes, they may or may not even be on the same physical machine. Whether they are or not, all nodes will use the Vortex network layer to communicate and exchange data between them.

From the perspective of the ApplicationConfig, a node is simply an ApplicationConfig inside another one. It inherits the elements of the parent ApplicationConfig while also defining new or overriding elements of its own. A node in an ApplicationConfig can thus add modules and extensions only to itself and redefine some of the parameters (such as Profiler settings or whether the node is free running or not).

Every Vortex simulator needs a master process. In standalone mode, since there is only one non-networked process, it is fairly straightforward. In a network setup, it is a bit more complicated since it is the master node that coordinates the exchange of data with the other nodes, called slaves, and instructs them on what to do. In most cases the master will contain the dynamics module, while a slave node never will. If one of your nodes contains the dynamics module, it will be designated as the master by the application.

A node can also be explicitly set as a master or a slave by settings its parameter "CommunicationModel" to master or slave.

Note
The master node's configuration (or the configuration of the application in standalone mode) almost always contains the DynamicsEngine module. In a multi-node simulator you must add the NetworkOpenDDS extension to your ApplicationConfig to allow nodes to communicate between each other.
Users of past versions of the SDK might remember having to add the VxSim::VxSlaveModule to their slave nodes' configuration. As of Vortex Studio 2017, this is no longer necessary as all that functionality has been integrated directly into the VxApplication.

Modules

As explained in Integrating the Application, modules are a core part of a Vortex application. Modules are not part of the content like the other extensions and objects are. Modules are directly added to the application, either manually through VxSim::VxApplication::insertModule() or by adding them to an ApplicationConfig, which is then applied to the VxApplication.

Extensions

A common workflow is to add extensions to an application by embedding them in a content object and loading the object in the application. Though useful in many cases, if you find yourself re-adding extensions to your content that are not directly related to it (for example, an extension handling a user interface or network communication), it is a clear sign that the extension probably belongs inside an ApplicationConfig instead. Extensions that are fundamental to your simulator application regardless of loaded content are good candidates for this.

Warning
The ApplicationConfig of a distributed simulator must contain a network configuration extension at the root level.

Parameters

A Vortex application exposes some high level parameters that can be customized from the ApplicationConfig (e.g., frame rate, default log level). Some of these parameters are global while others can be overridden by each node.

Please refer to the Vortex Studio Technical Documentation for more details on all the parameters exposed through the ApplicationConfig class.

Seats

The closest analogy to represent a seat is the one you are sitting on in the simulator. The operator's seat on the motion platform and the instructor's chair in another room are examples of seats that differ from one another mainly through the hardware that is attached to the seat (screens, motion platform, controllers, etc.). When a role is applied to a seat, only the modules of the seat will manage the extensions of the role, otherwise the extensions will be ignored by the application.

A role is the counterpart to the seat. It represents an actor in the simulation and contains extensions that are only added to the simulation when it is applied to a seat.

Take the development of a tank simulator, for example. The simulator includes room for one student in the operator seat and an instructor in the instructor seat. Inside the simulation, however, there are at least three different roles: one for the instructor (which may be physically inside the simulation as a Vortex Human), one for the tank driver, and another for the tank gunner. The instructor seat has a standard desktop with mouse and keyboard, perfect to navigate the scene and evaluate what the student does. The operator seat has a motion platform, a steering wheel, pedals and two joysticks. The driver and gunner roles can alternately be applied to the operator seat which contains all the modules to handle the hardware. However, the gunner role does not contain the extension for the steering wheel and the pedals, and inversely the driver role does not contain the joystick extensions. Also both roles may not use the same displays to reflect a different field of view. On the other side, the instructor seat does not have all the hardware modules of the operator and the instructor extensions may include an extension for using a mouse.

To summarize, roles are added to your content directly but seats are part of your ApplicationConfig since they go with the simulator regardless of the content loaded on top of it.

Creating an ApplicationConfig

The easiest way to create an ApplicationConfig document is through the Vortex Studio Editor. In the Editor, you can easily use presets to quickly develop your ApplicationConfig with all the needed components.

The SDK also provides the VxSim::ApplicationConfig class to access those functionalities in code.

The main ApplicationConfig object of an application can contain sub-configurations for each node of the application.

VxSim::VxSmartInterface<VxSim::ApplicationConfig> config = VxSim::VxExtensionFactory::create(VxSim::ApplicationConfigICD::kFactoryKey);
VxSim::VxSmartInterface<VxSim::ApplicationConfig> configNodeA = VxSim::VxExtensionFactory::create(VxSim::ApplicationConfigICD::kFactoryKey);
VxSim::VxSmartInterface<VxSim::ApplicationConfig> configNodeB = VxSim::VxExtensionFactory::create(VxSim::ApplicationConfigICD::kFactoryKey);

// Add the nodes to the main config.
config->addNode(configNodeA);
config->addNode(configNodeB);

Presets

The class VxSim::ApplicationConfigPreset holds a global list of common ApplicationConfig objects that you can use as a base for your own custom list. A preset adds or modifies elements of an existing VxSim::ApplicationConfig object.

VxSim::VxSmartInterface<VxSim::ApplicationConfig> config = VxSim::VxExtensionFactory::create(VxSim::ApplicationConfigICD::kFactoryKey);
std::vector<std::string> availablePresets = VxSim::ApplicationConfigPreset::getAvailablePresets();

...

// Applying a preset to our config object.
VxSim::ApplicationConfigPreset::applyPreset("Master with dynamics", config);

The following is a list of presets that comes with your Vortex Studio Installation:

  • ApplicationParameters
  • Master with dynamics
  • Slave with 1 window
  • Slave with 2 windows
  • Slave with no graphics
  • Standalone

Using an ApplicationConfig with Your Application

An ApplicationConfig's main use is to configure a generic application. The application could contain widely different modules and extensions based on the content of its ApplicationConfig.

One such example is the SimApp application that comes with Vortex Studio. If you launch it with the --config <vxcFile> command line option, it will load and parse the ApplicationConfig given as an argument, modifying the application with the information of the setup document.

Only one ApplicationConfig can be applied on a VxApplication; when it is applied to a VxApplication, the application is wiped of its modules and extensions before applying a new one.

When developing your own application you can use the class VxSim::ApplicationConfigSerializer to load an ApplicationConfig saved to a file and configure your VxApplication with it.

VxSim::VxApplication* application = new VxSim::VxApplication;
VxSim::ApplicationConfigSerializer serializer;
if (serializer.load("c:\MyVortexApplication\config\standalone.vxc"))
{
	// Get and the main config.
	VxSim::VxSmartInterface<VxSim::ApplicationConfig> config = serializer.getApplicationConfig();

	// Get and apply the "slave" sub-config.
	auto slaveConfig = config->getNode("slave");
	slaveConfig->apply(application);
}

Deploying Your Application

A simple desktop application may be trivial to deploy: create a shortcut that launches the SimApp with the right setup document and parameters (or your own application). For something more complex, possibly including multiple nodes across the network, deployment is more complex.

Deploying Using the Vortex Studio Director

Vortex Studio comes with the Vortex Studio Director, an application that simplifies simulator design.

  1. Starting the Vortex Service
    Make sure the VortexService.exe application is running on each computer that will be involved in the distributed simulator. The Director uses the service to communicate.
  2. Creating a setup
    Use the Vortex Studio Editor to create your setup file. The file must contain a network configuration extension at the root level. The extension is only available in the Vortex Studio Editor. Its default values will work with the Director.
    • Setup deployment
      You must deploy the setup on each node of your simulator. If more than one node are on the same system, you need only one copy of the configuration for that system. They need to have the same file path.
  3. Creating a simulator
    Use the Vortex Studio Director to create simulator topology, associating hardware-based nodes (a process on a networked computer) with your setup's node.
  4. Launching a simulator
    The Vortex Studio Director is also a simulator launcher; it will manage the network configuration of a simulator and will run a network broker to ensure nodes' communication. See Director User Guide for details.

Deploying Manually

If you are developing your own application (not using simapp.exe) for a simulator node, or need to use your own custom deployment, there are some guidelines that must be followed.

OpenDDS and the DCPSInfoRepo

To transfer data and events across a networked simulator, Vortex uses the OpenDDS library. OpenDDS is an open-source implementation of Data Distribution Service for real-time distributed systems.

OpenDDS uses a centralized method of discovering peers. If you are not using Vortex Studio Director to launch your distributed simulator, it is necessary to run an instance of OpenDDS DCPSInfoRepo server on the network, so that nodes in the distributed simulator can locate each other. Launch the executable located in your Vortex Studio installation folder (e.g., C:\CM Labs\Vortex Studio 2019a\bin\DCPSInfoRepo.exe) before launching your application.

Creating a Setup

Use the Vortex Studio Editor to create your setup file. The file must contain a network configuration extension at the root level. The extension is only available in the Vortex Studio Editor. Its default values will work with the Director.

Network Configuration Extension

In your application, OpenDDS is represented by the NetworkConfiguration extension that is added at the root of the ApplicationConfig.

The Vortex Studio Director will override some of the parameters of this extension so that you do not need to manage it manually. If you are deploying without the Director, you will need to properly set up the network communication.

SDK Network configuration

The extension exposes several configurable parameters as described in Network Configuration ICD.

Warning
Multicast Addresses
All nodes of a given distributed simulator must have the same multicast address and SimulationID. Only the ports should differ for the different channels. Different distributed simulators must have different multicast addresses and SimulationID. If different distributed simulators share multicast addresses, your simulators may talk with each other, leading to undefined result.
In order to avoid this issue, there are several options:
  • Using the Vortex Studio Director (recommanded)
  • Make sure that each ApplicationConfig of a given simulator has different multicast addresses and simulationID
  • Use the command line option --simulationID of simapp.exe

Consult these following tips when using this extension.

  • Simulation ID: unique ID that enables multiple simulator applications to share the same network. Must be between 1 and 65535. All nodes of the same simulator should share the same simulation ID and each simulator should have a different simulation ID.
    • This parameter can be overridden using command line option --simulationID of simapp.exe. Doing so also overrides the last two numbers of the multicast addresses of the channels and time synchronization.
  • OpenDDS Info Repository Address And Port : IPv4 address and port (format address:port) of the system hosting the DCPSInfoRepo program.
    • This parameter can be overridden using command line option --networkbroker of simapp.exe.
  • Event Channel: leave checked, ensure event communication between the nodes.
    • Use multicast: Only multicast can be used, leave checked. This option is deprecated and will be removed in a future version.
    • Multicast Address and port: Should be in the form of 239.192.x.x:2. Typically, event channel uses port 2. The last two numbers and port will be overidden when simapp.exe --simulationID command line option is used. The address must match the Kinematic Channel Multicast Address and Time Synchronisation Address.
  • Kinematic Channel: leave unchecked.
    • Use multicast: Only multicast can be used, leave checked. This option is deprecated and will be removed in a future version.
    • Multicast Address and port: Should be in the form of 239.192.x.x:1. Typically kinematic (or data) channel uses port 1. The last two numbers and port will be overidden when simapp.exe --simulationID command line option is used. The address must match the Event Channel Multicast Address and Time Synchronisation address.
  • Time synchonization
    • Mode: Default is Network Time Sync.
      • Network Time Sync: Synchronization is managed by Vortex.
      • No Time Sync: There is no synchronization, The slaves will be updated with the latest data package received.
      • External Time Sync: Time is managed by an External Source. In this case, the integrator must manage time and ensure VxApplication::setSimulationTime() is called at every step.
    • Address and port: Should be in the form of 239.192.x.x:3. Typically time synchronization uses port 3. The last two numbers and port will be overidden when simapp.exe --simulationID command line option is used. The address must match the Event Channel Multicast Address and the Kinematic Channel Multicast Address.
    • Period: Period (in seconds) at which the slaves are synchronized; the default value is 0.1 seconds.
    • Offset: Offset between time on master and time on slaves (in seconds); the default value is 0.05 seconds.
Setup Deployment

You must deploy the ApplicationConfig on each node of your simulator. If more than one node are on the same system, you need only one copy of the configuration for that system.

Launching Your Application and Applying the Correct Configuration

Start your master application and then start each of your slave nodes' applications. Once done, load and apply the configuration on each of them, and then apply the sub-configuration specific to each node separately.

If using the simapp.exe process as a simulator node, use the following command line options:

  • --config to specify the file path to the setup file
  • --confignode to specify the node name for that process

Loading Content on a Deployed Simulator

Content is created using the Vortex Studio Editor, but also in C++ or Python code (see Creating Content). It is possible to load multiples content files and move the object if needed.

Most Dynamics Objects can be moved using the IMobile interface. It is preferable to set the application mode to Editing while loading content and moving some part of it around.

The content you will load must be present on each node of the simulator at the same path. For example, if your application wants to load the scene C:\My Simulator\Assets\Scene\Excavator.vxscene, it needs to be present (and all of its sub-objects) with the exact same path on each node.

Before starting the application, content must be loaded into it so that the application will simulate something.

Loading and Unloading Using the Simulation File Manager

The most convenient way of loading content is to use the VxSimulationFileManager provided by the VxApplication.

Content should be loaded while the simulator is in Editing mode. Some features, such as configuration, cannot be modified while simulating.

The VxSimulationFileManager object will load the content into the application and ensure everything is properly dispatched to the simulator.

Function VxSimulationFileManager::loadObject() is your entry point and takes the following parameters:

  • fileName: The file name of the content file, usually a scene or a mechanism.
  • objectName (optional): The name of the object. If none or empty is given, the object will keep the name with which it was saved.
  • worldTransform (optional): The position of the object in the world, will be at (0,0,0) if not set. This parameter has no effect on non-IMobile objects.

The simulation file manager can also be used to remove content, using VxSimulationFileManager::unloadObject().

Example: Loading a scene
...
Vx::VxSmartPtr<VxApplication> application = new VxApplication;
...
// Set up the application
...
// Get the file manager to load content
Vx::VxSmartPtr<VxSim::VxSimulationFileManager> fileManager = application ->getSimulationFileManager();

// Load the file, the object returned is the root object, in this case, a scene. The reference should be kept to inspect the content during the simulation.
VxSim::VxSmartInterface<VxContent::Scene> scene = fileManager->loadObject("../Resources/assets/ExVHLIntegration/Design/ExVHLIntegration.vxscene");
if (!scene.valid())
{
	Vx::LogError("Couldn't load the scene in ../Resources/assets/ExVHLIntegration/Design/ExVHLIntegration.vxscene.\n");
}
...
run the simulator
...
// Cleanup
fileManager->unloadObject(scene.getObject());

Getting the Global Loading Status

When running on a multi-node simulator, file management should be handled from a single node. The simulation file manager will distribute commands to load content on all nodes. The content is not actually distributed across the network; each node will load the files from their own disk, thus the content files' path must be the same on every computer.

While content is being loaded, the node performing file management should monitor the loading status and ensure it is consistent across all nodes before performing anything else, such as setting the application mode.

Function VxSimulationFileManager::loadObject() is blocking, meaning the function will not return until the object is loaded. When you get the object back, the object is loaded locally, but not necessarily on the whole simulator. In order to know when objects are loaded, there are two ways to proceed.

  1. Periodically call VxSimulationFileManager::getLoadingStatus() between VxApplication::update().
  2. Register a VxSimulationFileManager::Listener with function VxSimulationFileManager::registerListener(). This interface will call the listener functions when the loading status of a file changes. When you are done, unregister the listener.

While waiting, it is important to continue running the application as the simulator communication relies on VxApplication::update() to update its status. Once the status is kLoaded for all content files, the simulator is ready to proceed.

See VxSimulationFileManager::eLoadingStatus for status detail.

 

Next topic: Creating Content