fmi_adapter is a small ROS package for wrapping functional mockup units (FMUs) for co-simulation of physical models into ROS nodes. FMUs are defined in the FMI standard. Currently, this package supports co-simulation FMUs according to the FMI 2.0 standard only.
FMUs can be created with a variety of modeling and simulation tools. Examples are Dymola, MATLAB/Simulink, OpenModelica, SimulationX, and Wolfram System Modeler.
Technically, a co-simulation FMU is a zip file (with suffix .fmu) containing a physical model and the corresponding solver as a shared library together with an XML file describing the inputs, outputs and parameters of the model and details of the solver configuration. An addition, the zip file may contain the source code of the model and solver in the C programming language.
fmi_adapter provides a ROS node (fmi_adapter_node.cpp), which takes an set of FMUs (defined in the config.json) and creates subscribers and publishers for the input and output variables of the FMU, respectively. Then, it runs the FMU's solver with a user-definable update period according to the ROS clock. This approach is illustrated in the following diagram.
The fmi_adapter_node also searches for counterparts for each FMU parameter and variable in the ROS parameter server and initializes the FMUs correspondingly.
For this purpose, this package provide a launch file with argument json_config_path. Simply call
roslaunch fmi_adapter fmi_adapter_node.launch json_config_path:=[PathToTheConfigFile.json]
The config file and FMUs should be placed in a directory together. The structure of the config.json
is like the following
{
"fmus":
{
"Triangle": "Triangle.fmu",
"TriangleToSquare": "TriangleToSquare.fmu",
"TriangleToCosine": "TriangleToCosine.fmu"
},
"expose":
[
"Triangle.stop",
"Triangle.o_triangleSignal",
"TriangleToSquare.o_squareSignal",
"TriangleToCosine.o_cosineSignal"
],
"connections":
{
"Triangle.o_triangleSignal": [
"TriangleToSquare.i_triangleSignal",
"TriangleToCosine.Input"
]
}
}
Define the slaves here, the structure of each entry is "Name": "relative filename"
.
Define which signals should be published and subscribed to. The Structure of each entry is "Name.SignalName"
.
Define how slaves should get the results from other slaves from the last step. The structure is:
"SourceName.SourceSignalName": [
"Sink1Name.Sink1SignalName",
"Sink2Name.Sink2SignalName",
...
]