Developing with HLA
This article is a stub. You can help the wiki by expanding it. |
- Last updated: 06/2013
- Contributors: Callahanp, Hooray
Multicore |
---|
Configuration |
Ongoing Efforts |
Proposals & RFCs |
Background |
For developers |
Objective
The HLA article only really discusses the overall picture and lists some general tutorials - it doesn't go into FG specifics, which we however need to cover to get more people up to scratch with HLA, i.e. 1) building SG/FG with HLA and 2) actually developing with it to partition FG into separate processes. Like I mentioned previously, we do have a bunch of C++ code that can serve as an example, i.e. to reverse-engineer things a little and provide a more programmer-centric tutorial
Work through a simple use-case of using HLA to support a Nasal HLA standalone interpreter that provides "live" property tree access using setprop()/getprop() and then generalize the info and present it here .
Intro
OpenRTI
Operation
OpenRTI can operate in several ways:
The most important one is probably the client/server scenario: Have one server process and some federates in several processes on some machines in a network.
Often it would be also good to exploit some locality in an RTI. To get this, an OpenRTI server can operate as slave servers under a parent server. That means that every server in that tree seed all the federations in that server tree but messages are only routed to servers that need these messages. So having a sub server on a local subnet, traffict just interresting for federates connected to that slave server originating from federates connected to that slave server will never be sent to the parent server.
But OpenRTI also can work without any external server running. When all federates are living in one program - may be in different threads, messages are just exchanged in that program. While this is probably the fastest operation mode it is also the one that is the easiest to set up.
Protocols
To select between the different modes of operation above, OpenRTI knows some protocols. This is the basic way of the transport used to communicate.
- thread: Just use the in memory communication between threads. This is the default as it does not require much setup.
- rti: This is the preferred tcp/ip protocol variant for networked communication.
- pipe: Uses the rti binary protocol on a named pipe. Can be used for machine local communication in presence of tight packet filters.
The implementation is prepared to some degree to move protocols into a user provided shared library that could be loaded at runtime.
Connecting to an rti
For rti1516 we have that string vector that is given to the ambassador when it is created. This vector can be used to configure the protocol that is used to communicate. The strings might contain key value pairs like <key>=<value>. Supported keys are:
- protocol=
- 'thread' (default) use the smp, in memory connect.
- 'rti' use the tcp/ip binary protocol on some custom port
- 'pipe' use the binary protocol on a named pipe
- 'trace' chain the communication to an other protocol and dump messages
- address=<a> - The interpretation depends on the protocol:
- For 'thread' this is ignored.
- For 'rti' this contains the host:port pair.
- port can be omitted to use the apropriate default port.
- For 'pipe' this should contain the path to the named pipe.
- timeout=<t>
- Sets initial packet timeouts for messages that happen syncronous. That is mostly for create, destroy, join and resign.
Federation execution names and URLs
OpenRTI interprets federation execution names as urls:
<protocol>://<address>/<path>/<name>
Where the protocol overriedes the protocol field from the string list. The address is the network address of the server. The path contains the path to the named pipe if protocol is pipe and the name is just the plain name of the federation execution.
Learn more at: openrti/OpenRTI/master/README
SimGear
FlightGear
Base Package
- Federation Object Model (FOM) - An identification of the essential classes of objects, object attributes, and object interactions. The FOM does not contain information about the actual objects in the simulation (the federates), but only about the possible object classes in the simulation.
Examples
All examples will be made available through Gitorious, i.e. see: gitorious/fg/hoorays-simgear/topics/hla-tutorial.
To track the simgear branch:
git remote add hla-tut https://gitorious.org/fg/hoorays-simgear.git
git fetch hla-tut
git checkout --track -b hla-tut/topics/hla-tutorial
Adding a new HLA app to the build system
Add this to your toplevel CMakeLists.txt:
##
# use this function to build HLA federates
#
# add_federate(hla-demo hla-demo.cxx dep1.cxx dep2.cxx)
#
function( add_federate EXECUTABLE SOURCE_FILE)
if(RTI_FOUND)
set(HLALibs SimGearCore "${CMAKE_THREAD_LIBS_INIT}" ${RTI_LIBRARIES} ${ZLIB_LIBRARY} ${WINSOCK_LIBRARY} ${RT_LIBRARY} )
# add additional files
set(FILES ${FILES} ${SOURCE_FILE} ) # using set() here is slower than list(APPEND) but more portable
foreach(additional_file ${ARGN} )
set( FILES ${FILES} ${additional_file} )
endforeach()
add_executable( ${EXECUTABLE} ${FILES})
target_link_libraries( ${EXECUTABLE} ${HLALibs} )
else(RTI_FOUND)
message(STATUS "RTI not found, not building ${EXECUTABLE}")
endif(RTI_FOUND)
endfunction(add_federate)
option(ENABLE_RTI "Set to ON to build with RTI support" OFF)
if(ENABLE_RTI)
# See if we have any rti library variant installed
message(STATUS "RTI: ENABLED")
find_package(RTI)
if(RTI_FOUND)
set(SG_HAVE_HLA 1)
endif(RTI_FOUND)
else()
message(STATUS "RTI: DISABLED")
endif(ENABLE_RTI)
set(RT_LIBRARY "")
if(HAVE_CLOCK_GETTIME)
check_library_exists(rt clock_gettime "" HAVE_RT)
if(HAVE_RT)
set(RT_LIBRARY rt)
endif(HAVE_RT)
endif(HAVE_CLOCK_GETTIME)
And this to your CMakeLists.txt in the source folder:
add_federate(hla-demo hla-demo.cxx)
Creating a new Federate
Create a new class and implement the interface of simgear::HLAFederate
#ifndef __MY_FEDERATE_HXX_
#define __MY_FEDERATE_HXX_
#include <simgear/hla/HLAFederate.hxx>
class MyFederate : public simgear::HLAFederate {
public:
MyFederate();
virtual ~MyFederate();
virtual simgear::HLAObjectClass* createObjectClass(const std::string& name);
virtual bool init();
virtual bool update();
virtual bool shutdown();
private:
};
#endif
Creating a Federate instance
Use the SGSharedPtr<> template to create a shared pointer of your new federate:
#include "MyFederate.hxx"
int main() {
SGSharedPtr<MyFederate> manager = new MyFederate;
return 0;
}
Initializing a Federate
Call the following federate methods, to initialize your federate:
- setVersion( simgear::HLAFederate::RTI13 )
- setFederateType(type);
- setFederationExecutionName("rti:///FlightGear")
- setCreateFederationExecution(true)
- setFederationObjectModel(OMT)
- init() + explicit update() calls or exec()
#include <simgear/misc/sg_path.hxx>
#include "MyFederate.hxx"
int main() {
SGSharedPtr<MyFederate> manager = new MyFederate;
manager.setVersion( simgear::HLAFederate::RTI13 )
manager.setFederateType("MyFederate");
manager.setFederationExecutionName("rti:///FlightGear");
std::string fg_root;
// get FG_ROOT for FOM (in $FG_ROOT/HLA)
if (fg_root.empty()) {
if (const char *fg_root_env = std::getenv("FG_ROOT")) {
fg_root = fg_root_env;
} else {
std::cerr << "Error: path to FG_ROOT must be specified as env var" << std::endl;
exit(-1);
}
// set up the default fg-local-fom.xml
if (manager->getFederationObjectModel().empty()) {
SGPath path(fg_root);
path.append("HLA");
path.append("fg-local-fom.xml");
manager->setFederationObjectModel(path.str());
std::cout << "OMT is:" << path << std::endl;
}
return manager.exec(); //fires off init() and update()
}
Hello World - HLA
Here's a more contrived but self-contained example:
#include <simgear/misc/sg_path.hxx>
#include <simgear/hla/HLAFederate.hxx>
#include <cstdlib>
#include <iostream>
using namespace std;
static void hello_from(std::string source) {
std::cerr << "Hello from:" << source << std::endl;
}
static void cancel(std::string error) {
std::cerr << error << std::endl;
exit(-1);
}
class MyFederate : public simgear::HLAFederate {
public:
MyFederate() {}
virtual ~MyFederate() {}
virtual simgear::HLAObjectClass* createObjectClass(const std::string& name) {return NULL; }
virtual bool init() { hello_from("init"); return true;}
virtual bool update() { hello_from("update"); return true;}
virtual bool shutdown() {hello_from("shutdown"); return true;}
private:
};
SGSharedPtr<MyFederate> manager = new MyFederate; // our global federate instance
static
void setup_fom(const char* filename="fg-local-fom.xml") {
std::string fg_root;
// get FG_ROOT for FOM (in $FG_ROOT/HLA)
if (fg_root.empty()) {
if (const char *fg_root_env = std::getenv("FG_ROOT")) {
fg_root = fg_root_env;
} else {
cancel("Error: path to FG_ROOT must be specified as env var");
}
// set up the default fg-local-fom.xml
if (manager->getFederationObjectModel().empty()) {
SGPath path(fg_root);
path.append("HLA");
path.append( filename );
manager->setFederationObjectModel(path.str());
std::cout << "OMT is:" << path << std::endl;
}
}
if ( !manager.valid() )
cancel("manager not valid!");
}
// entry point
int main() {
manager->setVersion( simgear::HLAFederate::RTI13 );
manager->setFederateType("MyFederate");
manager->setFederationExecutionName("rti:///FlightGear");
setup_fom();
// federate is now valid
return manager->exec(); //fires off init() and update()
}
Resources
Introductions (Youtube)
Tutorials
- http://en.wikipedia.org/wiki/High-level_architecture_%28simulation%29
- http://www.mak.com/resources/industry-standards/377-hla-high-level-architecture.html
- http://www.ecst.csuchico.edu/~hla/LectureNotes/HLA_1516_M1_P1.pdf
- http://www.ecst.csuchico.edu/~hla/LectureNotes/HLA_1516_M1_P2.pdf
- http://www.ecst.csuchico.edu/~hla/LectureNotes/HLA_1516_M1_P3.pdf
- http://www.ecst.csuchico.edu/~hla/LectureNotes/HLA_1516_M1_P4.pdf
- http://www.ecst.csuchico.edu/~hla/LectureNotes/HLA_1516_M1_P5.pdf
- http://www.ecst.csuchico.edu/~hla/LectureNotes/HLA_1516_M1_P6.pdf
- http://www.cc.gatech.edu/computing/pads/PAPERS/High_Level_Architecture_For_Simulation.pdf
- http://www.cs.bilkent.edu.tr/~cagatay/cs503/_M&S_09_Distributed_Simulations.pdf
- HLA Tutorial
- The HLA Tutorial: Practical Guide For Developing Distributed Simulations by Björn Möller and Team