VR-Link is an object-oriented C++ toolkit that developers use to quickly and easily build interoperable HLA, and DIS compliant simulation applications.
Learn all about VR-Link by clicking through the tabs below or download the VR-Link Capabilities document.
VR-Link is an object-oriented C++ toolkit that simulation developers use to quickly and easily build HLA, and DIS compliant applications. It provides a set of libraries that implement a stable, consistent, and documented API (Application Programmer's Interface) above the various protocols - an SDK (Software Developer's Kit) for interoperability. When you link your application you simply pick a protocol-specific library to use. To use a different protocol, just relink your application. When you use VR-Link, your developers are free to concentrate on the specific goals of your project, rather than spending their time worrying about the details of networking protocols. A few calls to VR-Link's functions replace thousands of lines of code that you would otherwise need to write yourself, saving time and money on development and maintenance.
VR-Link's top-level API abstracts away from the networking protocols. For example, application code sets the current state of locally simulated entities and objects, and any needed information is automatically sent to other applications either through the HLA's RTI or DIS network. On the incoming side, VR-Link processes information from other applications, and provides access to the current state of remote objects, without the application even having to know when individual updates arrive. If you are using either HLA, or DIS, there is great benefit in using VR-Link, since it saves you the time it would take to write all of the code that is necessary to interoperate using your protocol of choice. But if you need to be able to speak more than one protocol, (e.g. HLA and DIS or more than one version of HLA), or might have to in the future, then VR-Link is doubly valuable. That is because VR-Link implements all of these protocols largely through the same API. This means that you can write code once, and switch between DIS, HLA 1.3, IEEE 1516-2000, and IEEE 1516-2010 just by recompiling and linking with the appropriate versions of the VR-Link libraries.
The first example is a listen-only application that observes an exercise without simulating any entities on the network. The second is a send-only program that does not process information about remote entities. The source for both examples is included with VR-Link.
The Listen Example
This example illustrates a simple, listen-only VR-Link application. This application can be compiled for DIS or HLA, and contains no protocol-specific code.
With each iteration of the loop, the program prints an entity's updated, dead-reckoned position in topographic coordinates. In addition, if a fire PDU or interaction is detected on the network, the program prints a message showing the entity ID of the attacker.
1 // Define a callback to process fire interactions
2 void fireCb(DtFireInteraction* fire, void* usr)
4 std::cout << "Fire Interaction from " << fire->attackerId().string() << std::endl;
7 int main(int argc, char** argv)
9 // Create a connection to the exercise or federation execution
10 // based on initialization arguments passed as command-line arguments
11 // This causes the application to connect to the DIS network,
12 // HLA execution.
14 DtVrlApplicationInitializer appInit(argc, argv, "VR-Link Listen");
16 DtExerciseConn exConn(appInit);
18 // Register a callback to handle fire interactions
19 DtFireInteraction::addCallback(&exConn, fireCb, NULL);
21 // Create an object to manage remote entities.
22 DtReflectedEntityList rel(&exConn);
24 while (1)
26 // Tell VR-Link the current value of simulation time
28 // Process any incoming messages
31 // Find the first entity in the reflected entity list
32 DtReflectedEntity *first = rel.first();
34 if (first)
36 // Grab its state repository, where we can inspect its data
37 DtEntityStateRepository *esr = first->entityStateRep();
39 // Print the position
40 std::cout << "Position: " << esr->location().string() << std::endl;
43 // Sleep till next iteration
Connecting to an Exercise
In lines 14-16, the program creates a DtExerciseConnection. This connection serves as the program's interface to an exercise. Depending on whether the application is compiled for DIS, HLA 1.3, HLA 1516-2000, or IEEE 1516-2010, the DtExerciseConn constructor will ask the DtVrlApplicationInitializer for the appropriate initialization parameters, such as DIS port number or the HLA federation execution name. If you do not want to use VR-Link's command-line and configuration file-based initializer class, you can call alternate, protocol-specific constructors to create a DtExerciseConn.
Managing State and Interaction Information
Applications based on VR-Link typically use callbacks to handle incoming interactions such as fire, detonations, and collisions. For example, a callback named fireCb is registered with the DtFireInteraction class at line 19. This callback (defined at line 2) prints a message containing the attacker ID. It executes whenever the exercise connection receives a Fire interaction or PDU during a call to drain- Input().
We create a reflected entity list in line 22 to keep track of entities found on the network. The entity list tracks the arrival and departure of entities, performs dead reckoning, manages timeouts, and performs other entity-tracking tasks.
Listening to the Network
At the start of each iteration, the program sets VR-Link simulation time (line 27) to provide a common time value for use by time-related operations that occur within an iteration of the loop (such as the dead-reckoning of multiple entities). The drainInput() call (line 29) reads and processes any messages arriving through the exercise connection. This call triggers the execution, if needed, of any callbacks you have registered for that exercise connection. In HLA, this is where the RTI gets ticked. In line 32, the program finds the first entity in the entity list, then in line 37, retrieves the pointer to the entity's entity state repository, where VR-Link stores the values describing the remote entity's state. Line 40 obtains and prints the dead-reckoned entity location.
The Send Example
This example illustrates a simple send-only application that simulates the flight of an F18 aircraft. The program begins by sending an HLA fire interaction or a DIS fire PDU. Thereafter, the F18 flies north for 10 seconds, updating its position by sending HLA attribute updates or DIS entity state PDUs.
1 int main(int argc, char** argv)
3 // Create a connection to the exercise or federation execution
4 // based on initialization arguments passed as command-line arguments
5 // This causes the application to connect to the DIS network or
6 // HLA execution.
8 DtVrlApplicationInitializer appInit(argc, argv, "VR-Link Listen");
10 DtExerciseConn exConn(appInit);
12 DtEntityType f18Type(DtPlatform, DtPlatformDomainAir,
13 DtUnitedStates, DtFighter, DtF18, 0, 0);
15 // Create an entity publisher for the entity we are simulating
16 DtEntityPublisher f18EntityPub(f18Type, &exConn, DtDrDrmRvw, DtForceFriendly);
18 // Hold on to its state repository, where we can set data
19 DtEntityStateRepository *esr = f18EntityPub.entityStateRep();
21 // Create a topographic view on the state repository, so we
22 // can set position information in topographic coordinates
23 double refLatitude = DtDeg2Rad( 35.699760);
24 double refLongitude = DtDeg2Rad(-121.326577);
25 DtTopoView f18TopoView(esr, refLatitude, refLongitude);
27 // We can use the ESR to set state
30 DtVector position(0, 0, -100);
31 DtVector velocity(20, 0, 0);
33 // Send a Fire Interaction
34 DtFireInteraction fire;
38 // Main loop
39 DtTime timestep = 0.05;
40 DtTime simTime = 0;
41 while (simTime <= 10.0)
43 // Tell VR-Link the current value of simulation time
46 // Process any incoming messages
49 // Set the current position information
53 // Call tick, which insures that any data that needs to be
54 // updated is sent.
57 // Set up for next iteration
58 position += velocity * timestep;
59 simTime += timestep;
61 // Wait till real time equals simulation time of next step
62 DtSleep(simTime - exConn.clock()->elapsedRealTime());
Connecting to an Exercise
Like the listen-only example, this program creates a DtExerciseConnection to provide an interface to the RTI or DIS network (lines 8 through 10).
Line 12 defines the entity type the F18 will use. To be visible to other applications in the exercise, each locally-simulated entity requires a DtEntityPublisher, created in line 16. The entity publisher manages the generation of messages for this particular entity. It provides an entity state repository where you can set state values, and a tick() function, which causes state information to be sent to the network if necessary.
Line 19 sets up a pointer to the entity state repository, then line 25 creates a topographic view on that repository. This lets us set the entity's positional data using topographic coordinates, rather than the default geocentric coordinates. (Lines 23 and 24 hard code the coordinates for this example.) Line 28 shows an example of storing a non-positional state value in the repository.
An example of sending an interaction appears in lines 34-36. You can send the interaction using the exercise connection's sendStamped() function. You can use sendStamped() to send state updates as well, but it is preferable to let the entity publisher send state updates for you, using data in the entity state repository.
Sending State Messages
The main loop executes twenty times per second for ten seconds. As in the listen-only example, this program sets simulation time at the start of each iteration (line 44). While this program's main purpose is to demonstrate the sending of data to the network, it is not a true send-only application. Incoming data is also processed with the drainInput() call on line 47. This call is required for HLA because this is where we tick the RTI. The program updates the F18's positional data in its entity state repository in lines 50 and 51, and ticks the entity publisher in line 55 to send the updated data onto the network. Thereafter, the only remaining tasks are to increment the F18's position, increment the simulation time, and sleep until it's time to begin the next iteration.
Superior Technical Support
At MAK, technical support is not just an afterthought. Our reputation for supporting our customers is one of the key reasons that people choose our products. When you call or email us with questions, you speak directly to our product developers who know the software inside and out. When you buy MAK's products, you can be sure that MAK will be in your corner as you work towards successful completion of your HLA/DIS project. We've even been known to be on the phone with customers during their HLA certification process, or during key events.
When someone reports a bug, our engineers are quick to provide a patch or workaround, meaning you will not have to wait for the next release to have your problem addressed.
If you need assistance beyond the scope of technical support, our engineering services group is available to do VR-Link customization, extension, or integration on demand. We have had many customers not only buy VR-Link, but also buy our engineers' time to fully manage their transition to HLA or DIS compliance.
With maintenance, you are entitled to upgrades when they are released. Typically, new releases not only add support for the latest versions of RTIs, the RPR FOM, HLA Specifications, etc, but also try to maintain compatibility with older versions as well. For example, our current release supports many versions of the MAK RTI, includes FOM Mappers for RPR FOMs 0.5, 0.7, 0.8, 1.0, and 2.0, and continues to support DIS 2.0.4, IEEE 1278.1, and IEEE1278.1a.