Skip to content

Commit

Permalink
Readded fmu controller
Browse files Browse the repository at this point in the history
  • Loading branch information
luca7084 committed Aug 23, 2023
1 parent 46837ff commit 10eb163
Show file tree
Hide file tree
Showing 15 changed files with 256 additions and 154 deletions.
3 changes: 2 additions & 1 deletion rocket_twin/systems/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from rocket_twin.systems.control import ControllerCoSApp, RocketControllerCoSApp, ControllerFMU
from rocket_twin.systems.control import ControllerCoSApp, RocketControllerCoSApp, ControllerFMU, RocketControllerFMU
from rocket_twin.systems.engine import Engine, EngineGeom, EnginePerfo
from rocket_twin.systems.ground import Ground
from rocket_twin.systems.physics import Dynamics
Expand All @@ -24,6 +24,7 @@
"ControllerCoSApp",
"RocketControllerCoSApp",
"ControllerFMU",
"RocketControllerFMU",
"NoseGeom",
"TubeGeom",
"WingsGeom",
Expand Down
3 changes: 2 additions & 1 deletion rocket_twin/systems/control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
from rocket_twin.systems.control.rocket_controller_cosapp import RocketControllerCoSApp

from rocket_twin.systems.control.controller_fmu import ControllerFMU # isort: skip
from rocket_twin.systems.control.rocket_controller_fmu import RocketControllerFMU # isort: skip

__all__ = ["ControllerCoSApp", "ControllerFMU", "RocketControllerCoSApp"]
__all__ = ["ControllerCoSApp", "ControllerFMU", "RocketControllerCoSApp", "RocketControllerFMU"]
14 changes: 2 additions & 12 deletions rocket_twin/systems/control/controller.mo
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
model controller
input Real ti;
input Real weight;
parameter Real weight_max;
parameter Real tl;
input Real is_on;
output Real w;
output Boolean engine_on;
equation
if (ti < tl) then
engine_on = false;
else
engine_on = true;
end if;

if (weight < weight_max and engine_on == false) then
if (is_on > 0.5) then
w = 1.;
else
w = 0.;
Expand Down
2 changes: 1 addition & 1 deletion rocket_twin/systems/control/controller_cosapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ControllerCoSApp(System):

def setup(self):

self.add_inward_modevar("is_on", 0, desc="Whether the fuel flow is allowed or not")
self.add_inward("is_on", 0, desc="Whether the fuel flow is allowed or not")

self.add_outward("w", 1., desc="Ratio of command fuel flow to maximum flow", unit="")

Expand Down
27 changes: 1 addition & 26 deletions rocket_twin/systems/control/controller_fmu.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,12 @@ class ControllerFMU(System):

def setup(self, model_path, model_name):

self.add_inward("time_var", 0.0, desc="System time", unit="")
self.add_inward("time_int", 0.0, desc="Interval between fueling end and launch", unit="")
self.add_inward("time_lnc", 100000.0, desc="Launch time", unit="")
self.add_transient("x", der="1")

pulling = {
"w": "w",
"weight": "weight_prop",
"weight_max": "weight_max",
"tl": "time_lnc",
"ti": "time_var",
}

fmu_path = self.create_fmu(model_path, model_name)
self.add_child(
FMUSystem("fmu_controller", fmu_path=fmu_path),
pulling=pulling,
pulling=["w", "is_on"],
)

self.add_event("full_tank", trigger="weight_prop > 0.9999*weight_max")

def compute(self):

self.time_var = self.time

def transition(self):

if self.full_tank.present:

self.time_lnc = self.time_var + self.time_int

def create_fmu(self, model_path, model_name):
"""Create an fmu file in the control folder from an mo file.
Expand Down
49 changes: 40 additions & 9 deletions rocket_twin/systems/control/rocket_controller.mo
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
model rocket_controller
input Real ti;
input Real weight;
parameter Real weight_max;
input Real weight_1;
input Real weight_2;
input Real weight_3;
parameter Real tl;
output Real w;
output Boolean engine_on;
parameter Real weight_max_1;
parameter Real weight_max_2;
parameter Real weight_max_3;
output Real is_on_1;
output Real is_on_2;
output Real is_on_3;
output Real fueling;
output Real flying;
equation
if (flying < 0.5 and weight_3 < weight_max_3) then
fueling = 1.;
else
fueling = 0.;
end if;

if (ti < tl) then
engine_on = false;
flying = 0.;
else
engine_on = true;
flying = 1.;
end if;

if (weight > 0. and engine_on == true) then
w = 1.;
if (flying < 0.5) then
is_on_1 = 0.;
is_on_2 = 0.;
is_on_3 = 0.;
else
w = 0.;
if (weight_1 >= 0.1) then
is_on_1 = 1.;
is_on_2 = 0.;
is_on_3 = 0.;
elseif (weight_2 >= 0.1) then
is_on_1 = 0.;
is_on_2 = 1.;
is_on_3 = 0.;
elseif (weight_3 >= 0.1) then
is_on_1 = 0.;
is_on_2 = 0.;
is_on_3 = 1.;
else
is_on_1 = 0.;
is_on_2 = 0.;
is_on_3 = 0.;
end if;
end if;

end rocket_controller;
9 changes: 4 additions & 5 deletions rocket_twin/systems/control/rocket_controller_cosapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ def setup(self, n_stages):
for i in range(1, n_stages + 1):
self.add_inward(f"weight_prop_{i}", 0., desc=f"Stage {i} propellant weight", unit='kg')
self.add_inward(f"weight_max_{i}", 1., desc=f"Stage {i} maximum propellant weight", unit='kg')
self.add_outward_modevar(f"is_on_{i}", 0, desc=f"Whether the stage {i} is on or not")
self.add_outward(f"is_on_{i}", 0, desc=f"Whether the stage {i} is on or not")

self.add_inward("time_int", 0., desc="Interval between fueling end and launch", unit='s')
self.add_inward("time_int", 5., desc="Interval between fueling end and launch", unit='s')
self.add_inward("time_lnc", 100000., desc="Launch time", unit='s')

self.add_outward_modevar("fueling", 1, desc="Whether the rocket is fueling or not")
self.add_outward_modevar("flying", 0, desc="Whether the rocket is flying or not")
self.add_outward("fueling", 1, desc="Whether the rocket is fueling or not")
self.add_outward("flying", 0, desc="Whether the rocket is flying or not")

self.add_event("full", trigger = "weight_prop_1 == weight_max_1")
self.add_event("fuel_end", trigger=f"weight_prop_{n_stages} == weight_max_{n_stages}")
self.add_event("launch", trigger="t == time_lnc")
self.add_event("drop", trigger="weight_prop_1 == 0.")

Expand Down
90 changes: 90 additions & 0 deletions rocket_twin/systems/control/rocket_controller_fmu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import os

from cosapp.base import System
from cosapp_fmu.FMUsystem import FMUSystem
from OMPython import ModelicaSystem

import rocket_twin.systems.control

class RocketControllerFMU(System):

def setup(self, n_stages, model_path, model_name):

self.add_inward("n_stages", n_stages, desc="number of stages")
self.add_inward("stage", 1, desc="Current active stage")

self.add_inward("time_var", 0.0, desc="System time", unit="")
self.add_inward("time_int", 0.0, desc="Interval between fueling end and launch", unit="")
self.add_inward("time_lnc", 100000.0, desc="Launch time", unit="")
self.add_transient("x", der="1")

pulling = {"flying" : "flying", "fueling" : "fueling", "tl" : "time_lnc", "ti" : "time_var"}

for i in range(1, n_stages + 1):
self.add_outward(f"is_on_{i}", 0, desc=f"Whether the stage {i} is on or not")
pulling[f"weight_{i}"] = f"weight_prop_{i}"
pulling[f"weight_max_{i}"] = f"weight_max_{i}"
pulling[f"is_on_{i}"] = f"is_on_{i}"

fmu_path = self.create_fmu(model_path, model_name)
self.add_child(
FMUSystem("fmu_controller", fmu_path=fmu_path),
pulling=pulling,
)

self.add_event("full", trigger = "weight_prop_1 > 0.9999*weight_max_1")
self.add_event("drop", trigger="weight_prop_1 < 0.1")

def compute(self):

self.time_var = self.time

def transition(self):

if self.full.present:
if self.stage < self.n_stages:
self.stage += 1
self.full.trigger = f"weight_prop_{self.stage} > 0.9999 * weight_max_{self.stage}"
else:
self.time_lnc = self.time + self.time_int
self.stage = 1

if self.drop.present:
if self.stage < self.n_stages:
self.stage += 1
self.drop.trigger = f"weight_prop_{self.stage} < 0.1"

def create_fmu(self, model_path, model_name):
"""Create an fmu file in the control folder from an mo file.
Inputs
------
model_path: string
the path of the .mo file
model_name: string
the name of the .fmu file to be created
Outputs
------
fmu: string
the path to the .fmu file
"""

fmu_path = os.path.join(rocket_twin.systems.control.__path__[0], model_name)
model_path = os.path.join(rocket_twin.__path__[0], model_path)
model_path = model_path.replace("\\", "/")
try:
os.mkdir(fmu_path)
except OSError:
pass
os.chdir(fmu_path)
mod = ModelicaSystem(model_path, model_name)
fmu = mod.convertMo2Fmu()
for filename in os.listdir(fmu_path):
if filename != (model_name + ".fmu"):
os.remove(filename)

return fmu


2 changes: 1 addition & 1 deletion rocket_twin/systems/rocket/rocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def setup(self, n_stages=1):
self.add_child(Dynamics("dyn", forces=forces, weights=["weight_rocket"]), pulling=["a"])

for i in range(1, n_stages + 1):
self.connect(self.controller.modevars_out, self[f"stage_{i}"].modevars_in, {f"is_on_{i}" : "is_on"})
self.connect(self.controller.outwards, self[f"stage_{i}"].inwards, {f"is_on_{i}" : "is_on"})
self.connect(self[f"stage_{i}"].outwards, self.controller.inwards, {"weight_prop" : f"weight_prop_{i}", "weight_max" : f"weight_max_{i}"})
self.connect(self[f"stage_{i}"].outwards, self.geom.inwards, {"props": f"stage_{i}"})
self.connect(self[f"stage_{i}"].outwards, self.dyn.inwards, {"thrust": f"thrust_{i}"})
Expand Down
2 changes: 1 addition & 1 deletion rocket_twin/systems/station/station.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def setup(self, n_stages=1):
self.connect(self.g_tank.outwards, self.pipe.inwards, {"w_out": "w_in"})
self.connect(self.pipe.outwards, self.rocket.inwards, {"w_out": "w_in_1"})

self.connect(self.rocket.modevars_out, self.controller.modevars_in, {'fueling' : 'is_on'})
self.connect(self.rocket.outwards, self.controller.inwards, {'fueling' : 'is_on'})
self.connect(self.controller.outwards, self.g_tank.inwards, {"w": "w_command"})

self.g_tank.geom.height = 2.0
Expand Down
6 changes: 4 additions & 2 deletions rocket_twin/tests/test_controller_cosapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ def test_control(self):
"rocket.stage_1.tank.fuel.w_out_max": 1.0,
"rocket.stage_2.tank.fuel.w_out_max": 1.0,
"rocket.stage_3.tank.fuel.w_out_max": 1.0,
"rocket.controller.fueling" : 1,
"rocket.controller.time_int" : 5.
}

Expand All @@ -30,6 +29,7 @@ def test_control(self):
"rocket.weight_prop_1",
"rocket.weight_prop_2",
"rocket.weight_prop_3",
"rocket.a"
]

driver = sys.add_driver(RungeKutta("rk", order=4, dt=1))
Expand All @@ -43,8 +43,10 @@ def test_control(self):
data = driver.recorder.export_data()
data1 = data.drop(["Section", "Status", "Error code", "rocket.weight_prop_2", "rocket.weight_prop_3"], axis=1)
data2 = data.drop(["Section", "Status", "Error code", "rocket.dyn.weight", "rocket.weight_prop_1"], axis=1)
acel = np.asarray(data["rocket.a"])

print(data1)
print(data2)

np.testing.assert_allclose(1,2, atol=0.1)
np.testing.assert_allclose(sys.rocket.geom.weight, 4., atol=10 ** (0))
np.testing.assert_allclose(acel[-3], 40., atol=0.1)
56 changes: 0 additions & 56 deletions rocket_twin/tests/test_controller_fmu.py

This file was deleted.

Loading

0 comments on commit 10eb163

Please sign in to comment.