.. include:: definitions.rstinc ===================== FMI Export ===================== AGX Dynamics supports FMI export for co-simulation using the FMI-standard (see http://fmi-standard.org/). The standard (and its interface) is called Functional Mockup Interface (FMI), and one unit created or connected via this standard is called a Functional Mockup Unit (FMU). The following tutorial demonstrates how to build an AGX Dynamics FMI module compatible with the FMI 2.0 standard. The resulting FMI module can, according to the FMI standard, also be referred to as an FMU (see above). The FMI export interface is exposed in AGX using the *agxFMI2::Export* namespace. The interface bindings are defined using Python. AGX Dynamics only supports creating FMUs using the FMI 2.0 standard. The following diagram displays the structure of a Python based AGX FMI module: .. Raw image available at our lucidchart.com account .. image:: images/fmi_export_1.png Building an AGX FMU consists of the following steps: 1. Setting up a directory structure matching the structure described in the FMI standard. The FMI module structure is described in section 2.3 (FMU Distribution) in the FMI2 specification. #. Implementing the Python script, which is responsible for a. Defining the AGX scene to be simulated (in Python or C++) #. Registering the FMI variables to be exported 3. Running the AGX FmiExporter tool that will a. Automatically generate the FMI XML interface definition (:code:`modelDescription.xml`) #. Package the FMU as a zip file according to the standard --------------------------- AGX Python FMU generation --------------------------- The FMU root directory, from here on referred to as :code:`$FMU_ROOT`, must contain a Python file named :code:`main.agxPy`. This is the main entry point for building the scene and setting up the module parameters. The :code:`main.agxPy` file must contain a function called fmiInit, which takes no arguments. The module of type :code:`agxFMI2::Export::Module*` can be accessed through the global agxPython context: .. code-block:: python def fmiInit(): context = agxPython.getContext() export_module = context.environment.getFMI2Module() This module contains a simulation instance, to which the simulated scene is added, an OSG render node for debug rendering, and methods for registering FMI parameters. You can find an FMU example in the :code:`data/FmiModules/Tutorial/Python/SpinningBox` directory. The AGX-FMUs are exported using the FmiExporter tool, which has the following syntax :code:`FmiExporter --name --output ` Name and output have implicit values so you can simply run :code:`FmiExporter myFmu` where myFmu is the directory containing the FMU resources, including a mandantory :code:`main.agxPy` file. In this case the module name will be myFmu and output path will be myFmu.fmu. The FmiExporter will automatically generate a FMI modelDescription.xml and package the FMU zip file. In order to run the FMU, AGX has to be installed on the computer with a valid license and valid environment variables. You can test your generated FMU using the command: .. code-block:: console > fmucheck -n 10 myFmu.fmu .. _fmu_cpp_export: ------------------------ AGX C++ FMU generation ------------------------ The directory :code:`data/FmiModules/Tutorial/CppModule/ExternalBuild` contains an example of how to structure and setup an AGX C++ FMU. It assumes an installed AGX package, and use a cmake build file to locate AGX, compile source code, and run the :code:`FmiExporter` command line tool to produce an FMU zip package. To build the sample FMU:s as part of building the tutorials/examples, the CMake flag :code:`AGX_BUILD_FMI_TUTORIALS` must be set to ON. Also, if the CMake flag :code:`AGX_ENABLE_TESTS` is set to ON, it is possible to test the built C++ FMU by executing the command: .. code-block:: console > ctest -C Release .. note:: It is important to build and run the FMU with the correct configuration. Because the naming convention of FMU:s it is not easy to make a distinction between release or debug builds. In Mac and Linux releases, it is only possible to build and run the FMU:s in release mode. We recommend building FMU:s in Release mode when possible due to conflicts between different runtime libraries. The general structure for a C++ based FMU is similar to the python FMU:s. At least one source file named :cpp:`main.cpp` must be present in the resource directory and all files in the named directory will be part of the FMU, including the source files. The main.cpp source file must at least contain the following functions: .. code-block:: c++ #include #include #include #include using namespace agx; namespace { // Called when the fmi is shutdown fmi2Status fmiShutdown(agxFMI2::Export::Module *) { return fmi2OK; } // Called when the fmi is initialized fmi2Status fmiInit(agxFMI2::Export::Module *module) { agxSDK::Simulation *simulation = module->getSimulation(); // Here is where we build our model RigidBody *body = new RigidBody(new agxCollide::Geometry(new agxCollide::Box(1, 1, 1))); simulation->add(body); agx::Hinge *hinge = new agx::Hinge(body, new agx::Frame()); hinge->setName("TheHinge"); hinge->getMotor1D()->setSpeed( 1.456 ); hinge->getMotor1D()->setEnable( true ); simulation->add(hinge); // Create motor speed input parameter auto vSetSpeed = new agxFMI2::Export::InputVariable_Real("targetMotorSpeed"); // Callback when parameter is changed from FMI master vSetSpeed->setCallback([=](Real val) { hinge->getMotor1D()->setSpeed(val); }); vSetSpeed->setDescription("The motor speed controller"); vSetSpeed->setStartValue(hinge->getMotor1D()->getSpeed()); module->registerVariable(vSetSpeed); // Create box angular velocity output parameter auto vSpeedOutput = new agxFMI2::Export::OutputVariable_Real("boxAngularVelocity"); // Callback when parameter is read from FMI master vSpeedOutput->setCallback([=](Real& val) { val = body->getAngularVelocity().z(); }); vSpeedOutput->setDescription("The current angular velocity"); module->registerVariable(vSpeedOutput); return fmi2OK; } // Called when the application is initialized fmi2Status fmiInitApplication(agxFMI2::Export::Module *) { return fmi2OK; } }