Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions fmu2aadl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build/
dist/
fmu2aadl.egg-info/
6 changes: 2 additions & 4 deletions fmu2aadl/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ Installation
The script is provided as a standard Python module.

The script can be installed, as user, using default Python install
procedure:
procedure::

```
python setup.py install --user
```
python setup.py install --user
10 changes: 7 additions & 3 deletions fmu2aadl/examples/moonlanding/Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
all: moonlanding_fmu.aadl check_aadl code_gen

moonlanding_fmu.aadl:
fmu2aadl ../../../models/MoonLanding/MoonLanding.fmu
moonlanding_fmu.aadl: MoonLanding.fmu
fmu2aadl MoonLanding.fmu

code_gen: moonlanding_fmu.aadl
ocarina -aadlv2 -y -g polyorb_hi_c moonlanding.aadl

build: moonlanding_fmu.aadl
ocarina -aadlv2 -y -b -g polyorb_hi_c moonlanding.aadl

check_aadl: moonlanding_fmu.aadl
ocarina -aadlv2 -y moonlanding.aadl

clean:
-rm -rf *~

distclean: clean
-rm -rf moonlanding_sys_impl
-rm -rf moonlanding_sys_impl fmu_wrapper.* userdefined.mk moonlanding_fmu.aadl \
moonlanding_fmu_wrapper.c
25 changes: 25 additions & 0 deletions fmu2aadl/examples/moonlanding/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Moonlanding AADL + FMI
======================

About
-----

This example is adapted from the Moonlanding example from Peter Fritzon, as detailed in the tutorial : https://openmodelica.org/images/docs/userdocs/modprod2012-tutorial1-Peter-Fritzson-ModelicaTutorial.pdf

We adapted this example so that:

* the environment is modeled as a `Modelica` model, and turned into a FMU using the OpenModelica toolset
* the controller is implemented as a `C` function,
* the controller is integrated to the environment in an `AADL` model

From an code generation perpective:

* The fmu2aadl script generates the corresponding AADL for the environment elements, and the C wrapper function.
* ocarina is used to assemble all elements together.



Note
----

The generated FMU targets GNU/Linux 64 bits
71 changes: 0 additions & 71 deletions fmu2aadl/examples/moonlanding/moonlanding_fmu_wrapper.c

This file was deleted.

28 changes: 0 additions & 28 deletions fmu2aadl/examples/moonlanding/userdefined.mk

This file was deleted.

125 changes: 123 additions & 2 deletions fmu2aadl/fmu2aadl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,121 @@ def FMU2AADL_Subprogram(root,tree,file):
file.write(3 * ' ' + 'end ' + root.get('modelName') + '_spg;\n')
file.write('\n')

################################################################################
def FMU2C_Wrapper(root,tree,file):

file.write ('#include <stdbool.h>\n')
file.write ('#include <stdio.h>\n')
file.write ('#include <stdlib.h>\n')
file.write ('#include "fmi2.h"\n')
file.write ('#include "sim_support.h"\n')
file.write ('#include "fmu_wrapper.h"\n')
file.write ('\n')

is_first_arg = True
file.write('void ' + root.get('modelName').lower() + '_fmu_entrypoint \n')

for svar in tree.xpath("/fmiModelDescription/ModelVariables/ScalarVariable"):
if svar.get('causality') == 'input':
if is_first_arg:
file.write(6 * ' ' + '(')
is_first_arg = False
else:
file.write (',\n')
file.write(7 * ' ')

file.write ('fmi2Real ' + svar.get('name') + '_in')

if svar.get('causality') == 'output':
if is_first_arg:
file.write(6 * ' ' + '(')
is_first_arg = False
else:
file.write (',\n')
file.write(7 * ' ')

file.write('fmi2Real *' + svar.get('name') + '_out')

file.write (') \n{\n');

file.write(2 * ' ' + 'const char *fmuFileName ="MoonLanding.fmu";\n')
file.write(2 * ' ' + 'double tEnd = 110.0;\n')
file.write(2 * ' ' + 'double h = 0.1;\n')
file.write(2 * ' ' + 'static bool initialized = false;\n')
file.write(2 * ' ' + 'static FMUContext ctx;\n')
file.write('\n');
file.write(2 * ' ' + '/* 1/ FMU activation */')
file.write('\n');

file.write(2 * ' ' + 'if (!initialized) {\n');
file.write(4 * ' ' + 'ctx.fmu = malloc (sizeof (FMU));\n');
file.write(4 * ' '
+ 'FMU_Activate_Entrypoint (fmuFileName, tEnd, h, &ctx);\n');
file.write(4 * ' ' + 'initialized = true;\n');
file.write(2 * ' ' + '}\n');
file.write('\n');

file.write(2 * ' ' + '/* 2/ Regular compute entrypoint */\n');
file.write('\n');
file.write(2 * ' ' + 'fmi2ValueReference vr;\n');
file.write(2 * ' ' + 'fmi2Real r;\n');
file.write(2 * ' ' + 'fmi2Status fmi2Flag;\n');
file.write('\n');

file.write(2 * ' ' + '/* Get the scalar variables */\n');
for svar in tree.xpath("/fmiModelDescription/ModelVariables/ScalarVariable"):
if svar.get('causality') == 'input' or svar.get('causality') == 'output':
file.write(2 * ' ' + 'ScalarVariable *' + svar.get('name') + '_sv'
+ ' = getVariable (ctx.fmu->modelDescription, "'
+ svar.get('name') + '");\n')
file.write('\n');

file.write (2 * ' ' + '/* Set the input */\n')
for svar in tree.xpath("/fmiModelDescription/ModelVariables/ScalarVariable"):
if svar.get('causality') == 'input':
file.write(2 * ' ' + 'vr = getValueReference (' + svar.get('name')
+ '_sv);\n')
file.write (2 * ' '
+ 'fmi2Flag = ctx.fmu->setReal (ctx.component, &vr, 1, &'
+ svar.get('name') + '_in);\n')
file.write('\n')

file.write (2 * ' ' + '/* Calculate the Step */\n')
file.write (2 * ' ' + 'doStep (ctx.fmu, ctx.component,\n')
file.write (10 * ' ' + 'ctx.currentCommunicationPoint,\n')
file.write (10 * ' ' + 'ctx.communicationStepSize,\n')
file.write (10 * ' ' + 'ctx.noSetFMUStatePriorToCurrentPoint);\n')
file.write('\n');

file.write (2 * ' ' + '/* Dump values */\n')
file.write (2 * ' ' + 'outputRow (ctx.fmu, ctx.component,\n')
file.write (13 * ' ' + 'ctx.currentCommunicationPoint,\n')
file.write (13 * ' ' + "ctx.resultFile, ',', fmi2False);\n")
file.write('\n');

file.write (2 * ' ' + '/* Get the outputs */\n')
for svar in tree.xpath("/fmiModelDescription/ModelVariables/ScalarVariable"):
if svar.get('causality') == 'output':
file.write(2 * ' ' + 'vr = getValueReference (' + svar.get('name')
+ '_sv);\n')
file.write(2 * ' '
+ 'fmi2Flag = ctx.fmu->getReal (ctx.component, &vr, 1, &r);\n')
file.write (2 * ' ' + '*' + svar.get('name') + '_out = r;\n')
file.write('\n');

file.write(2 * ' '
+ 'ctx.currentCommunicationPoint += ctx.communicationStepSize;\n');
file.write('\n');
file.write(2 * ' ' + '/* 3) terminate the simulation */\n');
file.write('\n');
file.write(2 * ' ' + 'if (ctx.currentCommunicationPoint > tEnd) {\n');
file.write(4 * ' ' + 'freeContext (ctx);\n');
file.write(4 * ' ' + 'exit (0);\n');
file.write(2 * ' ' + '}\n');
file.write('}\n');

file.close()

################################################################################
def fmu2aadl(fmu_file):
'''
Expand All @@ -155,8 +270,6 @@ def fmu2aadl(fmu_file):

'''

print os.path.dirname(__file__)

# Unzip FMU

_unzipModelDescriptionFile(fmu_file)
Expand All @@ -178,6 +291,14 @@ def fmu2aadl(fmu_file):
FMU2AADL_Thread_Impl(root,tree,file)
FMU2AADL_Epilogue(root, file)

# Build C wrapper file

cFile = root.get('modelName').lower() + '_fmu_wrapper.c'
file = open(cFile,'w')
print "Generating C file: " + cFile

FMU2C_Wrapper (root, tree, file)

# Copy required runtime files

shutil.copy(os.path.dirname(__file__) + "/fmu_wrapper.c", ".")
Expand Down
55 changes: 55 additions & 0 deletions models/CrazyFlie/AA_control.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
model AA_control
import Modelica.SIunits;
final constant Real g = Modelica.Constants.g_n; //Acceleration of the gravity
parameter SIunits.Mass m = 0.65;
parameter SIunits.Length l = 0.23; // Length
parameter SIunits.MomentOfInertia Ix = 7.5e-3; //Quadrotor moment of inertia around X axis
parameter SIunits.MomentOfInertia Iy = 7.5e-3; //Quadrotor moment of inertia around Y axis
parameter SIunits.MomentOfInertia Iz = 1.3e-2; //Quadrotor moment of inertia around Z axis
parameter SIunits.MomentOfInertia Jr = 6.5e-5; //Total rotational moment of inertia around the propeller axis
parameter Real d = 7.5e-7; // Drag factor
parameter Real Kpz=90, Kdz=13.795, Kpp=50, Kdp=8, Kpt=50, Kdt=8.09, Kpps=50, Kdps=8.3996;
Modelica.Blocks.Interfaces.RealInput Phi annotation(
Placement(visible = true, transformation(origin = {-120, 240}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 240}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Theta annotation(
Placement(visible = true, transformation(origin = {-120, 180}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 180}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Psi annotation(
Placement(visible = true, transformation(origin = {-120, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Phid annotation(
Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Thetad annotation(
Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Psid annotation(
Placement(visible = true, transformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Z annotation(
Placement(visible = true, transformation(origin = {-120, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Zd annotation(
Placement(visible = true, transformation(origin = {-120, -180}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -180}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealInput Omega annotation(
Placement(visible = true, transformation(origin = {-120, -240}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -240}, extent = {{-20, -20}, {20, 20}}, rotation = 0)));

Modelica.Blocks.Interfaces.RealOutput T annotation(
Placement(visible = true, transformation(origin = {110, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealOutput tau_phi annotation(
Placement(visible = true, transformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealOutput tau_theta annotation(
Placement(visible = true, transformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
Modelica.Blocks.Interfaces.RealOutput tau_psi annotation(
Placement(visible = true, transformation(origin = {110, -100}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -100}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
Real Z_dot, Phi_dot, Theta_dot, Psi_dot;

equation
Z_dot=der(Z);Phi_dot=der(Phi);Theta_dot=der(Theta);Psi_dot=der(Psi);
T=(Kpz*(Zd-Z)-Kdz*Z_dot+g)*m/(cos(Phi)*cos(Theta))+d*Z_dot;
tau_phi=Kpp*(Phid-Phi)-Kdp*Phi_dot-(Iy-Iz)/l*Theta_dot*Psi_dot-Jr/l*Theta_dot*Omega;
tau_theta=Kpt*(Thetad-Theta)-Kdt*Theta_dot-(Iz-Ix)/l*Phi_dot*Psi_dot+Jr/l*Phi_dot*Omega;
tau_psi=Kpps*(Psid-Psi)-Kdps*Psi_dot-(Ix-Iy)/l*Phi_dot*Theta_dot;

annotation(
uses(Modelica(version = "3.2.2")),
Icon(coordinateSystem(extent = {{-100, -280}, {100, 280}}),graphics = {Rectangle(extent = {{-100, 280}, {100, -280}})}),
Diagram(coordinateSystem(extent = {{-100, -280}, {100, 280}})),
version = "",
__OpenModelica_commandLineOptions = "");

end AA_control;
Loading